Browse Source

ruff as new formatter and linter

pull/12/head
crunk 6 months ago
parent
commit
23ac3e7699
  1. 68
      pyproject.toml
  2. 126
      verse/adminpage.py
  3. 54
      verse/admintool.py
  4. 72
      verse/app.py
  5. 30
      verse/deploydb.py
  6. 34
      verse/describer/describe_files.py
  7. 47
      verse/describer/forms/describe_file_form.py
  8. 18
      verse/distribusikan/distribusikan.py
  9. 244
      verse/distribusikan/distribusiselector.py
  10. 54
      verse/distribusikan/distribusisinfo.py
  11. 176
      verse/distribusikan/distribusiworkflow.py
  12. 284
      verse/distribusikan/editor.py
  13. 90
      verse/distribusikan/themeselector.py
  14. 136
      verse/distribusikan/upload.py
  15. 64
      verse/distribusikan/uploadpage.py
  16. 100
      verse/file_crawler.py
  17. 24
      verse/forms/admindistribusiform.py
  18. 24
      verse/forms/adminuserform.py
  19. 4
      verse/forms/distribusiform.py
  20. 46
      verse/forms/editorform.py
  21. 12
      verse/forms/forgotpasswordform.py
  22. 18
      verse/forms/loginform.py
  23. 10
      verse/forms/publicthemeform.py
  24. 52
      verse/forms/registerform.py
  25. 28
      verse/forms/resetpasswordform.py
  26. 10
      verse/forms/selectorform.py
  27. 20
      verse/forms/themeform.py
  28. 134
      verse/forms/uploadform.py
  29. 90
      verse/migrations/env.py
  30. 22
      verse/models/distribusi_file_model.py
  31. 24
      verse/models/distribusi_model.py
  32. 24
      verse/models/user_model.py
  33. 105
      verse/start.py
  34. 78
      verse/statuspengguna/forgotpassword.py
  35. 126
      verse/statuspengguna/helper.py
  36. 70
      verse/statuspengguna/loginuser.py
  37. 110
      verse/statuspengguna/registeruser.py
  38. 126
      verse/statuspengguna/resetpassword.py

68
pyproject.toml

@ -1,25 +1,49 @@
[tool.black] [tool.ruff]
line-length = 79 line-length = 79
target-version = ['py311'] target-version = "py311"
include = '\.pyi?$' #include = '\.pyi?$'
exclude = ''' exclude = [
/( ".bzr",
\.eggs ".direnv",
| \.git ".eggs",
| \.hg ".git",
| \.mypy_cache ".git-rewrite",
| \.tox ".hg",
| \.venv ".ipynb_checkpoints",
| _build ".mypy_cache",
| buck-out ".nox",
| build ".pants.d",
| dist ".pyenv",
".pytest_cache",
# The following are specific to Black, you probably don't want those. ".pytype",
| blib2to3 ".ruff_cache",
| tests/data ".svn",
| profiling ".tox",
)/ ".venv",
''' ".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]
[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
select = ["E4", "E7", "E9", "F"]
ignore = []
# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
[tool.ruff.format]
quote-style = "double"
indent-style = "tab"
docstring-code-format = true
line-ending = "auto"
skip-magic-trailing-comma = false

126
verse/adminpage.py

@ -3,10 +3,10 @@ import shutil
from flask import render_template from flask import render_template
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db from app import db
@ -18,88 +18,88 @@ from models.user_model import User
def AdminPage(): def AdminPage():
adminuserform = AddUsersToForm(AdminUserForm()) adminuserform = AddUsersToForm(AdminUserForm())
admindistribusiform = AddDistribusisToForm(AdminDistribusiForm()) admindistribusiform = AddDistribusisToForm(AdminDistribusiForm())
if admindistribusiform.validate_on_submit(): if admindistribusiform.validate_on_submit():
DeleteDistribusis(admindistribusiform) DeleteDistribusis(admindistribusiform)
if adminuserform.validate_on_submit(): if adminuserform.validate_on_submit():
if adminuserform.delete.data: if adminuserform.delete.data:
DeleteUsers(adminuserform) DeleteUsers(adminuserform)
template = render_template( template = render_template(
"admin.html", "admin.html",
adminuserform=adminuserform, adminuserform=adminuserform,
admindistribusiform=admindistribusiform, admindistribusiform=admindistribusiform,
) )
return template return template
def DeleteUsers(adminuserform): def DeleteUsers(adminuserform):
for userform in adminuserform: for userform in adminuserform:
if "user" in userform.id: if "user" in userform.id:
if userform.data: if userform.data:
useremail = userform.label.text useremail = userform.label.text
user = User.query.filter_by(email=useremail).first() user = User.query.filter_by(email=useremail).first()
DeleteUserDistribusis(user) DeleteUserDistribusis(user)
DeleteUserFromDb(user) DeleteUserFromDb(user)
userform.errors.append(f"User {useremail} deleted!") userform.errors.append(f"User {useremail} deleted!")
def DeleteUserFromDb(user): def DeleteUserFromDb(user):
try: try:
db.session.delete(user) db.session.delete(user)
db.session.commit() db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
def DeleteUserDistribusis(user): def DeleteUserDistribusis(user):
distribusis = DistribusisInfo.getuserdistribusis(user.email) distribusis = DistribusisInfo.getuserdistribusis(user.email)
for distribusi in distribusis: for distribusi in distribusis:
DeleteDistribusiFiles(distribusi.distribusiname) DeleteDistribusiFiles(distribusi.distribusiname)
DeleteDistribusiFromDb(distribusi) DeleteDistribusiFromDb(distribusi)
def DeleteDistribusis(admindistribusiform): def DeleteDistribusis(admindistribusiform):
for distribusiform in admindistribusiform: for distribusiform in admindistribusiform:
if "distribusi" in distribusiform.id: if "distribusi" in distribusiform.id:
if distribusiform.data: if distribusiform.data:
distribusiname = distribusiform.label.text distribusiname = distribusiform.label.text
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=distribusiname distribusiname=distribusiname
).first() ).first()
DeleteDistribusiFromDb(distribusi) DeleteDistribusiFromDb(distribusi)
DeleteDistribusiFiles(distribusiname) DeleteDistribusiFiles(distribusiname)
distribusiform.errors.append("Deleted distribusi") distribusiform.errors.append("Deleted distribusi")
def DeleteDistribusiFromDb(distribusi): def DeleteDistribusiFromDb(distribusi):
try: try:
db.session.delete(distribusi) db.session.delete(distribusi)
db.session.commit() db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
def DeleteDistribusiFiles(distribusiname): def DeleteDistribusiFiles(distribusiname):
userfolder = os.path.join("stash", distribusiname) userfolder = os.path.join("stash", distribusiname)
if os.path.exists(userfolder): if os.path.exists(userfolder):
shutil.rmtree(userfolder) shutil.rmtree(userfolder)
cssfolder = os.path.join("themes/userthemes", distribusiname) cssfolder = os.path.join("themes/userthemes", distribusiname)
if os.path.exists(cssfolder): if os.path.exists(cssfolder):
shutil.rmtree(cssfolder) shutil.rmtree(cssfolder)
def AddDistribusisToForm(admindistribusiform): def AddDistribusisToForm(admindistribusiform):
distribusis = DistribusisInfo.visibledistribusis() distribusis = DistribusisInfo.visibledistribusis()
admindistribusiform = AdminDistribusiForm.distribusi_list_form_builder( admindistribusiform = AdminDistribusiForm.distribusi_list_form_builder(
distribusis distribusis
) )
return admindistribusiform return admindistribusiform
def AddUsersToForm(adminuserform): def AddUsersToForm(adminuserform):
users = User.query.all() users = User.query.all()
adminuserform = AdminUserForm.user_list_form_builder(users) adminuserform = AdminUserForm.user_list_form_builder(users)
return adminuserform return adminuserform

54
verse/admintool.py

@ -1,10 +1,10 @@
import sys import sys
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import create_app, db from app import create_app, db
@ -13,32 +13,32 @@ from models.user_model import User # noqa: F401
def admintool(): def admintool():
"""Admin CLI tool. To elevate a user to admin""" """Admin CLI tool. To elevate a user to admin"""
app = create_app() app = create_app()
app.app_context().push() app.app_context().push()
elevateusertoadmin() elevateusertoadmin()
def elevateusertoadmin(): def elevateusertoadmin():
"""To elevates user of first command line argument to admin""" """To elevates user of first command line argument to admin"""
user = User.query.filter_by(email=sys.argv[1]).first() user = User.query.filter_by(email=sys.argv[1]).first()
print(f"user {user.username} found with email {user.email}") print(f"user {user.username} found with email {user.email}")
try: try:
user.admin = True user.admin = True
db.session.commit() db.session.commit()
print(f"Account {user.email} succesfully made into an admin") print(f"Account {user.email} succesfully made into an admin")
except InvalidRequestError: except InvalidRequestError:
db.session.rollback() db.session.rollback()
print("Something went wrong!") print("Something went wrong!")
except InterfaceError: except InterfaceError:
db.session.rollback() db.session.rollback()
print("Error connecting to the database") print("Error connecting to the database")
except DataError: except DataError:
db.session.rollback() db.session.rollback()
print("Invalid Entry") print("Invalid Entry")
except DatabaseError: except DatabaseError:
db.session.rollback() db.session.rollback()
print("Error connecting to the database") print("Error connecting to the database")
admintool() admintool()

72
verse/app.py

@ -16,56 +16,56 @@ login_manager = LoginManager()
def create_app(): def create_app():
APP.secret_key = os.urandom(24) APP.secret_key = os.urandom(24)
APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///distribusiverse.db" APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///distribusiverse.db"
APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
APP.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 1024 APP.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 1024
APP.config["MAIL_SERVER"] = "mail.autonomic.zone" APP.config["MAIL_SERVER"] = "mail.autonomic.zone"
APP.config["MAIL_PORT"] = 587 APP.config["MAIL_PORT"] = 587
APP.config["MAIL_USE_SSL"] = False APP.config["MAIL_USE_SSL"] = False
APP.config["MAIL_USE_TLS"] = True APP.config["MAIL_USE_TLS"] = True
APP.config["MAIL_USERNAME"] = "noreply@vvvvvvaria.org" APP.config["MAIL_USERNAME"] = "noreply@vvvvvvaria.org"
login_manager.session_protection = "strong" login_manager.session_protection = "strong"
login_manager.login_view = "index" login_manager.login_view = "index"
login_manager.login_message_category = "info" login_manager.login_message_category = "info"
csrf = CSRFProtect() csrf = CSRFProtect()
APP.config["SECRET_KEY"] = os.urandom(24) APP.config["SECRET_KEY"] = os.urandom(24)
APP.config["UPLOAD_FOLDER"] = "tmpupload" APP.config["UPLOAD_FOLDER"] = "tmpupload"
APP.config["PUBLIC_THEMES"] = "themes/publicthemes" APP.config["PUBLIC_THEMES"] = "themes/publicthemes"
# user settings_file # user settings_file
settings() settings()
csrf.init_app(APP) csrf.init_app(APP)
login_manager.init_app(APP) login_manager.init_app(APP)
db.init_app(APP) db.init_app(APP)
migrate.init_app(APP, db, render_as_batch=True) migrate.init_app(APP, db, render_as_batch=True)
bcrypt.init_app(APP) bcrypt.init_app(APP)
@APP.context_processor @APP.context_processor
def inject_title(): def inject_title():
return dict(title=APP.config["title"]) return dict(title=APP.config["title"])
return APP return APP
def settings(): def settings():
settings = settings_from_file() settings = settings_from_file()
APP.config.update(settings) APP.config.update(settings)
return APP return APP
def get_app(): def get_app():
return APP return APP
def settings_from_file(): def settings_from_file():
if os.path.isfile("settings_development.toml"): if os.path.isfile("settings_development.toml"):
with open("settings_development.toml", "rb") as settings_file: with open("settings_development.toml", "rb") as settings_file:
return tomllib.load(settings_file) return tomllib.load(settings_file)
with open("settings.toml", "rb") as settings_file: with open("settings.toml", "rb") as settings_file:
return tomllib.load(settings_file) return tomllib.load(settings_file)

30
verse/deploydb.py

@ -1,23 +1,23 @@
def deploy(): def deploy():
"""Run deployment of database.""" """Run deployment of database."""
from flask_migrate import init, migrate, stamp, upgrade from flask_migrate import init, migrate, stamp, upgrade
from app import create_app, db from app import create_app, db
from models.distribusi_model import Distribusis # noqa: F401 from models.distribusi_model import Distribusis # noqa: F401
from models.distribusi_file_model import DistribusiFiles # noqa: F401 from models.distribusi_file_model import DistribusiFiles # noqa: F401
# This model is required for flask_migrate to make the table # This model is required for flask_migrate to make the table
from models.user_model import User # noqa: F401 from models.user_model import User # noqa: F401
app = create_app() app = create_app()
app.app_context().push() app.app_context().push()
db.create_all() db.create_all()
# migrate database to latest revision # migrate database to latest revision
init() init()
stamp() stamp()
migrate() migrate()
upgrade() upgrade()
deploy() deploy()

34
verse/describer/describe_files.py

@ -2,23 +2,31 @@ from flask import Blueprint, render_template, redirect, url_for
from flask_login import current_user from flask_login import current_user
from models.distribusi_model import Distribusis from models.distribusi_model import Distribusis
from models.distribusi_file_model import DistribusiFiles from models.distribusi_file_model import DistribusiFiles
from describer.forms.describe_file_form import DescribeFileForm
describer = Blueprint( describer = Blueprint(
"describer", "describer",
__name__, __name__,
template_folder="templates/describe_files", template_folder="templates/describe_files",
static_folder="static", static_folder="static",
) )
@describer.route("/<string:distribusiname>") @describer.route("/<string:distribusiname>")
def describe_distribusi_files(distribusiname): def describe_distribusi_files(distribusiname):
if not current_user.is_authenticated: if not current_user.is_authenticated:
return redirect(url_for("index")) return redirect(url_for("index"))
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=distribusiname distribusiname=distribusiname
).first() ).first()
distribusi_files = DistribusiFiles.query.filter_by( distribusi_files = DistribusiFiles.query.filter_by(
distribusi=distribusi.id distribusi=distribusi.id
).all() ).all()
return render_template("describe.html", distribusi_files=distribusi_files) # distribusi_file_forms = {}
# for distribusi_file in distribusi_files:
describe_form = DescribeFileForm()
return render_template(
"describe.html",
distribusi_files=distribusi_files,
describe_form=describe_form,
)

47
verse/describer/forms/describe_file_form.py

@ -4,28 +4,29 @@ from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, validators from wtforms import StringField, SubmitField, validators
from wtforms.validators import Length from wtforms.validators import Length
class DescribeFileForm(FlaskForm): class DescribeFileForm(FlaskForm):
"""DescribeFileForm selection form.""" """DescribeFileForm selection form."""
alttext = StringField( alttext = StringField(
"Alt-text for this file:", "Alt-text for this file:",
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Length(3, 255), Length(3, 255),
], ],
) )
searchtags = StringField( searchtags = StringField(
"Add search tags, seperated by commas. No need for the '#' sign:", "Add search tags, seperated by commas. No need for the '#' sign:",
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Length(3, 500), Length(3, 500),
], ],
) )
description = StringField( description = StringField(
"Description of this file:", "Description of this file:",
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Length(3, 4096), Length(3, 4096),
], ],
) )
save = SubmitField("Save") save = SubmitField("Save")

18
verse/distribusikan/distribusikan.py

@ -10,38 +10,38 @@ from distribusikan.themeselector import ThemeSelector
from distribusikan.uploadpage import UploadPage from distribusikan.uploadpage import UploadPage
distribusikan = Blueprint( distribusikan = Blueprint(
"distribusikan", "distribusikan",
__name__, __name__,
template_folder="templates/distribusikan", template_folder="templates/distribusikan",
static_folder="static", static_folder="static",
) )
@distribusikan.route("/distribusi", methods=["GET", "POST"]) @distribusikan.route("/distribusi", methods=["GET", "POST"])
@login_required @login_required
def distribusi(): def distribusi():
return DistribusiWorkflow() return DistribusiWorkflow()
@distribusikan.route("/upload", methods=["POST"]) @distribusikan.route("/upload", methods=["POST"])
@login_required @login_required
def upload(): def upload():
return UploadPage() return UploadPage()
@distribusikan.route("/theme", methods=["GET", "POST"]) @distribusikan.route("/theme", methods=["GET", "POST"])
@login_required @login_required
def theme(): def theme():
return ThemeSelector() return ThemeSelector()
@distribusikan.route("/editor", methods=["GET", "POST"]) @distribusikan.route("/editor", methods=["GET", "POST"])
@login_required @login_required
def editor(): def editor():
return Editor() return Editor()
@distribusikan.route("/selector", methods=["GET", "POST"]) @distribusikan.route("/selector", methods=["GET", "POST"])
@login_required @login_required
def selector(): def selector():
return DistribusiSelector() return DistribusiSelector()

244
verse/distribusikan/distribusiselector.py

@ -4,10 +4,10 @@ import shutil
from flask import flash, render_template, redirect, url_for from flask import flash, render_template, redirect, url_for
from flask_login import current_user from flask_login import current_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db from app import db
@ -25,148 +25,148 @@ from statuspengguna.helper import UserHelper
def DistribusiSelector(): def DistribusiSelector():
uploadform = UploadForm() uploadform = UploadForm()
selectorform = SelectorForm() selectorform = SelectorForm()
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames() selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if selectorform.validate_on_submit(): if selectorform.validate_on_submit():
if selectorform.new.data: if selectorform.new.data:
SelectNewDistribusi() SelectNewDistribusi()
if selectorform.describe.data: if selectorform.describe.data:
return SelectDescribeDistribusi(selectorform.distribusis.data) return SelectDescribeDistribusi(selectorform.distribusis.data)
if selectorform.delete.data: if selectorform.delete.data:
selectorform = DeleteDistribusi(selectorform.distribusis.data) selectorform = DeleteDistribusi(selectorform.distribusis.data)
selectorform.distribusis.choices = ( selectorform.distribusis.choices = (
DistribusisInfo.userdistribusinames() DistribusisInfo.userdistribusinames()
) )
if selectorform.update.data: if selectorform.update.data:
SelectUpdateDistribusi(selectorform.distribusis.data) SelectUpdateDistribusi(selectorform.distribusis.data)
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
uploadform = AutoFillInUploadForm(uploadform, current_distribusi) uploadform = AutoFillInUploadForm(uploadform, current_distribusi)
return RenderDistribusiTemplate( return RenderDistribusiTemplate(
selectorform, uploadform, current_distribusi selectorform, uploadform, current_distribusi
) )
def AutoFillInUploadForm(uploadform, current_distribusi): def AutoFillInUploadForm(uploadform, current_distribusi):
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
uploadform.sitename.data = distribusi.distribusiname uploadform.sitename.data = distribusi.distribusiname
uploadform.sitename.render_kw = {"readonly": True} uploadform.sitename.render_kw = {"readonly": True}
uploadform.category.data = distribusi.category uploadform.category.data = distribusi.category
uploadform.year.data = distribusi.year uploadform.year.data = distribusi.year
uploadform.tags.data = distribusi.tags uploadform.tags.data = distribusi.tags
return uploadform return uploadform
def SelectNewDistribusi(): def SelectNewDistribusi():
print("make a new distribusi") print("make a new distribusi")
SelectCurrentDistribusi("new") SelectCurrentDistribusi("new")
def SelectDescribeDistribusi(distribusiname): def SelectDescribeDistribusi(distribusiname):
return redirect( return redirect(
url_for( url_for(
"describer.describe_distribusi_files", "describer.describe_distribusi_files",
distribusiname=distribusiname, distribusiname=distribusiname,
) )
) )
def SelectUpdateDistribusi(distribusiname): def SelectUpdateDistribusi(distribusiname):
print(f"Update this distribusi {distribusiname}") print(f"Update this distribusi {distribusiname}")
SelectCurrentDistribusi(distribusiname) SelectCurrentDistribusi(distribusiname)
def DeleteDistribusi(distribusiname): def DeleteDistribusi(distribusiname):
print(f"delete this distribusi {distribusiname}") print(f"delete this distribusi {distribusiname}")
selectorform = SelectorForm() selectorform = SelectorForm()
try: try:
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=distribusiname distribusiname=distribusiname
).first() ).first()
if distribusi.userid is user.id: if distribusi.userid is user.id:
db.session.delete(distribusi) db.session.delete(distribusi)
db.session.commit() db.session.commit()
userfolder = os.path.join("stash", distribusi.distribusiname) userfolder = os.path.join("stash", distribusi.distribusiname)
if os.path.exists(userfolder): if os.path.exists(userfolder):
shutil.rmtree(userfolder) shutil.rmtree(userfolder)
cssfolder = os.path.join( cssfolder = os.path.join(
"themes/userthemes", distribusi.distribusiname "themes/userthemes", distribusi.distribusiname
) )
if os.path.exists(cssfolder): if os.path.exists(cssfolder):
shutil.rmtree(cssfolder) shutil.rmtree(cssfolder)
if distribusi.publictheme is not None: if distribusi.publictheme is not None:
publicthemefolder = os.path.join( publicthemefolder = os.path.join(
"themes/publicthemes", distribusi.distribusiname "themes/publicthemes", distribusi.distribusiname
) )
if os.path.exists(publicthemefolder): if os.path.exists(publicthemefolder):
shutil.rmtree(publicthemefolder) shutil.rmtree(publicthemefolder)
# SelectField error is list is a tuple?? why?? # SelectField error is list is a tuple?? why??
# selectorform.distribusis.errors.append("Distribusi deleted!") # selectorform.distribusis.errors.append("Distribusi deleted!")
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
# selectorform.distribusis.errors.append("Unknown error occured!") # selectorform.distribusis.errors.append("Unknown error occured!")
flash("An error occured !", "danger") flash("An error occured !", "danger")
return selectorform return selectorform
def SelectCurrentDistribusi(distribusiname): def SelectCurrentDistribusi(distribusiname):
if not current_user.is_authenticated: if not current_user.is_authenticated:
return return
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
try: try:
user.currentdistribusi = distribusiname user.currentdistribusi = distribusiname
db.session.commit() db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
flash("An error occured !", "danger") flash("An error occured !", "danger")
def DistribusiSelected(): def DistribusiSelected():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
if user.currentdistribusi is None: if user.currentdistribusi is None:
return False return False
return True return True
def SelectorVisible(): def SelectorVisible():
has_distribusi = UserHelper.has_distribusi() has_distribusi = UserHelper.has_distribusi()
distribusi_selected = DistribusiSelected() distribusi_selected = DistribusiSelected()
if distribusi_selected: if distribusi_selected:
return False return False
if not has_distribusi: if not has_distribusi:
return False return False
return True return True
def RenderDistribusiTemplate(selectorform, uploadform, current_distribusi): def RenderDistribusiTemplate(selectorform, uploadform, current_distribusi):
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
# because the user has chosen to update his distribusi, we assume # because the user has chosen to update his distribusi, we assume
# no selected css. # no selected css.
css_selected = False css_selected = False
selectorvisible = SelectorVisible() selectorvisible = SelectorVisible()
limit_reached = UserHelper.distribusi_limit_reached() limit_reached = UserHelper.distribusi_limit_reached()
template = render_template( template = render_template(
"distribusi.html", "distribusi.html",
uploadform=uploadform, uploadform=uploadform,
distribusiform=distribusiform, distribusiform=distribusiform,
themeform=themeform, themeform=themeform,
publicthemeform=publicthemeform, publicthemeform=publicthemeform,
selectorform=selectorform, selectorform=selectorform,
files_uploaded=files_uploaded, files_uploaded=files_uploaded,
distribusi_live=distribusi_live, distribusi_live=distribusi_live,
css_selected=css_selected, css_selected=css_selected,
selectorvisible=selectorvisible, selectorvisible=selectorvisible,
limit_reached=limit_reached, limit_reached=limit_reached,
) )
return template return template

54
verse/distribusikan/distribusisinfo.py

@ -5,34 +5,34 @@ from models.user_model import User
class DistribusisInfo: class DistribusisInfo:
def userdistribusinames(): def userdistribusinames():
distribusinames = [] distribusinames = []
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
for distribusi in Distribusis.query.filter_by(userid=user.id).all(): for distribusi in Distribusis.query.filter_by(userid=user.id).all():
distribusinames.append(distribusi.distribusiname) distribusinames.append(distribusi.distribusiname)
return distribusinames return distribusinames
def publicthemes(): def publicthemes():
publicthemes = [] publicthemes = []
distribusis = Distribusis.query.filter( distribusis = Distribusis.query.filter(
Distribusis.publictheme.isnot(None) Distribusis.publictheme.isnot(None)
).all() ).all()
for distribusi in distribusis: for distribusi in distribusis:
user = User.query.filter_by(id=distribusi.userid).first() user = User.query.filter_by(id=distribusi.userid).first()
publictheme = ( publictheme = (
f"{distribusi.distribusiname}/{distribusi.publictheme}", f"{distribusi.distribusiname}/{distribusi.publictheme}",
f"""{distribusi.publictheme} used in {distribusi.distribusiname} f"""{distribusi.publictheme} used in {distribusi.distribusiname}
made by {user.username}""", made by {user.username}""",
) )
publicthemes.append(publictheme) publicthemes.append(publictheme)
return publicthemes return publicthemes
def visibledistribusis(): def visibledistribusis():
distribusis = Distribusis.query.filter( distribusis = Distribusis.query.filter(
Distribusis.visible.isnot(False) Distribusis.visible.isnot(False)
).all() ).all()
return distribusis return distribusis
def getuserdistribusis(useremail): def getuserdistribusis(useremail):
user = User.query.filter_by(email=useremail).first() user = User.query.filter_by(email=useremail).first()
return Distribusis.query.filter_by(userid=user.id).all() return Distribusis.query.filter_by(userid=user.id).all()

176
verse/distribusikan/distribusiworkflow.py

@ -8,10 +8,10 @@ from distribusi.distribusi import distribusify
from flask import flash, redirect, render_template, url_for from flask import flash, redirect, render_template, url_for
from flask_login import current_user from flask_login import current_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db from app import db
@ -32,112 +32,112 @@ from statuspengguna.helper import UserHelper
def DistribusiWorkflow(): def DistribusiWorkflow():
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
if distribusiform.validate_on_submit(): if distribusiform.validate_on_submit():
userfolder = os.path.join("stash", distribusi.distribusiname) userfolder = os.path.join("stash", distribusi.distribusiname)
cssfile = GetCssFile(distribusi) cssfile = GetCssFile(distribusi)
UnzipDistribusiFiles(distribusi, userfolder) UnzipDistribusiFiles(distribusi, userfolder)
CleanUpDistribusiFiles(userfolder) CleanUpDistribusiFiles(userfolder)
RunDistribusi(userfolder, cssfile) RunDistribusi(userfolder, cssfile)
SetDistribusiToVisible(distribusi, user) SetDistribusiToVisible(distribusi, user)
DeleteCssFile(cssfile) DeleteCssFile(cssfile)
return redirect(url_for("index")) return redirect(url_for("index"))
return RenderDistribusiTemplate(distribusiform, current_distribusi) return RenderDistribusiTemplate(distribusiform, current_distribusi)
def UnzipDistribusiFiles(distribusi, userfolder): def UnzipDistribusiFiles(distribusi, userfolder):
zipfilename = "{}.zip".format(distribusi.distribusiname) zipfilename = "{}.zip".format(distribusi.distribusiname)
unzipfile = os.path.join(userfolder, zipfilename) unzipfile = os.path.join(userfolder, zipfilename)
if os.path.exists(unzipfile): if os.path.exists(unzipfile):
with zipfile.ZipFile(unzipfile, "r") as zip_ref: with zipfile.ZipFile(unzipfile, "r") as zip_ref:
zip_ref.extractall(userfolder) zip_ref.extractall(userfolder)
# after extracting all files remove zip file. # after extracting all files remove zip file.
if os.path.exists(unzipfile): if os.path.exists(unzipfile):
os.remove(os.path.join(userfolder, zipfilename)) os.remove(os.path.join(userfolder, zipfilename))
def CleanUpDistribusiFiles(userfolder): def CleanUpDistribusiFiles(userfolder):
if os.path.exists(userfolder): if os.path.exists(userfolder):
RemoveMacFolders(userfolder) RemoveMacFolders(userfolder)
def RemoveMacFolders(path): def RemoveMacFolders(path):
for filename in os.listdir(path): for filename in os.listdir(path):
fullpath = os.path.join(path, filename) fullpath = os.path.join(path, filename)
if filename.startswith("."): if filename.startswith("."):
if os.path.isdir(fullpath): if os.path.isdir(fullpath):
shutil.rmtree(fullpath) shutil.rmtree(fullpath)
else: else:
os.remove(fullpath) os.remove(fullpath)
if filename == "__MACOSX": if filename == "__MACOSX":
shutil.rmtree(fullpath) shutil.rmtree(fullpath)
if os.path.isdir(fullpath): if os.path.isdir(fullpath):
RemoveMacFolders(fullpath) RemoveMacFolders(fullpath)
def GetCssFile(distribusi): def GetCssFile(distribusi):
cssfile = "" cssfile = ""
cssfolder = os.path.join("themes/userthemes", distribusi.distribusiname) cssfolder = os.path.join("themes/userthemes", distribusi.distribusiname)
if os.path.exists(cssfolder): if os.path.exists(cssfolder):
for filename in os.listdir(cssfolder): for filename in os.listdir(cssfolder):
if filename.endswith(".css"): if filename.endswith(".css"):
cssfile = os.path.join(cssfolder, filename) cssfile = os.path.join(cssfolder, filename)
return cssfile return cssfile
def RunDistribusi(userfolder, cssfile): def RunDistribusi(userfolder, cssfile):
parser = build_argparser() parser = build_argparser()
args = parser.parse_args(["-t", "--menu-with-index", "-s", cssfile]) args = parser.parse_args(["-t", "--menu-with-index", "-s", cssfile])
distribusify(args, userfolder) distribusify(args, userfolder)
def SetDistribusiToVisible(distribusi, user): def SetDistribusiToVisible(distribusi, user):
try: try:
distribusi.visible = True distribusi.visible = True
user.currentdistribusi = None user.currentdistribusi = None
db.session.commit() db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
flash("Unknown error occured!") flash("Unknown error occured!")
def DeleteCssFile(cssfile): def DeleteCssFile(cssfile):
if os.path.exists(cssfile): if os.path.exists(cssfile):
os.remove(cssfile) os.remove(cssfile)
def RenderDistribusiTemplate(distribusiform, current_distribusi): def RenderDistribusiTemplate(distribusiform, current_distribusi):
uploadform = UploadForm() uploadform = UploadForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
selectorform = SelectorForm() selectorform = SelectorForm()
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames() selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
selectorvisible = SelectorVisible() selectorvisible = SelectorVisible()
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
css_selected = UserHelper.is_css_selected(current_distribusi) css_selected = UserHelper.is_css_selected(current_distribusi)
limit_reached = UserHelper.distribusi_limit_reached() limit_reached = UserHelper.distribusi_limit_reached()
template = render_template( template = render_template(
"distribusi.html", "distribusi.html",
uploadform=uploadform, uploadform=uploadform,
distribusiform=distribusiform, distribusiform=distribusiform,
themeform=themeform, themeform=themeform,
publicthemeform=publicthemeform, publicthemeform=publicthemeform,
selectorform=selectorform, selectorform=selectorform,
files_uploaded=files_uploaded, files_uploaded=files_uploaded,
distribusi_live=distribusi_live, distribusi_live=distribusi_live,
css_selected=css_selected, css_selected=css_selected,
selectorvisible=selectorvisible, selectorvisible=selectorvisible,
limit_reached=limit_reached, limit_reached=limit_reached,
) )
return template return template

284
verse/distribusikan/editor.py

@ -5,10 +5,10 @@ import bleach
from bleach_allowlist import all_styles from bleach_allowlist import all_styles
from flask import render_template from flask import render_template
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
@ -25,175 +25,175 @@ from statuspengguna.helper import UserHelper
def Editor(): def Editor():
editorform = EditorForm() editorform = EditorForm()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if editorform.validate_on_submit(): if editorform.validate_on_submit():
ValidateEditCssForm(editorform, current_distribusi) ValidateEditCssForm(editorform, current_distribusi)
return RenderDistribusiTemplate(current_distribusi) return RenderDistribusiTemplate(current_distribusi)
return RenderEditorTemplate(editorform, current_distribusi) return RenderEditorTemplate(editorform, current_distribusi)
def ValidateEditCssForm(editorform, current_distribusi): def ValidateEditCssForm(editorform, current_distribusi):
newcssfolder = os.path.join("themes/userthemes", current_distribusi) newcssfolder = os.path.join("themes/userthemes", current_distribusi)
if os.path.exists(newcssfolder): if os.path.exists(newcssfolder):
shutil.rmtree(newcssfolder) shutil.rmtree(newcssfolder)
publicfolder = os.path.join("themes/publicthemes", current_distribusi) publicfolder = os.path.join("themes/publicthemes", current_distribusi)
if os.path.exists(publicfolder): if os.path.exists(publicfolder):
shutil.rmtree(publicfolder) shutil.rmtree(publicfolder)
if editorform.public.data: if editorform.public.data:
MakePublicTheme(editorform, current_distribusi) MakePublicTheme(editorform, current_distribusi)
if editorform.cssfile.data: if editorform.cssfile.data:
SaveUploadCssFile(editorform, publicfolder) SaveUploadCssFile(editorform, publicfolder)
CopyPublicToUserFolder(editorform, publicfolder, newcssfolder) CopyPublicToUserFolder(editorform, publicfolder, newcssfolder)
return return
else: else:
WriteCssToFile(editorform, publicfolder) WriteCssToFile(editorform, publicfolder)
if editorform.cssfile.data: if editorform.cssfile.data:
SaveUploadCssFile(editorform, newcssfolder) SaveUploadCssFile(editorform, newcssfolder)
return return
if editorform.cssname.data: if editorform.cssname.data:
WriteCssToFile(editorform, newcssfolder) WriteCssToFile(editorform, newcssfolder)
def SaveUploadCssFile(editorform, newcssfolder): def SaveUploadCssFile(editorform, newcssfolder):
if not os.path.exists(newcssfolder): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
cssfile = editorform.cssfile.data cssfile = editorform.cssfile.data
cssfilename = f"{secure_filename(editorform.cssname.data)}.css" cssfilename = f"{secure_filename(editorform.cssname.data)}.css"
cssfile.save(os.path.join(newcssfolder, cssfilename)) cssfile.save(os.path.join(newcssfolder, cssfilename))
openfile = open(os.path.join(newcssfolder, cssfilename), "r") openfile = open(os.path.join(newcssfolder, cssfilename), "r")
cleancss = bleach.clean(openfile.read(), all_styles) cleancss = bleach.clean(openfile.read(), all_styles)
cleancss = cleancss.replace("&gt;", ">") cleancss = cleancss.replace("&gt;", ">")
openfile.close() openfile.close()
cleanfile = open(os.path.join(newcssfolder, cssfilename), "w") cleanfile = open(os.path.join(newcssfolder, cssfilename), "w")
cleanfile.write(cleancss) cleanfile.write(cleancss)
cleanfile.close() cleanfile.close()
def WriteCssToFile(editorform, newcssfolder): def WriteCssToFile(editorform, newcssfolder):
if not os.path.exists(newcssfolder): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
cssfilename = f"{secure_filename(editorform.cssname.data)}.css" cssfilename = f"{secure_filename(editorform.cssname.data)}.css"
cleancss = bleach.clean(editorform.css.data, all_styles) cleancss = bleach.clean(editorform.css.data, all_styles)
cleancss = cleancss.replace("&gt;", ">") cleancss = cleancss.replace("&gt;", ">")
with open(os.path.join(newcssfolder, cssfilename), "w") as cssfile: with open(os.path.join(newcssfolder, cssfilename), "w") as cssfile:
cssfile.write(cleancss) cssfile.write(cleancss)
cssfile.close cssfile.close
def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder): def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder):
if not os.path.exists(newcssfolder): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
copycssfile = os.path.join( copycssfile = os.path.join(
publicfolder, f"{secure_filename(editorform.cssname.data)}.css" publicfolder, f"{secure_filename(editorform.cssname.data)}.css"
) )
print(f"copying file: {copycssfile}") print(f"copying file: {copycssfile}")
print(f"to folder: {newcssfolder}") print(f"to folder: {newcssfolder}")
shutil.copy(copycssfile, newcssfolder) shutil.copy(copycssfile, newcssfolder)
def MakePublicTheme(editorform, current_distribusi): def MakePublicTheme(editorform, current_distribusi):
try: try:
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
distribusi.publictheme = secure_filename(editorform.cssname.data) distribusi.publictheme = secure_filename(editorform.cssname.data)
db.session.commit() db.session.commit()
except InvalidRequestError: except InvalidRequestError:
db.session.rollback() db.session.rollback()
editorform.public.errors.append("Something went wrong!") editorform.public.errors.append("Something went wrong!")
except DataError: except DataError:
db.session.rollback() db.session.rollback()
editorform.public.errors.append("Invalid Entry") editorform.public.errors.append("Invalid Entry")
except InterfaceError: except InterfaceError:
db.session.rollback() db.session.rollback()
editorform.public.errors.append("Error connecting to the database") editorform.public.errors.append("Error connecting to the database")
except DatabaseError: except DatabaseError:
db.session.rollback() db.session.rollback()
editorform.public.errors.append("Error connecting to the database") editorform.public.errors.append("Error connecting to the database")
def RenderDistribusiTemplate(current_distribusi): def RenderDistribusiTemplate(current_distribusi):
uploadform = UploadForm() uploadform = UploadForm()
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
selectorform = SelectorForm() selectorform = SelectorForm()
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
css_selected = True css_selected = True
selectorvisible = False selectorvisible = False
limit_reached = UserHelper.distribusi_limit_reached() limit_reached = UserHelper.distribusi_limit_reached()
template = render_template( template = render_template(
"distribusi.html", "distribusi.html",
uploadform=uploadform, uploadform=uploadform,
distribusiform=distribusiform, distribusiform=distribusiform,
themeform=themeform, themeform=themeform,
publicthemeform=publicthemeform, publicthemeform=publicthemeform,
selectorform=selectorform, selectorform=selectorform,
files_uploaded=files_uploaded, files_uploaded=files_uploaded,
distribusi_live=distribusi_live, distribusi_live=distribusi_live,
css_selected=css_selected, css_selected=css_selected,
selectorvisible=selectorvisible, selectorvisible=selectorvisible,
limit_reached=limit_reached, limit_reached=limit_reached,
) )
return template return template
def RenderEditorTemplate(editorform, current_distribusi): def RenderEditorTemplate(editorform, current_distribusi):
htmlplaceholder = HtmlPlaceholder() htmlplaceholder = HtmlPlaceholder()
cssplaceholder = CssPlaceholder(current_distribusi) cssplaceholder = CssPlaceholder(current_distribusi)
editorform.css.data = cssplaceholder editorform.css.data = cssplaceholder
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
template = render_template( template = render_template(
"editor.html", "editor.html",
files_uploaded=files_uploaded, files_uploaded=files_uploaded,
distribusi_live=distribusi_live, distribusi_live=distribusi_live,
editorform=editorform, editorform=editorform,
htmlplaceholder=htmlplaceholder, htmlplaceholder=htmlplaceholder,
) )
return template return template
def CssPlaceholder(current_distribusi): def CssPlaceholder(current_distribusi):
cssplaceholder = "Try out your CSS here" cssplaceholder = "Try out your CSS here"
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
if distribusi is not None and distribusi.publictheme is not None: if distribusi is not None and distribusi.publictheme is not None:
cssplaceholder = GetPublicCssFile(distribusi) cssplaceholder = GetPublicCssFile(distribusi)
else: else:
with open("themes/editor/placeholder.css") as f: with open("themes/editor/placeholder.css") as f:
cssplaceholder = f.read() cssplaceholder = f.read()
return cssplaceholder return cssplaceholder
def HtmlPlaceholder(): def HtmlPlaceholder():
htmlplaceholder = "Write some test HTML here" htmlplaceholder = "Write some test HTML here"
with open("themes/editor/placeholder.html") as f: with open("themes/editor/placeholder.html") as f:
htmlplaceholder = f.read() htmlplaceholder = f.read()
return htmlplaceholder return htmlplaceholder
def GetPublicCssFile(distribusi): def GetPublicCssFile(distribusi):
cssplaceholder = "" cssplaceholder = ""
publicthemefolder = os.path.join( publicthemefolder = os.path.join(
"themes/publicthemes", distribusi.distribusiname "themes/publicthemes", distribusi.distribusiname
) )
for filename in os.listdir(publicthemefolder): for filename in os.listdir(publicthemefolder):
if filename.endswith(".css"): if filename.endswith(".css"):
cssfile = os.path.join(publicthemefolder, filename) cssfile = os.path.join(publicthemefolder, filename)
with open(cssfile) as f: with open(cssfile) as f:
cssplaceholder = f.read() cssplaceholder = f.read()
return cssplaceholder return cssplaceholder

90
verse/distribusikan/themeselector.py

@ -13,55 +13,55 @@ from statuspengguna.helper import UserHelper
def ThemeSelector(): def ThemeSelector():
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if themeform.validate_on_submit(): if themeform.validate_on_submit():
copycssfile = os.path.join( copycssfile = os.path.join(
"themes", "themes",
f"{themeform.theme.data}.css", f"{themeform.theme.data}.css",
) )
MoveCssToUserFolder(current_distribusi, copycssfile) MoveCssToUserFolder(current_distribusi, copycssfile)
if publicthemeform.validate_on_submit(): if publicthemeform.validate_on_submit():
copycssfile = os.path.join( copycssfile = os.path.join(
"themes/publicthemes/", "themes/publicthemes/",
f"{publicthemeform.publicthemes.data}.css", f"{publicthemeform.publicthemes.data}.css",
) )
MoveCssToUserFolder(current_distribusi, copycssfile) MoveCssToUserFolder(current_distribusi, copycssfile)
return RenderDistribusiTemplate( return RenderDistribusiTemplate(
themeform, publicthemeform, current_distribusi themeform, publicthemeform, current_distribusi
) )
def MoveCssToUserFolder(current_distribusi, copycssfile): def MoveCssToUserFolder(current_distribusi, copycssfile):
newcssfolder = os.path.join("themes/userthemes", current_distribusi) newcssfolder = os.path.join("themes/userthemes", current_distribusi)
if not os.path.exists(newcssfolder): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
shutil.copy(copycssfile, newcssfolder) shutil.copy(copycssfile, newcssfolder)
def RenderDistribusiTemplate(themeform, publicthemeform, current_distribusi): def RenderDistribusiTemplate(themeform, publicthemeform, current_distribusi):
uploadform = UploadForm() uploadform = UploadForm()
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
selectorform = SelectorForm() selectorform = SelectorForm()
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
css_selected = UserHelper.is_css_selected(current_distribusi) css_selected = UserHelper.is_css_selected(current_distribusi)
selectorvisible = False selectorvisible = False
limit_reached = UserHelper.distribusi_limit_reached() limit_reached = UserHelper.distribusi_limit_reached()
template = render_template( template = render_template(
"distribusi.html", "distribusi.html",
uploadform=uploadform, uploadform=uploadform,
distribusiform=distribusiform, distribusiform=distribusiform,
themeform=themeform, themeform=themeform,
publicthemeform=publicthemeform, publicthemeform=publicthemeform,
selectorform=selectorform, selectorform=selectorform,
files_uploaded=files_uploaded, files_uploaded=files_uploaded,
distribusi_live=distribusi_live, distribusi_live=distribusi_live,
css_selected=css_selected, css_selected=css_selected,
selectorvisible=selectorvisible, selectorvisible=selectorvisible,
limit_reached=limit_reached, limit_reached=limit_reached,
) )
return template return template

136
verse/distribusikan/upload.py

@ -4,11 +4,11 @@ import shutil
from flask import flash from flask import flash
from flask_login import current_user from flask_login import current_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
IntegrityError, IntegrityError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db from app import db
@ -20,76 +20,76 @@ from statuspengguna.helper import UserHelper
def UploadNewDistribusi(uploadfolder): def UploadNewDistribusi(uploadfolder):
uploadform = UploadForm() uploadform = UploadForm()
if uploadform.validate_on_submit(): if uploadform.validate_on_submit():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
try: try:
newdistribusi = Distribusis( newdistribusi = Distribusis(
distribusiname=uploadform.sitename.data, distribusiname=uploadform.sitename.data,
userid=user.id, userid=user.id,
category=uploadform.category.data, category=uploadform.category.data,
year=uploadform.year.data, year=uploadform.year.data,
tags=uploadform.tags.data, tags=uploadform.tags.data,
) )
user.currentdistribusi = uploadform.sitename.data user.currentdistribusi = uploadform.sitename.data
db.session.add(newdistribusi) db.session.add(newdistribusi)
db.session.commit() db.session.commit()
except IntegrityError: except IntegrityError:
db.session.rollback() db.session.rollback()
uploadform.sitename.errors.append( uploadform.sitename.errors.append(
"distribusi name already exists!" "distribusi name already exists!"
) )
flash("distribusi name already exists!", "warning") flash("distribusi name already exists!", "warning")
return uploadform return uploadform
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
uploadform.sitename.errors.append("Something went wrong!") uploadform.sitename.errors.append("Something went wrong!")
flash("Something went wrong!", "danger") flash("Something went wrong!", "danger")
return uploadform return uploadform
SelectCurrentDistribusi(newdistribusi.distribusiname) SelectCurrentDistribusi(newdistribusi.distribusiname)
zipfilename = "{}.zip".format(newdistribusi.distribusiname) zipfilename = "{}.zip".format(newdistribusi.distribusiname)
zipfile = uploadform.zipfile.data zipfile = uploadform.zipfile.data
zipfile.save(os.path.join(uploadfolder, zipfilename)) zipfile.save(os.path.join(uploadfolder, zipfilename))
newuserfolder = os.path.join("stash", newdistribusi.distribusiname) newuserfolder = os.path.join("stash", newdistribusi.distribusiname)
if not os.path.exists(newuserfolder): if not os.path.exists(newuserfolder):
os.mkdir(newuserfolder) os.mkdir(newuserfolder)
copyzipfile = os.path.join(uploadfolder, zipfilename) copyzipfile = os.path.join(uploadfolder, zipfilename)
shutil.copy(copyzipfile, newuserfolder) shutil.copy(copyzipfile, newuserfolder)
os.remove(os.path.join(uploadfolder, zipfilename)) os.remove(os.path.join(uploadfolder, zipfilename))
return uploadform return uploadform
def UploadUpdatedFiles(uploadfolder): def UploadUpdatedFiles(uploadfolder):
uploadform = UploadForm() uploadform = UploadForm()
if uploadform.validate_on_submit(): if uploadform.validate_on_submit():
try: try:
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
distribusi.category = uploadform.category.data distribusi.category = uploadform.category.data
distribusi.year = uploadform.year.data distribusi.year = uploadform.year.data
distribusi.tags = uploadform.tags.data distribusi.tags = uploadform.tags.data
distribusi.visible = False distribusi.visible = False
db.session.commit() db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
uploadform.sitename.errors.append("Something went wrong!") uploadform.sitename.errors.append("Something went wrong!")
zipfilename = "{}.zip".format(distribusi.distribusiname) zipfilename = "{}.zip".format(distribusi.distribusiname)
zipfile = uploadform.zipfile.data zipfile = uploadform.zipfile.data
zipfile.save(os.path.join(uploadfolder, zipfilename)) zipfile.save(os.path.join(uploadfolder, zipfilename))
newuserfolder = os.path.join("stash", distribusi.distribusiname) newuserfolder = os.path.join("stash", distribusi.distribusiname)
if os.path.exists(newuserfolder): if os.path.exists(newuserfolder):
shutil.rmtree(newuserfolder) shutil.rmtree(newuserfolder)
os.mkdir(newuserfolder) os.mkdir(newuserfolder)
copyzipfile = os.path.join(uploadfolder, zipfilename) copyzipfile = os.path.join(uploadfolder, zipfilename)
shutil.copy(copyzipfile, newuserfolder) shutil.copy(copyzipfile, newuserfolder)
os.remove(os.path.join(uploadfolder, zipfilename)) os.remove(os.path.join(uploadfolder, zipfilename))
return uploadform return uploadform

64
verse/distribusikan/uploadpage.py

@ -14,37 +14,37 @@ from statuspengguna.helper import UserHelper
def UploadPage(): def UploadPage():
"render upload page section of distribusi workflow" "render upload page section of distribusi workflow"
uploadfolder = APP.config["UPLOAD_FOLDER"] uploadfolder = APP.config["UPLOAD_FOLDER"]
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
selectorform = SelectorForm() selectorform = SelectorForm()
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames() selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
selectorvisible = SelectorVisible() selectorvisible = SelectorVisible()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if current_distribusi == "new" or UserHelper.has_distribusi() is False: if current_distribusi == "new" or UserHelper.has_distribusi() is False:
uploadform = UploadNewDistribusi(uploadfolder) uploadform = UploadNewDistribusi(uploadfolder)
else: else:
uploadform = UploadUpdatedFiles(uploadfolder) uploadform = UploadUpdatedFiles(uploadfolder)
files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data) files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
css_selected = UserHelper.is_css_selected(current_distribusi) css_selected = UserHelper.is_css_selected(current_distribusi)
limit_reached = UserHelper.distribusi_limit_reached() limit_reached = UserHelper.distribusi_limit_reached()
template = render_template( template = render_template(
"distribusi.html", "distribusi.html",
uploadform=uploadform, uploadform=uploadform,
distribusiform=distribusiform, distribusiform=distribusiform,
themeform=themeform, themeform=themeform,
publicthemeform=publicthemeform, publicthemeform=publicthemeform,
selectorform=selectorform, selectorform=selectorform,
files_uploaded=files_uploaded, files_uploaded=files_uploaded,
distribusi_live=distribusi_live, distribusi_live=distribusi_live,
css_selected=css_selected, css_selected=css_selected,
selectorvisible=selectorvisible, selectorvisible=selectorvisible,
limit_reached=limit_reached, limit_reached=limit_reached,
) )
return template return template

100
verse/file_crawler.py

@ -6,70 +6,68 @@ from models.distribusi_model import Distribusis
from models.distribusi_file_model import DistribusiFiles from models.distribusi_file_model import DistribusiFiles
from app import create_app, get_app, db from app import create_app, get_app, db
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
IntegrityError, IntegrityError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
MIME_TYPE = magic.Magic(mime=True) MIME_TYPE = magic.Magic(mime=True)
def _distribusi_file_with_type(distribusi, full_path): def _distribusi_file_with_type(distribusi, full_path):
mime = MIME_TYPE.from_file(full_path) mime = MIME_TYPE.from_file(full_path)
type_, subtype = mime.split("/") type_, subtype = mime.split("/")
if type_ in FILE_TYPES: if type_ in FILE_TYPES:
_add_distribusi_file_to_db(distribusi, full_path, type_) _add_distribusi_file_to_db(distribusi, full_path, type_)
def _get_distribusi_from_path(path): def _get_distribusi_from_path(path):
distribusi = Distribusis.query.filter_by(distribusiname=path).first() distribusi = Distribusis.query.filter_by(distribusiname=path).first()
return distribusi return distribusi
def _add_distribusi_file_to_db(distribusi, full_path, type): def _add_distribusi_file_to_db(distribusi, full_path, type):
app = get_app() app = get_app()
print(f"adding file to database: {full_path} type: {type}") print(f"adding file to database: {full_path} type: {type}")
try: try:
new_distribusi_file = DistribusiFiles( new_distribusi_file = DistribusiFiles(
path=full_path, path=full_path,
type=type, type=type,
distribusi=distribusi.id, distribusi=distribusi.id,
) )
db.session.add(new_distribusi_file) db.session.add(new_distribusi_file)
db.session.commit() db.session.commit()
return return
except InvalidRequestError: except InvalidRequestError:
db.session.rollback() db.session.rollback()
app.logger.error("Something went wrong!") app.logger.error("Something went wrong!")
except IntegrityError: except IntegrityError:
db.session.rollback() db.session.rollback()
app.logger.error("File %s already exists!", full_path) app.logger.error("File %s already exists!", full_path)
except DataError: except DataError:
db.session.rollback() db.session.rollback()
app.logger.error("%s Invalid Entry", full_path) app.logger.error("%s Invalid Entry", full_path)
except InterfaceError: except InterfaceError:
db.session.rollback() db.session.rollback()
app.logger.error( app.logger.error("Error connecting to the database")
"Error connecting to the database" except DatabaseError:
) db.session.rollback()
except DatabaseError: app.logger.error("Error connecting to the database")
db.session.rollback()
app.logger.error(
"Error connecting to the database"
)
def add_distribusi_files(path): def add_distribusi_files(path):
app = create_app() app = create_app()
with app.app_context(): with app.app_context():
distribusi = _get_distribusi_from_path(path) distribusi = _get_distribusi_from_path(path)
path = os.path.join("stash", path) path = os.path.join("stash", path)
for root, dirs, files in os.walk(path, topdown=True): for root, dirs, files in os.walk(path, topdown=True):
files = list(filter(lambda f: not f.startswith("."), files)) files = list(filter(lambda f: not f.startswith("."), files))
files = list(filter(lambda f: not f.endswith(".html"), files)) files = list(filter(lambda f: not f.endswith(".html"), files))
for file in files: for file in files:
full_path = os.path.join(root, file) full_path = os.path.join(root, file)
_distribusi_file_with_type(distribusi, full_path) _distribusi_file_with_type(distribusi, full_path)
add_distribusi_files("2018-12-WttF-Mastodon-and-the-Fediverse") add_distribusi_files("2018-12-WttF-Mastodon-and-the-Fediverse")

24
verse/forms/admindistribusiform.py

@ -5,19 +5,19 @@ from wtforms import BooleanField, SubmitField
class AdminDistribusiForm(FlaskForm): class AdminDistribusiForm(FlaskForm):
"""Admin Distribusi form.""" """Admin Distribusi form."""
delete = SubmitField("Delete") delete = SubmitField("Delete")
def distribusi_list_form_builder(distribusis): def distribusi_list_form_builder(distribusis):
class DistribusiListForm(AdminDistribusiForm): class DistribusiListForm(AdminDistribusiForm):
pass pass
for i, distribusi in enumerate(distribusis): for i, distribusi in enumerate(distribusis):
setattr( setattr(
DistribusiListForm, DistribusiListForm,
f"distribusi_{i}", f"distribusi_{i}",
BooleanField(label=distribusi.distribusiname), BooleanField(label=distribusi.distribusiname),
) )
return DistribusiListForm() return DistribusiListForm()

24
verse/forms/adminuserform.py

@ -5,19 +5,19 @@ from wtforms import BooleanField, SubmitField
class AdminUserForm(FlaskForm): class AdminUserForm(FlaskForm):
"""Admin Userform form.""" """Admin Userform form."""
def user_list_form_builder(users): def user_list_form_builder(users):
class UserListForm(AdminUserForm): class UserListForm(AdminUserForm):
pass pass
for i, user in enumerate(users): for i, user in enumerate(users):
setattr( setattr(
UserListForm, UserListForm,
f"user_{i}", f"user_{i}",
BooleanField(label=user.email), BooleanField(label=user.email),
) )
return UserListForm() return UserListForm()
delete = SubmitField("Delete") delete = SubmitField("Delete")

4
verse/forms/distribusiform.py

@ -3,6 +3,6 @@ from wtforms import SubmitField
class DistribusiForm(FlaskForm): class DistribusiForm(FlaskForm):
"""Distribusi class to launch your distribusi website""" """Distribusi class to launch your distribusi website"""
submit = SubmitField("Distribusi!") submit = SubmitField("Distribusi!")

46
verse/forms/editorform.py

@ -3,33 +3,33 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed, FileField, FileSize from flask_wtf.file import FileAllowed, FileField, FileSize
from wtforms import ( from wtforms import (
BooleanField, BooleanField,
StringField, StringField,
SubmitField, SubmitField,
TextAreaField, TextAreaField,
validators, validators,
) )
from wtforms.validators import Length from wtforms.validators import Length
class EditorForm(FlaskForm): class EditorForm(FlaskForm):
"""Css editor form class.""" """Css editor form class."""
cssname = StringField( cssname = StringField(
"fill in a name for your css style:", "fill in a name for your css style:",
validators=[validators.InputRequired(), Length(5, 200)], validators=[validators.InputRequired(), Length(5, 200)],
) )
cssfile = FileField( cssfile = FileField(
"(Optional) upload your own css file:", "(Optional) upload your own css file:",
validators=[ validators=[
FileAllowed(["css"], "css files only!"), FileAllowed(["css"], "css files only!"),
FileSize( FileSize(
max_size=10485760, max_size=10485760,
message="css file size must be smaller than 10MB", message="css file size must be smaller than 10MB",
), ),
], ],
) )
css = TextAreaField() css = TextAreaField()
public = BooleanField("Make your CSS public so others can use it") public = BooleanField("Make your CSS public so others can use it")
submit = SubmitField("Save") submit = SubmitField("Save")

12
verse/forms/forgotpasswordform.py

@ -6,10 +6,10 @@ from wtforms.validators import Email, Length
class ForgotPasswordForm(FlaskForm): class ForgotPasswordForm(FlaskForm):
"""Forgotten password distribusiverse form class.""" """Forgotten password distribusiverse form class."""
email = StringField( email = StringField(
"Email address:", "Email address:",
validators=[validators.InputRequired(), Email(), Length(6, 64)], validators=[validators.InputRequired(), Email(), Length(6, 64)],
) )
submit = SubmitField("Send email") submit = SubmitField("Send email")

18
verse/forms/loginform.py

@ -6,13 +6,13 @@ from wtforms.validators import Email, Length
class LoginForm(FlaskForm): class LoginForm(FlaskForm):
"""Login distribusiverse form class.""" """Login distribusiverse form class."""
email = StringField( email = StringField(
"Email address:", "Email address:",
validators=[validators.InputRequired(), Email(), Length(6, 64)], validators=[validators.InputRequired(), Email(), Length(6, 64)],
) )
password = PasswordField( password = PasswordField(
"Password:", validators=[validators.InputRequired()] "Password:", validators=[validators.InputRequired()]
) )
submit = SubmitField("Sign In") submit = SubmitField("Sign In")

10
verse/forms/publicthemeform.py

@ -5,10 +5,10 @@ from wtforms import RadioField, SubmitField
class PublicThemeForm(FlaskForm): class PublicThemeForm(FlaskForm):
"""PublicTheme selection form.""" """PublicTheme selection form."""
publicthemes = RadioField( publicthemes = RadioField(
"Public themes from other distribusi-verse users:" "Public themes from other distribusi-verse users:"
) )
save = SubmitField("Save") save = SubmitField("Save")

52
verse/forms/registerform.py

@ -6,33 +6,33 @@ from wtforms.validators import Email, EqualTo, Length
class RegisterForm(FlaskForm): class RegisterForm(FlaskForm):
"""Register for distribusi-verse form class""" """Register for distribusi-verse form class"""
username = StringField( username = StringField(
"Username:", "Username:",
validators=[validators.InputRequired(), Length(3, 150)], validators=[validators.InputRequired(), Length(3, 150)],
) )
email = StringField( email = StringField(
"Email address:", "Email address:",
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Email(), Email(),
Length(6, 128), Length(6, 128),
], ],
) )
password = PasswordField( password = PasswordField(
"New password:", "New password:",
validators=[validators.InputRequired(), Length(12, 72)], validators=[validators.InputRequired(), Length(12, 72)],
) )
confirmpassword = PasswordField( confirmpassword = PasswordField(
"Confirm your password:", "Confirm your password:",
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Length(12, 72), Length(12, 72),
EqualTo("password", message="Passwords must match !"), EqualTo("password", message="Passwords must match !"),
], ],
) )
submit = SubmitField("Register to Distribusi-verse") submit = SubmitField("Register to Distribusi-verse")

28
verse/forms/resetpasswordform.py

@ -6,18 +6,18 @@ from wtforms.validators import EqualTo, Length
class ResetPasswordForm(FlaskForm): class ResetPasswordForm(FlaskForm):
"""ResetPassword for distribusi-verse form class""" """ResetPassword for distribusi-verse form class"""
password = PasswordField( password = PasswordField(
"New password:", "New password:",
validators=[validators.InputRequired(), Length(12, 72)], validators=[validators.InputRequired(), Length(12, 72)],
) )
confirmpassword = PasswordField( confirmpassword = PasswordField(
"Confirm your password:", "Confirm your password:",
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Length(12, 72), Length(12, 72),
EqualTo("password", message="Passwords must match !"), EqualTo("password", message="Passwords must match !"),
], ],
) )
submit = SubmitField("Reset your password") submit = SubmitField("Reset your password")

10
verse/forms/selectorform.py

@ -3,12 +3,12 @@ from wtforms import SelectField, SubmitField
class SelectorForm(FlaskForm): class SelectorForm(FlaskForm):
distribusis = SelectField("Your existing distribusi:") distribusis = SelectField("Your existing distribusi:")
new = SubmitField("new") new = SubmitField("new")
update = SubmitField("update") update = SubmitField("update")
describe = SubmitField("describe") describe = SubmitField("describe")
delete = SubmitField("delete") delete = SubmitField("delete")

20
verse/forms/themeform.py

@ -5,15 +5,15 @@ from wtforms import RadioField, SubmitField
class ThemeForm(FlaskForm): class ThemeForm(FlaskForm):
"""Basic theme selection form.""" """Basic theme selection form."""
theme = RadioField( theme = RadioField(
"Select your theme:", "Select your theme:",
choices=[ choices=[
("hacking", "Hackers (black background, green text)"), ("hacking", "Hackers (black background, green text)"),
("peachsunset", "Peach sunset (single column)"), ("peachsunset", "Peach sunset (single column)"),
("masonry", "Masonry (white background, grid layout)"), ("masonry", "Masonry (white background, grid layout)"),
], ],
) )
save = SubmitField("Save") save = SubmitField("Save")

134
verse/forms/uploadform.py

@ -1,85 +1,85 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed, FileField, FileRequired, FileSize from flask_wtf.file import FileAllowed, FileField, FileRequired, FileSize
from wtforms import ( from wtforms import (
SelectField, SelectField,
StringField, StringField,
SubmitField, SubmitField,
validators, validators,
) )
from wtforms.validators import ( from wtforms.validators import (
DataRequired, DataRequired,
Length, Length,
ValidationError, ValidationError,
) )
from app import settings from app import settings
class UploadForm(FlaskForm): class UploadForm(FlaskForm):
"""File upload class for a new site in distribusi-verse""" """File upload class for a new site in distribusi-verse"""
def distribusiname(form, field): def distribusiname(form, field):
if field.data.lower() == "new": if field.data.lower() == "new":
raise ValidationError("Name has to be unique and not just new.") raise ValidationError("Name has to be unique and not just new.")
def category_choices(): def category_choices():
APP = settings() APP = settings()
config_categories = APP.config["categories"] config_categories = APP.config["categories"]
categories = [] categories = []
for config_category in config_categories: for config_category in config_categories:
categories.append((config_category, config_category)) categories.append((config_category, config_category))
return categories return categories
def year_choices(): def year_choices():
APP = settings() APP = settings()
start_time = APP.config["start_time"] start_time = APP.config["start_time"]
end_time = APP.config["end_time"] end_time = APP.config["end_time"]
year_range = range(start_time.year, end_time.year, 1) year_range = range(start_time.year, end_time.year, 1)
year_choices = [] year_choices = []
for year in year_range: for year in year_range:
year_choices.append((str(year), str(year))) year_choices.append((str(year), str(year)))
return year_choices return year_choices
sitename = StringField( sitename = StringField(
"Name of your archive section:", "Name of your archive section:",
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Length(2, 100), Length(2, 100),
distribusiname, distribusiname,
], ],
) )
year = SelectField( year = SelectField(
"Year:", "Year:",
validate_choice=True, validate_choice=True,
coerce=str, coerce=str,
choices=year_choices, choices=year_choices,
option_widget=None, option_widget=None,
validators=[DataRequired()], validators=[DataRequired()],
) )
category = SelectField( category = SelectField(
"Category:", "Category:",
validate_choice=True, validate_choice=True,
coerce=str, coerce=str,
choices=category_choices, choices=category_choices,
option_widget=None, option_widget=None,
validators=[DataRequired()], validators=[DataRequired()],
) )
tags = StringField( tags = StringField(
"Add search tags, seperated by commas. No need for the '#' sign:", "Add search tags, seperated by commas. No need for the '#' sign:",
validators=[validators.InputRequired(), Length(3, 500)], validators=[validators.InputRequired(), Length(3, 500)],
) )
zipfile = FileField( zipfile = FileField(
"Upload your zip file with content here:", "Upload your zip file with content here:",
validators=[ validators=[
FileAllowed(["zip"], "Zip archives only!"), FileAllowed(["zip"], "Zip archives only!"),
FileRequired(), FileRequired(),
FileSize( FileSize(
max_size=1073741824, max_size=1073741824,
message="Zipfile size must be smaller than 100MB", message="Zipfile size must be smaller than 100MB",
), ),
], ],
) )
submit = SubmitField("Upload") submit = SubmitField("Upload")

90
verse/migrations/env.py

@ -14,17 +14,19 @@ config = context.config
# Interpret the config file for Python logging. # Interpret the config file for Python logging.
# This line sets up loggers basically. # This line sets up loggers basically.
fileConfig(config.config_file_name) fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env') logger = logging.getLogger("alembic.env")
# add your model's MetaData object here # add your model's MetaData object here
# for 'autogenerate' support # for 'autogenerate' support
# from myapp import mymodel # from myapp import mymodel
# target_metadata = mymodel.Base.metadata # target_metadata = mymodel.Base.metadata
config.set_main_option( config.set_main_option(
'sqlalchemy.url', "sqlalchemy.url",
str(current_app.extensions['migrate'].db.get_engine().url).replace( str(current_app.extensions["migrate"].db.get_engine().url).replace(
'%', '%%')) "%", "%%"
target_metadata = current_app.extensions['migrate'].db.metadata ),
)
target_metadata = current_app.extensions["migrate"].db.metadata
# other values from the config, defined by the needs of env.py, # other values from the config, defined by the needs of env.py,
# can be acquired: # can be acquired:
@ -33,59 +35,59 @@ target_metadata = current_app.extensions['migrate'].db.metadata
def run_migrations_offline(): def run_migrations_offline():
"""Run migrations in 'offline' mode. """Run migrations in 'offline' mode.
This configures the context with just a URL This configures the context with just a URL
and not an Engine, though an Engine is acceptable and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation here as well. By skipping the Engine creation
we don't even need a DBAPI to be available. we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the Calls to context.execute() here emit the given string to the
script output. script output.
""" """
url = config.get_main_option("sqlalchemy.url") url = config.get_main_option("sqlalchemy.url")
context.configure( context.configure(
url=url, target_metadata=target_metadata, literal_binds=True url=url, target_metadata=target_metadata, literal_binds=True
) )
with context.begin_transaction(): with context.begin_transaction():
context.run_migrations() context.run_migrations()
def run_migrations_online(): def run_migrations_online():
"""Run migrations in 'online' mode. """Run migrations in 'online' mode.
In this scenario we need to create an Engine In this scenario we need to create an Engine
and associate a connection with the context. and associate a connection with the context.
""" """
# this callback is used to prevent an auto-migration from being generated # this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema # when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives): def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False): if getattr(config.cmd_opts, "autogenerate", False):
script = directives[0] script = directives[0]
if script.upgrade_ops.is_empty(): if script.upgrade_ops.is_empty():
directives[:] = [] directives[:] = []
logger.info('No changes in schema detected.') logger.info("No changes in schema detected.")
connectable = current_app.extensions['migrate'].db.get_engine() connectable = current_app.extensions["migrate"].db.get_engine()
with connectable.connect() as connection: with connectable.connect() as connection:
context.configure( context.configure(
connection=connection, connection=connection,
target_metadata=target_metadata, target_metadata=target_metadata,
process_revision_directives=process_revision_directives, process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args **current_app.extensions["migrate"].configure_args,
) )
with context.begin_transaction(): with context.begin_transaction():
context.run_migrations() context.run_migrations()
if context.is_offline_mode(): if context.is_offline_mode():
run_migrations_offline() run_migrations_offline()
else: else:
run_migrations_online() run_migrations_online()

22
verse/models/distribusi_file_model.py

@ -2,17 +2,17 @@ from app import db
class DistribusiFiles(db.Model): class DistribusiFiles(db.Model):
"""Distribusi file model class for a single file in a distribusi""" """Distribusi file model class for a single file in a distribusi"""
__tablename__ = "distribusi_files" __tablename__ = "distribusi_files"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
type = db.Column(db.String(100), nullable=True, unique=False) type = db.Column(db.String(100), nullable=True, unique=False)
distribusi = db.Column(db.Integer, db.ForeignKey("distribusis.id")) distribusi = db.Column(db.Integer, db.ForeignKey("distribusis.id"))
path = db.Column(db.String(4096), nullable=True, unique=False) path = db.Column(db.String(4096), nullable=True, unique=False)
alttext = db.Column(db.String(255), nullable=True, unique=False) alttext = db.Column(db.String(255), nullable=True, unique=False)
tags = db.Column(db.String(500), nullable=True, unique=False) tags = db.Column(db.String(500), nullable=True, unique=False)
description = db.Column(db.String(4096), nullable=True, unique=False) description = db.Column(db.String(4096), nullable=True, unique=False)
def __repr__(self): def __repr__(self):
return "<Distribusi_File %r>" % self.path return "<Distribusi_File %r>" % self.path

24
verse/models/distribusi_model.py

@ -2,18 +2,18 @@ from app import db
class Distribusis(db.Model): class Distribusis(db.Model):
"""distribusi model class for a single distribusi in distribusi-verse""" """distribusi model class for a single distribusi in distribusi-verse"""
__tablename__ = "distribusis" __tablename__ = "distribusis"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
distribusiname = db.Column(db.String(300), nullable=False, unique=True) distribusiname = db.Column(db.String(300), nullable=False, unique=True)
userid = db.Column(db.Integer, db.ForeignKey("users.id")) userid = db.Column(db.Integer, db.ForeignKey("users.id"))
category = db.Column(db.String(500), nullable=True, unique=False) category = db.Column(db.String(500), nullable=True, unique=False)
year = db.Column(db.String(9), nullable=True, unique=False) year = db.Column(db.String(9), nullable=True, unique=False)
tags = db.Column(db.String(500), nullable=True, unique=False) tags = db.Column(db.String(500), nullable=True, unique=False)
publictheme = db.Column(db.String(300), unique=True, nullable=True) publictheme = db.Column(db.String(300), unique=True, nullable=True)
visible = db.Column(db.Boolean, default=False) visible = db.Column(db.Boolean, default=False)
def __repr__(self): def __repr__(self):
return "<Distribusi %r>" % self.distribusiname return "<Distribusi %r>" % self.distribusiname

24
verse/models/user_model.py

@ -4,18 +4,18 @@ from app import db
class User(UserMixin, db.Model): class User(UserMixin, db.Model):
"""User model class for a user in distribusi-verse""" """User model class for a user in distribusi-verse"""
__tablename__ = "users" __tablename__ = "users"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), unique=True, nullable=False) username = db.Column(db.String(150), unique=True, nullable=False)
email = db.Column(db.String(150), unique=True, nullable=False) email = db.Column(db.String(150), unique=True, nullable=False)
password = db.Column(db.String(300), nullable=False, unique=False) password = db.Column(db.String(300), nullable=False, unique=False)
currentdistribusi = db.Column(db.String(300), nullable=True, unique=False) currentdistribusi = db.Column(db.String(300), nullable=True, unique=False)
resethash = db.Column(db.String(300), nullable=True, unique=True) resethash = db.Column(db.String(300), nullable=True, unique=True)
resettime = db.Column(db.DateTime) resettime = db.Column(db.DateTime)
admin = db.Column(db.Boolean, default=False) admin = db.Column(db.Boolean, default=False)
def __repr__(self): def __repr__(self):
return "<User %r>" % self.email return "<User %r>" % self.email

105
verse/start.py

@ -2,8 +2,14 @@
from datetime import timedelta from datetime import timedelta
from flask import (Blueprint, redirect, render_template, send_from_directory, from flask import (
session, url_for) Blueprint,
redirect,
render_template,
send_from_directory,
session,
url_for,
)
from flask_login import current_user, login_required, logout_user from flask_login import current_user, login_required, logout_user
from flask_wtf.csrf import CSRFError from flask_wtf.csrf import CSRFError
@ -31,92 +37,91 @@ APP.register_blueprint(forgot_password, url_prefix="/login/forgotpassword")
APP.register_blueprint(distribusikan) APP.register_blueprint(distribusikan)
@APP.before_request @APP.before_request
def session_handler(): def session_handler():
session.permanent = True session.permanent = True
APP.permanent_session_lifetime = timedelta(minutes=30) APP.permanent_session_lifetime = timedelta(minutes=30)
@APP.route("/") @APP.route("/")
def index(): def index():
UserHelper.reset_user_state() UserHelper.reset_user_state()
uploadform = UploadForm() uploadform = UploadForm()
distribusis = DistribusisInfo.visibledistribusis() distribusis = DistribusisInfo.visibledistribusis()
distribusisindex = {} distribusisindex = {}
for distribusi in distribusis: for distribusi in distribusis:
user = User.query.filter_by(id=distribusi.userid).first() user = User.query.filter_by(id=distribusi.userid).first()
singledistribusi = { singledistribusi = {
"username": user.username, "username": user.username,
"publictheme": distribusi.publictheme, "publictheme": distribusi.publictheme,
"category": distribusi.category, "category": distribusi.category,
"year": distribusi.year, "year": distribusi.year,
"tags": distribusi.tags.split(","), "tags": distribusi.tags.split(","),
} }
distribusisindex[distribusi.distribusiname] = singledistribusi distribusisindex[distribusi.distribusiname] = singledistribusi
years = uploadform.year.choices years = uploadform.year.choices
categories = uploadform.category.choices categories = uploadform.category.choices
adminuser = isadminuser() adminuser = is_adminuser()
template = render_template( template = render_template(
"base/index.html", "base/index.html",
distribusisindex=distribusisindex, distribusisindex=distribusisindex,
years=years, years=years,
categories=categories, categories=categories,
adminuser=adminuser, adminuser=adminuser,
) )
return template return template
@APP.route("/help") @APP.route("/help")
def help(): def help():
return render_template("base/help.html") return render_template("base/help.html")
@APP.route("/publicthemes/<path>") @APP.route("/publicthemes/<path>")
def publicthemes(path): def publicthemes(path):
distribusi = Distribusis.query.filter_by(distribusiname=path).first() distribusi = Distribusis.query.filter_by(distribusiname=path).first()
publicthemefolder = f"publicthemes/{distribusi.distribusiname}/" publicthemefolder = f"publicthemes/{distribusi.distribusiname}/"
cssfile = f"{publicthemefolder}/{distribusi.publictheme}.css" cssfile = f"{publicthemefolder}/{distribusi.publictheme}.css"
return send_from_directory("themes", cssfile, as_attachment=True) return send_from_directory("themes", cssfile, as_attachment=True)
@APP.route("/stash") @APP.route("/stash")
def shortstashurl(): def shortstashurl():
return redirect(url_for("index")) return redirect(url_for("index"))
@APP.route("/admin", methods=["GET", "POST"]) @APP.route("/admin", methods=["GET", "POST"])
@login_required @login_required
def admin(): def admin():
if not isadminuser(): if not is_adminuser():
return redirect(url_for("index")) return redirect(url_for("index"))
return AdminPage() return AdminPage()
@APP.route("/logout") @APP.route("/logout")
@login_required @login_required
def logout(): def logout():
logout_user() logout_user()
return redirect(url_for("index")) return redirect(url_for("index"))
@APP.errorhandler(CSRFError) @APP.errorhandler(CSRFError)
def handle_csrf_error(e): def handle_csrf_error(e):
return render_template("csrf_error.html", reason=e.description), 400 return render_template("csrf_error.html", reason=e.description), 400
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): def load_user(user_id):
return User.query.get(int(user_id)) return User.query.get(int(user_id))
def isadminuser(): def is_adminuser():
if not current_user.is_authenticated: if not current_user.is_authenticated:
return False return False
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
return user.admin return user.admin
if __name__ == "__main__": if __name__ == "__main__":
APP.debug = True APP.debug = True
APP.run(port=5000) APP.run(port=5000)

78
verse/statuspengguna/forgotpassword.py

@ -4,10 +4,10 @@ from uuid import uuid1
from flask import Blueprint, render_template from flask import Blueprint, render_template
from flask_mail import Mail, Message from flask_mail import Mail, Message
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db, get_app from app import db, get_app
@ -16,57 +16,57 @@ from models.user_model import User
mail = Mail(get_app()) mail = Mail(get_app())
forgot_password = Blueprint( forgot_password = Blueprint(
"forgotpassword", "forgotpassword",
__name__, __name__,
template_folder="templates/statuspengguna", template_folder="templates/statuspengguna",
static_folder="static", static_folder="static",
) )
@forgot_password.route("/", methods=["GET", "POST"]) @forgot_password.route("/", methods=["GET", "POST"])
def forgotpassword(): def forgotpassword():
return ForgotPassword(mail) return ForgotPassword(mail)
def ForgotPassword(mail): def ForgotPassword(mail):
forgotpasswordform = ForgotPasswordForm() forgotpasswordform = ForgotPasswordForm()
if forgotpasswordform.validate_on_submit(): if forgotpasswordform.validate_on_submit():
user = User.query.filter_by( user = User.query.filter_by(
email=forgotpasswordform.email.data email=forgotpasswordform.email.data
).first() ).first()
if user is not None: if user is not None:
resethash = AddResetPasswordHash(user, forgotpasswordform) resethash = AddResetPasswordHash(user, forgotpasswordform)
ResetPassWordMessage(user, resethash, mail) ResetPassWordMessage(user, resethash, mail)
forgotpasswordform.email.errors.append( forgotpasswordform.email.errors.append(
f"""If {forgotpasswordform.email.data} exists, an email is send with f"""If {forgotpasswordform.email.data} exists, an email is send with
a password reset link. (If your inbox doesn't a password reset link. (If your inbox doesn't
contain any new mail, please check your spam folder.)""" contain any new mail, please check your spam folder.)"""
) )
return render_template( return render_template(
"forgotpassword.html", forgotpasswordform=forgotpasswordform "forgotpassword.html", forgotpasswordform=forgotpasswordform
) )
def AddResetPasswordHash(user, forgotpasswordform): def AddResetPasswordHash(user, forgotpasswordform):
resethash = uuid1().hex resethash = uuid1().hex
try: try:
user.resettime = datetime.now() user.resettime = datetime.now()
user.resethash = resethash user.resethash = resethash
db.session.commit() db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
forgotpasswordform.email.errors.append("Something went wrong!") forgotpasswordform.email.errors.append("Something went wrong!")
db.session.rollback() db.session.rollback()
return resethash return resethash
def ResetPassWordMessage(user, resethash, mail): def ResetPassWordMessage(user, resethash, mail):
msg = Message( msg = Message(
"Distribusiverse Forgotten Password ", "Distribusiverse Forgotten Password ",
sender=("Distribusiverse mailer", "test@this.com"), sender=("Distribusiverse mailer", "test@this.com"),
recipients=[user.email], recipients=[user.email],
) )
msg.html = f"""{user.username} has requested a password reset for msg.html = f"""{user.username} has requested a password reset for
Distribusiverse.<br><hr> Distribusiverse.<br><hr>
<a href='http://localhost:5000/resetpassword/{resethash}'>Click here to <a href='http://localhost:5000/resetpassword/{resethash}'>Click here to
reset your password.</a>""" reset your password.</a>"""
mail.send(msg) mail.send(msg)

126
verse/statuspengguna/helper.py

@ -3,10 +3,10 @@ import os
from flask import flash from flask import flash
from flask_login import current_user from flask_login import current_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db from app import db
@ -16,68 +16,68 @@ from models.user_model import User
class UserHelper: class UserHelper:
def is_zip_uploaded(distribusiname): def is_zip_uploaded(distribusiname):
userfolder = os.path.join("stash", distribusiname) userfolder = os.path.join("stash", distribusiname)
if os.path.exists(userfolder): if os.path.exists(userfolder):
zipfilename = "{}.zip".format(distribusiname) zipfilename = "{}.zip".format(distribusiname)
if os.path.exists(os.path.join(userfolder, zipfilename)): if os.path.exists(os.path.join(userfolder, zipfilename)):
print("folder with zipfile found, file uploaded") print("folder with zipfile found, file uploaded")
return True return True
print("distribusi folder has no zipfile") print("distribusi folder has no zipfile")
return False return False
def is_distribusi_live(distribusiname): def is_distribusi_live(distribusiname):
userfolder = os.path.join("stash", distribusiname) userfolder = os.path.join("stash", distribusiname)
if os.path.exists(userfolder): if os.path.exists(userfolder):
zipfilename = "{}.zip".format(distribusiname) zipfilename = "{}.zip".format(distribusiname)
if os.path.exists(os.path.join(userfolder, zipfilename)): if os.path.exists(os.path.join(userfolder, zipfilename)):
print("folder with zipfile found, file uploaded") print("folder with zipfile found, file uploaded")
return False return False
if len(os.listdir(userfolder)) > 0: if len(os.listdir(userfolder)) > 0:
return True return True
print("distribusi folder is empty") print("distribusi folder is empty")
return False return False
def is_css_selected(distribusiname): def is_css_selected(distribusiname):
userfolder = os.path.join("themes/userthemes", distribusiname) userfolder = os.path.join("themes/userthemes", distribusiname)
if os.path.exists(userfolder): if os.path.exists(userfolder):
for file in os.listdir(userfolder): for file in os.listdir(userfolder):
if file.endswith(".css"): if file.endswith(".css"):
return True return True
print("distribusi folder has no css file") print("distribusi folder has no css file")
return False return False
def has_distribusi(): def has_distribusi():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
distribusi = Distribusis.query.filter_by(userid=user.id).first() distribusi = Distribusis.query.filter_by(userid=user.id).first()
if distribusi is None: if distribusi is None:
print("no distribusi found") print("no distribusi found")
return False return False
return True return True
def current_distribusi(): def current_distribusi():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
if user.currentdistribusi is None: if user.currentdistribusi is None:
return "None" return "None"
return user.currentdistribusi return user.currentdistribusi
def reset_user_state(): def reset_user_state():
"""reset user state upon visiting index, so that distribusi workflow can """reset user state upon visiting index, so that distribusi workflow can
be done correctly""" be done correctly"""
if not current_user.is_authenticated: if not current_user.is_authenticated:
return return
try: try:
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
user.currentdistribusi = None user.currentdistribusi = None
db.session.commit() db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError): except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
db.session.rollback() db.session.rollback()
flash("An error occured !", "danger") flash("An error occured !", "danger")
def distribusi_limit_reached(): def distribusi_limit_reached():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
distribusiamount = len(DistribusisInfo.getuserdistribusis(user.email)) distribusiamount = len(DistribusisInfo.getuserdistribusis(user.email))
if distribusiamount > 19: if distribusiamount > 19:
print("user already has 20 distribusis") print("user already has 20 distribusis")
return True return True
return False return False

70
verse/statuspengguna/loginuser.py

@ -1,11 +1,11 @@
from flask import ( from flask import (
Blueprint, Blueprint,
abort, abort,
flash, flash,
redirect, redirect,
render_template, render_template,
request, request,
url_for, url_for,
) )
from flask_bcrypt import check_password_hash from flask_bcrypt import check_password_hash
from flask_login import login_user from flask_login import login_user
@ -14,39 +14,39 @@ from forms.loginform import LoginForm
from models.user_model import User from models.user_model import User
login_section = Blueprint( login_section = Blueprint(
"login", "login",
__name__, __name__,
template_folder="templates/statuspengguna", template_folder="templates/statuspengguna",
static_folder="static", static_folder="static",
) )
@login_section.route("/", methods=["GET", "POST"]) @login_section.route("/", methods=["GET", "POST"])
def login(): def login():
return LoginUser() return LoginUser()
def LoginUser(): def LoginUser():
loginform = LoginForm() loginform = LoginForm()
if loginform.validate_on_submit(): if loginform.validate_on_submit():
try: try:
user = User.query.filter_by(email=loginform.email.data).first() user = User.query.filter_by(email=loginform.email.data).first()
if user is None: if user is None:
loginform.password.errors.append("Invalid email or password!") loginform.password.errors.append("Invalid email or password!")
return render_template("login.html", loginform=loginform) return render_template("login.html", loginform=loginform)
if check_password_hash(user.password, loginform.password.data): if check_password_hash(user.password, loginform.password.data):
login_user(user) login_user(user)
flash("Logged in successfully.", "success") flash("Logged in successfully.", "success")
next = request.args.get("next") next = request.args.get("next")
if next is not None and not is_safe_url(next): # noqa: F821 if next is not None and not is_safe_url(next): # noqa: F821
print(next) print(next)
return abort(400) return abort(400)
print("index") print("index")
return redirect(next or url_for("index")) return redirect(next or url_for("index"))
else: else:
flash("Invalid email or password!", "danger") flash("Invalid email or password!", "danger")
loginform.password.errors.append("Invalid email or password!") loginform.password.errors.append("Invalid email or password!")
return render_template("login.html", loginform=loginform) return render_template("login.html", loginform=loginform)
except Exception as e: except Exception as e:
flash(e, "danger") flash(e, "danger")
return render_template("login.html", loginform=loginform) return render_template("login.html", loginform=loginform)

110
verse/statuspengguna/registeruser.py

@ -2,11 +2,11 @@ from flask import Blueprint, flash, redirect, render_template, url_for
from flask_bcrypt import generate_password_hash from flask_bcrypt import generate_password_hash
from flask_login import login_user from flask_login import login_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
IntegrityError, IntegrityError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from werkzeug.routing import BuildError from werkzeug.routing import BuildError
@ -15,64 +15,64 @@ from forms.registerform import RegisterForm
from models.user_model import User from models.user_model import User
register_user = Blueprint( register_user = Blueprint(
"register", "register",
__name__, __name__,
template_folder="templates/statuspengguna", template_folder="templates/statuspengguna",
static_folder="static", static_folder="static",
) )
@register_user.route("/", methods=["GET", "POST"]) @register_user.route("/", methods=["GET", "POST"])
def register(): def register():
return RegisterUser() return RegisterUser()
def RegisterUser(): def RegisterUser():
registerform = RegisterForm() registerform = RegisterForm()
if registerform.validate_on_submit(): if registerform.validate_on_submit():
try: try:
username = registerform.username.data username = registerform.username.data
email = registerform.email.data email = registerform.email.data
password = registerform.confirmpassword.data password = registerform.confirmpassword.data
newuser = User( newuser = User(
username=username, username=username,
email=email, email=email,
password=generate_password_hash(password), password=generate_password_hash(password),
) )
db.session.add(newuser) db.session.add(newuser)
db.session.commit() db.session.commit()
flash("Account Succesfully created", "success") flash("Account Succesfully created", "success")
login_user(newuser) login_user(newuser)
return redirect(url_for("index")) return redirect(url_for("index"))
except InvalidRequestError: except InvalidRequestError:
db.session.rollback() db.session.rollback()
registerform.email.errors.append("Something went wrong!") registerform.email.errors.append("Something went wrong!")
flash("Something went wrong!", "danger") flash("Something went wrong!", "danger")
except IntegrityError: except IntegrityError:
db.session.rollback() db.session.rollback()
registerform.email.errors.append("User already exists!") registerform.email.errors.append("User already exists!")
flash("User already exists!", "warning") flash("User already exists!", "warning")
except DataError: except DataError:
db.session.rollback() db.session.rollback()
registerform.email.errors.append("Invalid Entry") registerform.email.errors.append("Invalid Entry")
flash("Invalid Entry", "warning") flash("Invalid Entry", "warning")
except InterfaceError: except InterfaceError:
db.session.rollback() db.session.rollback()
registerform.email.errors.append( registerform.email.errors.append(
"Error connecting to the database" "Error connecting to the database"
) )
flash("Error connecting to the database", "danger") flash("Error connecting to the database", "danger")
except DatabaseError: except DatabaseError:
db.session.rollback() db.session.rollback()
registerform.email.errors.append( registerform.email.errors.append(
"Error connecting to the database" "Error connecting to the database"
) )
flash("Error connecting to the database", "danger") flash("Error connecting to the database", "danger")
except BuildError: except BuildError:
db.session.rollback() db.session.rollback()
registerform.email.errors.append("Unknown error occured!") registerform.email.errors.append("Unknown error occured!")
flash("An error occured !", "danger") flash("An error occured !", "danger")
return render_template("register.html", registerform=registerform) return render_template("register.html", registerform=registerform)

126
verse/statuspengguna/resetpassword.py

@ -4,11 +4,11 @@ from flask import Blueprint, flash, redirect, render_template, url_for
from flask_bcrypt import generate_password_hash from flask_bcrypt import generate_password_hash
from flask_login import login_user from flask_login import login_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
IntegrityError, IntegrityError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from werkzeug.routing import BuildError from werkzeug.routing import BuildError
@ -17,74 +17,74 @@ from forms.resetpasswordform import ResetPasswordForm
from models.user_model import User from models.user_model import User
reset_password = Blueprint( reset_password = Blueprint(
"reset_password", "reset_password",
__name__, __name__,
template_folder="templates/statuspengguna", template_folder="templates/statuspengguna",
static_folder="static", static_folder="static",
) )
@reset_password.route("/resetpassword/<path>", methods=["GET", "POST"]) @reset_password.route("/resetpassword/<path>", methods=["GET", "POST"])
def resetpassword(path): def resetpassword(path):
return ResetPassword(path) return ResetPassword(path)
def ResetPassword(path): def ResetPassword(path):
linkvalid = False linkvalid = False
user = User.query.filter_by(resethash=path).first() user = User.query.filter_by(resethash=path).first()
if user is None: if user is None:
return redirect(url_for("index")) return redirect(url_for("index"))
timepassed = datetime.now() - user.resettime timepassed = datetime.now() - user.resettime
if timepassed.days < 1: if timepassed.days < 1:
linkvalid = True linkvalid = True
resetpasswordform = ResetPasswordForm() resetpasswordform = ResetPasswordForm()
if resetpasswordform.validate_on_submit(): if resetpasswordform.validate_on_submit():
return ResetUserPasswordInDB(user, resetpasswordform) return ResetUserPasswordInDB(user, resetpasswordform)
return render_template( return render_template(
"resetpassword.html", "resetpassword.html",
resetpasswordform=resetpasswordform, resetpasswordform=resetpasswordform,
path=path, path=path,
linkvalid=linkvalid, linkvalid=linkvalid,
) )
def ResetUserPasswordInDB(user, resetpasswordform): def ResetUserPasswordInDB(user, resetpasswordform):
try: try:
newpassword = resetpasswordform.confirmpassword.data newpassword = resetpasswordform.confirmpassword.data
user.password = generate_password_hash(newpassword) user.password = generate_password_hash(newpassword)
user.resethash = None user.resethash = None
user.resettime = None user.resettime = None
db.session.commit() db.session.commit()
flash("Password Succesfully updated", "success") flash("Password Succesfully updated", "success")
login_user(user) login_user(user)
return redirect(url_for("index")) return redirect(url_for("index"))
except InvalidRequestError: except InvalidRequestError:
db.session.rollback() db.session.rollback()
resetpasswordform.email.errors.append("Something went wrong!") resetpasswordform.email.errors.append("Something went wrong!")
flash("Something went wrong!", "danger") flash("Something went wrong!", "danger")
except IntegrityError: except IntegrityError:
db.session.rollback() db.session.rollback()
resetpasswordform.email.errors.append("User already exists!") resetpasswordform.email.errors.append("User already exists!")
flash("User already exists!", "warning") flash("User already exists!", "warning")
except DataError: except DataError:
db.session.rollback() db.session.rollback()
resetpasswordform.email.errors.append("Invalid Entry") resetpasswordform.email.errors.append("Invalid Entry")
flash("Invalid Entry", "warning") flash("Invalid Entry", "warning")
except InterfaceError: except InterfaceError:
db.session.rollback() db.session.rollback()
resetpasswordform.email.errors.append( resetpasswordform.email.errors.append(
"Error connecting to the database" "Error connecting to the database"
) )
flash("Error connecting to the database", "danger") flash("Error connecting to the database", "danger")
except DatabaseError: except DatabaseError:
db.session.rollback() db.session.rollback()
resetpasswordform.email.errors.append( resetpasswordform.email.errors.append(
"Error connecting to the database" "Error connecting to the database"
) )
flash("Error connecting to the database", "danger") flash("Error connecting to the database", "danger")
except BuildError: except BuildError:
db.session.rollback() db.session.rollback()
resetpasswordform.email.errors.append("Unknown error occured!") resetpasswordform.email.errors.append("Unknown error occured!")
flash("An error occured !", "danger") flash("An error occured !", "danger")

Loading…
Cancel
Save