diff --git a/.gitignore b/.gitignore index 705c21e..f273bbd 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,12 @@ *.pyc *.egg-info/ .eggs/ +.ruff_cache build/ dist/ pip-wheel-metadata/ verse/tmpupload/* verse/stash/* +verse/search/searchdata/* *.db diff --git a/pyproject.toml b/pyproject.toml index 9b286c9..665a9ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,25 +1,49 @@ -[tool.black] +[tool.ruff] line-length = 79 -target-version = ['py311'] -include = '\.pyi?$' -exclude = ''' -/( - \.eggs - | \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - - # The following are specific to Black, you probably don't want those. - | blib2to3 - | tests/data - | profiling -)/ -''' +target-version = "py311" +#include = '\.pyi?$' +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".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 = "space" +docstring-code-format = true +line-ending = "auto" +skip-magic-trailing-comma = false diff --git a/requirements.txt b/requirements.txt index 952979d..374fc78 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,9 +6,9 @@ black==24.4.0 bleach==4.1.0 bleach-allowlist==1.0.3 blinker==1.7.0 -cffi==1.15.0 +cffi click==8.1.7 -distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@e291e7497e40211c2ebd54ca32a1f4bdaed71230 +distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@3eefd6e5ca7048555d441df8c6fbf4f2e255acac dnspython==2.1.0 email-validator==1.1.3 Flask==3.0.3 @@ -36,7 +36,7 @@ neovim==0.3.1 packaging==24.0 passlib==1.7.4 pathspec==0.9.0 -Pillow==8.3.2 +Pillow platformdirs==2.4.0 pycparser==2.21 pynvim==0.5.0 @@ -44,7 +44,7 @@ pyparsing==3.0.7 python-dateutil==2.9.0.post0 python-magic==0.4.24 pytz==2021.3 -regex==2021.11.10 +regex six==1.16.0 speaklater==1.3 SQLAlchemy==2.0.29 diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index 94548af..0000000 --- a/src/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -*/ -!.gitignore diff --git a/verse/admin.py b/verse/admin.py new file mode 100644 index 0000000..f95623b --- /dev/null +++ b/verse/admin.py @@ -0,0 +1,9 @@ +from flask_login import current_user +from models.user_model import User + + +def is_adminuser(): + if not current_user.is_authenticated: + return False + user = User.query.filter_by(email=current_user.email).first() + return user.admin diff --git a/verse/adminpage.py b/verse/admin_page/admin_page.py similarity index 57% rename from verse/adminpage.py rename to verse/admin_page/admin_page.py index 4d78d26..faf46ac 100644 --- a/verse/adminpage.py +++ b/verse/admin_page/admin_page.py @@ -1,7 +1,8 @@ import os import shutil -from flask import render_template +from flask import render_template, Blueprint +from flask_login import current_user, login_required from sqlalchemy.exc import ( DatabaseError, DataError, @@ -10,22 +11,34 @@ from sqlalchemy.exc import ( ) from app import db -from distribusikan.distribusisinfo import DistribusisInfo -from forms.admindistribusiform import AdminDistribusiForm -from forms.adminuserform import AdminUserForm +from admin import is_adminuser +from distribusikan.distribusis_info import DistribusisInfo +from admin_page.forms.admindistribusiform import AdminDistribusiForm +from admin_page.forms.adminuserform import AdminUserForm from models.distribusi_model import Distribusis from models.user_model import User +admin_page = Blueprint( + "admin", + __name__, + template_folder="templates/describe_files", + static_folder="static", +) + -def AdminPage(): - adminuserform = AddUsersToForm(AdminUserForm()) - admindistribusiform = AddDistribusisToForm(AdminDistribusiForm()) +@admin_page.route("/admin", methods=["GET", "POST"]) +@login_required +def admin(): + if not is_adminuser(): + return redirect(url_for("index")) + adminuserform = add_users_to_form(AdminUserForm()) + admindistribusiform = add_distribusis_to_form(AdminDistribusiForm()) if admindistribusiform.validate_on_submit(): - DeleteDistribusis(admindistribusiform) + delete_distribusis(admindistribusiform) if adminuserform.validate_on_submit(): if adminuserform.delete.data: - DeleteUsers(adminuserform) + delete_users(adminuserform) template = render_template( "admin.html", @@ -35,19 +48,18 @@ def AdminPage(): return template -def DeleteUsers(adminuserform): +def delete_users(adminuserform): for userform in adminuserform: if "user" in userform.id: if userform.data: useremail = userform.label.text user = User.query.filter_by(email=useremail).first() - DeleteUserDistribusis(user) - DeleteUserFromDb(user) + delete_User_distribusis(user) + delete_user_from_db(user) userform.errors.append(f"User {useremail} deleted!") - -def DeleteUserFromDb(user): +def delete_user_from_db(user): try: db.session.delete(user) db.session.commit() @@ -55,14 +67,14 @@ def DeleteUserFromDb(user): db.session.rollback() -def DeleteUserDistribusis(user): - distribusis = DistribusisInfo.getuserdistribusis(user.email) +def delete_User_distribusis(user): + distribusis = DistribusisInfo.get_user_distribusis(user.email) for distribusi in distribusis: - DeleteDistribusiFiles(distribusi.distribusiname) - DeleteDistribusiFromDb(distribusi) + delete_distribusi_files(distribusi.distribusiname) + delete_distribusi_from_db(distribusi) -def DeleteDistribusis(admindistribusiform): +def delete_distribusis(admindistribusiform): for distribusiform in admindistribusiform: if "distribusi" in distribusiform.id: if distribusiform.data: @@ -70,12 +82,12 @@ def DeleteDistribusis(admindistribusiform): distribusi = Distribusis.query.filter_by( distribusiname=distribusiname ).first() - DeleteDistribusiFromDb(distribusi) - DeleteDistribusiFiles(distribusiname) + delete_distribusi_from_db(distribusi) + delete_distribusi_files(distribusiname) distribusiform.errors.append("Deleted distribusi") -def DeleteDistribusiFromDb(distribusi): +def delete_distribusi_from_db(distribusi): try: db.session.delete(distribusi) db.session.commit() @@ -83,7 +95,7 @@ def DeleteDistribusiFromDb(distribusi): db.session.rollback() -def DeleteDistribusiFiles(distribusiname): +def delete_distribusi_files(distribusiname): userfolder = os.path.join("stash", distribusiname) if os.path.exists(userfolder): shutil.rmtree(userfolder) @@ -92,15 +104,15 @@ def DeleteDistribusiFiles(distribusiname): shutil.rmtree(cssfolder) -def AddDistribusisToForm(admindistribusiform): - distribusis = DistribusisInfo.visibledistribusis() +def add_distribusis_to_form(admindistribusiform): + distribusis = DistribusisInfo.visible_distribusis() admindistribusiform = AdminDistribusiForm.distribusi_list_form_builder( distribusis ) return admindistribusiform -def AddUsersToForm(adminuserform): +def add_users_to_form(adminuserform): users = User.query.all() adminuserform = AdminUserForm.user_list_form_builder(users) return adminuserform diff --git a/verse/forms/admindistribusiform.py b/verse/admin_page/forms/admindistribusiform.py similarity index 100% rename from verse/forms/admindistribusiform.py rename to verse/admin_page/forms/admindistribusiform.py diff --git a/verse/forms/adminuserform.py b/verse/admin_page/forms/adminuserform.py similarity index 100% rename from verse/forms/adminuserform.py rename to verse/admin_page/forms/adminuserform.py diff --git a/verse/templates/base/admin.html b/verse/admin_page/templates/admin.html similarity index 100% rename from verse/templates/base/admin.html rename to verse/admin_page/templates/admin.html diff --git a/verse/app.py b/verse/app.py index 56dd762..ff47f2b 100644 --- a/verse/app.py +++ b/verse/app.py @@ -8,6 +8,7 @@ from flask_migrate import Migrate from flask_sqlalchemy import SQLAlchemy from flask_wtf.csrf import CSRFProtect + APP = Flask(__name__, static_folder="static") db = SQLAlchemy() migrate = Migrate() @@ -19,8 +20,8 @@ def create_app(): APP.secret_key = os.urandom(24) APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///distribusiverse.db" 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_PORT"] = 587 APP.config["MAIL_USE_SSL"] = False @@ -64,7 +65,6 @@ def get_app(): def settings_from_file(): - settings = {} if os.path.isfile("settings_development.toml"): with open("settings_development.toml", "rb") as settings_file: return tomllib.load(settings_file) diff --git a/verse/deploydb.py b/verse/deploydb.py index 9a33cdc..30a8364 100644 --- a/verse/deploydb.py +++ b/verse/deploydb.py @@ -4,6 +4,7 @@ def deploy(): from app import create_app, db from models.distribusi_model import Distribusis # noqa: F401 + from models.distribusi_file_model import DistribusiFiles # noqa: F401 # This model is required for flask_migrate to make the table from models.user_model import User # noqa: F401 diff --git a/verse/describer/describe_files.py b/verse/describer/describe_files.py new file mode 100644 index 0000000..f53c329 --- /dev/null +++ b/verse/describer/describe_files.py @@ -0,0 +1,160 @@ +import os +from flask import ( + Blueprint, + render_template, + redirect, + url_for, + send_from_directory, + flash, +) +from flask_login import current_user, login_required +from sqlalchemy.exc import ( + DatabaseError, + DataError, + IntegrityError, + InterfaceError, + InvalidRequestError, +) +import piexif +from PIL import Image +from app import db +from models.distribusi_model import Distribusis +from models.distribusi_file_model import DistribusiFiles +from describer.forms.describe_files_form import DescribeFilesForm +from describer.forms.redistribusi_form import ReDistribusiForm +from distribusikan.distribusi_workflow import run_distribusi, get_css_file + +describer = Blueprint( + "describer", + __name__, + template_folder="templates/describe_files", + static_folder="static", +) + + +@describer.route("/") +@login_required +def show_distribusi_files(distribusiname): + if not current_user.is_authenticated: + return redirect(url_for("index")) + distribusi = Distribusis.query.filter_by( + distribusiname=distribusiname + ).first() + redistribusi_form = ReDistribusiForm() + distribusi_file_forms = get_distribusi_file_forms(distribusi.id) + return render_template( + "describe.html", + distribusiname=distribusiname, + redistribusi_form=redistribusi_form, + distribusi_file_forms=distribusi_file_forms, + ) + + +@describer.route("/redistribusi/", methods=["POST"]) +@login_required +def re_distribusi_files(distribusiname): + distribusi = Distribusis.query.filter_by( + distribusiname=distribusiname + ).first() + redistribusi_form = ReDistribusiForm() + if redistribusi_form.validate_on_submit(): + userfolder = os.path.join("stash", distribusi.distribusiname) + cssfile = get_css_file(distribusi) + run_distribusi(userfolder, cssfile) + return redirect( + url_for( + "describer.show_distribusi_files", + distribusiname=distribusi.distribusiname, + ) + ) + + +@describer.route("/describe_file/", methods=["POST"]) +@login_required +def describe_file(file_id): + distribusi_file = DistribusiFiles.query.filter_by(id=file_id).first() + describe_form = DescribeFilesForm( + distribusi_file.id, distribusi_file.path, distribusi_file.type + ) + save_described_file_to_db(describe_form, distribusi_file) + add_alttext_to_file(describe_form, distribusi_file) + add_description_to_file(describe_form, distribusi_file) + distribusi = Distribusis.query.filter_by( + id=distribusi_file.distribusi + ).first() + return redirect( + url_for( + "describer.show_distribusi_files", + distribusiname=distribusi.distribusiname, + ) + ) + + +@describer.route("/stash/") +def send_stash_file(path): + return send_from_directory("stash", path) + + +def get_distribusi_file_forms(distribusi_id): + distribusi_file_forms = {} + distribusi_files = DistribusiFiles.query.filter_by( + distribusi=distribusi_id + ).all() + for distribusi_file in distribusi_files: + describe_form = DescribeFilesForm( + distribusi_file.id, distribusi_file.path, distribusi_file.type + ) + describe_form.description.data = distribusi_file.description + describe_form.alttext.data = distribusi_file.alttext + describe_form.searchtags.data = distribusi_file.tags + distribusi_file_forms[distribusi_file.id] = describe_form + return distribusi_file_forms + + +def save_described_file_to_db(describe_form, distribusi_file): + try: + if describe_form.description.data: + print(distribusi_file.id) + distribusi_file.description = describe_form.description.data + if describe_form.alttext.data: + distribusi_file.alttext = describe_form.alttext.data + if describe_form.searchtags.data: + distribusi_file.tags = describe_form.searchtags.data + db.session.add(distribusi_file) + db.session.commit() + except (InvalidRequestError, IntegrityError): + db.session.rollback() + describe_form.save.errors.append("Something went wrong!") + flash("Something went wrong!", "danger") + except DataError: + db.session.rollback() + describe_form.save.errors.append("Invalid Entry") + flash("Invalid Entry", "warning") + except InterfaceError: + db.session.rollback() + describe_form.save.errors.append("Error connecting to the database") + flash("Error connecting to the database", "danger") + except DatabaseError: + db.session.rollback() + describe_form.save.errors.append("Error connecting to the database") + flash("Error connecting to the database", "danger") + + +def add_alttext_to_file(describe_form, distribusi_file): + if not describe_form.alttext.data: + return + filename_no_ext = os.path.splitext(distribusi_file.path)[0] + with open(f"{filename_no_ext}_alttext.txt", "w") as alttext_file: + alttext_file.write(describe_form.alttext.data) + return + + +def add_description_to_file(describe_form, distribusi_file): + if not describe_form.description.data: + return + filename_no_ext = os.path.splitext(distribusi_file.path)[0] + with open( + f"{filename_no_ext}_dv_description.txt", "w" + ) as description_file: + description_file.write(describe_form.description.data) + return diff --git a/verse/describer/forms/describe_files_form.py b/verse/describer/forms/describe_files_form.py new file mode 100644 index 0000000..6155be4 --- /dev/null +++ b/verse/describer/forms/describe_files_form.py @@ -0,0 +1,48 @@ +"""Describe File Form to describe files in the distribusi archive""" + +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField, validators +from wtforms.validators import Length +from wtforms.widgets import TextArea + + +class DescribeFilesForm(FlaskForm): + """DescribeFileForm selection form.""" + + alttext = StringField( + "Alt-text for this file:", + validators=[ + Length(3, 255), + ], + ) + searchtags = StringField( + "Add search tags, seperated by commas. No need for the '#' sign:", + validators=[ + Length(3, 500), + ], + ) + description = StringField( + "Description of this file:", + validators=[ + Length(3, 4096), + ], + widget=TextArea(), + ) + save = SubmitField("Save") + + def __init__(self, id, file_path=None, type=None): + super(DescribeFilesForm, self).__init__() + self.id = id + self.file_path = file_path + self.type = type + self.alttext.id = f"alttext-{id}" + self.searchtags.id = f"searchtags-{id}" + self.description.id = f"description-{id}" + self.save.id = f"save-{id}" + + +# def StringFieldWithId(form_name, **kwargs): +# name = kwargs.get('name', 'Bar') +# return wtf.StringField(name, render_kw={ +# 'id': f'{}{}'.format(form_name, name.lower(), +# **kwargs.get('render_kw', {})}) diff --git a/verse/describer/forms/redistribusi_form.py b/verse/describer/forms/redistribusi_form.py new file mode 100644 index 0000000..1d7676a --- /dev/null +++ b/verse/describer/forms/redistribusi_form.py @@ -0,0 +1,8 @@ +from flask_wtf import FlaskForm +from wtforms import SubmitField + + +class ReDistribusiForm(FlaskForm): + """Re-Distribusi form class to re-distrusi with desribed files""" + + submit = SubmitField("Re-Distribusi!") diff --git a/verse/describer/static/css/describer.css b/verse/describer/static/css/describer.css new file mode 100644 index 0000000..c80d69c --- /dev/null +++ b/verse/describer/static/css/describer.css @@ -0,0 +1,32 @@ +#describe_workflow { + display: flex; + width: 60em; + margin:0 auto; +} + +.redistribusi { + position: sticky; + top: 2em; + margin-top: 2em; + margin-left: 1em; + width: 15em; + height: 10em; + border-style: outset; + float: right; + padding: 0.5em; +} + +.distribusi_file { + margin-top: 2em; + padding: 0.5em; + width: 42em; + background-color:#fdfdfd; + text-decoration: none; + scroll-behavior: smooth; + border-style: outset; +} + +.distribusi_file > img, video { + max-width: 100%; + max-height: 100%; +} diff --git a/verse/describer/templates/describe_files/describe.html b/verse/describer/templates/describe_files/describe.html new file mode 100644 index 0000000..65d7120 --- /dev/null +++ b/verse/describer/templates/describe_files/describe.html @@ -0,0 +1,78 @@ +{% extends "base/base.html" %} +{% block main %} +
+ {% if current_user.is_authenticated %} +
+ + + +
+ {% if adminuser %} +
+ + + +
+ {% endif %} +
+ + + +
+ {% endif %} +
+ + + +
+
+
+
+ {% for id, describe_form in distribusi_file_forms.items() %} +
+ {% if describe_form.type == "image" %} + + {% elif describe_form.type == "video" %} + + {% elif describe_form.type == "audio" %} + + {% else %} + file: {{describe_form.file_path}} + {% endif %} +
+ {{ describe_form.csrf_token }} +

File path: {{describe_form.file_path}}

+
+ {{ describe_form.description.label }} + {{ describe_form.description }} + {% for message in describe_form.description.errors %} +
{{ message }}
+ {% endfor %} +
+
+ {{ describe_form.searchtags.label }} + {{ describe_form.searchtags }} + {% for message in describe_form.searchtags.errors %} +
{{ message }}
+ {% endfor %} +
+
+ {{ describe_form.alttext.label }} + {{ describe_form.alttext }} + {% for message in describe_form.alttext.errors %} +
{{ message }}
+ {% endfor %} +
+
+ {{ describe_form.save }} +
+
+
+ {% endfor%} +
+ {% block redistribusi %} + {% include "redistribusi.html" %} + {% endblock redistribusi%} +
+ +{% endblock %} diff --git a/verse/describer/templates/describe_files/redistribusi.html b/verse/describer/templates/describe_files/redistribusi.html new file mode 100644 index 0000000..d373311 --- /dev/null +++ b/verse/describer/templates/describe_files/redistribusi.html @@ -0,0 +1,13 @@ +
+

Run distribusi again after describing your files.Distribusi will run again and add your alttext and descriptions. +

+
+ {{ redistribusi_form.csrf_token }} +
+ {{ redistribusi_form.submit }} + {% for message in redistribusi_form.submit.errors %} +
{{ message }}
+ {% endfor %} +
+
+
diff --git a/verse/distribusikan/add_files_to_describer.py b/verse/distribusikan/add_files_to_describer.py new file mode 100644 index 0000000..466f912 --- /dev/null +++ b/verse/distribusikan/add_files_to_describer.py @@ -0,0 +1,82 @@ +import os + +import magic +from distribusi.mappings import FILE_TYPES +from models.distribusi_model import Distribusis +from models.distribusi_file_model import DistribusiFiles +from app import create_app, get_app, db +from sqlalchemy.exc import ( + DatabaseError, + DataError, + IntegrityError, + InterfaceError, + InvalidRequestError, +) + +MIME_TYPE = magic.Magic(mime=True) + + +def _distribusi_file_with_type(distribusi, full_path): + mime = MIME_TYPE.from_file(full_path) + type_, subtype = mime.split("/") + if type_ in FILE_TYPES: + _add_distribusi_file_to_db(distribusi, full_path, type_) + + +def _get_distribusi_from_path(path): + distribusi = Distribusis.query.filter_by(distribusiname=path).first() + return distribusi + + +def _add_distribusi_file_to_db(distribusi, full_path, type): + app = get_app() + app.logger.info(f"adding file to database: {full_path} type: {type}") + distribusi_file = DistribusiFiles.query.filter_by(path=full_path).first() + if distribusi_file is not None: + app.logger.error(f"File already in database: {full_path}") + return + try: + new_distribusi_file = DistribusiFiles( + path=full_path, + type=type, + distribusi=distribusi.id, + ) + db.session.add(new_distribusi_file) + db.session.commit() + return + except InvalidRequestError: + db.session.rollback() + app.logger.error("Something went wrong!") + except IntegrityError: + db.session.rollback() + app.logger.error("File %s already exists!", full_path) + except DataError: + db.session.rollback() + app.logger.error("%s Invalid Entry", full_path) + except InterfaceError: + db.session.rollback() + app.logger.error("Error connecting to the database") + except DatabaseError: + db.session.rollback() + app.logger.error("Error connecting to the database") + + +def add_distribusi_files_to_db(path): + distribusi = _get_distribusi_from_path(path) + path = os.path.join("stash", path) + 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.endswith(".html"), files)) + files = list(filter(lambda f: not f.endswith("_thumbnail.jpg"), files)) + files = list(filter(lambda f: not f.endswith("_alttext.txt"), files)) + files = list( + filter(lambda f: not f.endswith("_dv_description.txt"), files) + ) + + for file in files: + full_path = os.path.join(root, file) + distribusi_file = DistribusiFiles.query.filter_by( + path=full_path + ).first() + if distribusi_file is None: + _distribusi_file_with_type(distribusi, full_path) diff --git a/verse/distribusikan/editor.py b/verse/distribusikan/css_editor_page.py similarity index 69% rename from verse/distribusikan/editor.py rename to verse/distribusikan/css_editor_page.py index 88e63c2..8e9997e 100644 --- a/verse/distribusikan/editor.py +++ b/verse/distribusikan/css_editor_page.py @@ -13,28 +13,28 @@ from sqlalchemy.exc import ( from werkzeug.utils import secure_filename from app import db -from distribusikan.distribusisinfo import DistribusisInfo -from forms.distribusiform import DistribusiForm -from forms.editorform import EditorForm -from forms.publicthemeform import PublicThemeForm -from forms.selectorform import SelectorForm -from forms.themeform import ThemeForm -from forms.uploadform import UploadForm +from distribusikan.distribusis_info import DistribusisInfo +from distribusikan.forms.distribusiform import DistribusiForm +from distribusikan.forms.editorform import EditorForm +from distribusikan.forms.publicthemeform import PublicThemeForm +from distribusikan.forms.selectorform import SelectorForm +from distribusikan.forms.themeform import ThemeForm +from distribusikan.forms.uploadform import UploadForm from models.distribusi_model import Distribusis from statuspengguna.helper import UserHelper -def Editor(): +def css_editor_page(): editorform = EditorForm() current_distribusi = UserHelper.current_distribusi() if editorform.validate_on_submit(): - ValidateEditCssForm(editorform, current_distribusi) - return RenderDistribusiTemplate(current_distribusi) + validate_edit_css_form(editorform, current_distribusi) + return render_distribusi_template(current_distribusi) - return RenderEditorTemplate(editorform, current_distribusi) + return render_editor_template(editorform, current_distribusi) -def ValidateEditCssForm(editorform, current_distribusi): +def validate_edit_css_form(editorform, current_distribusi): newcssfolder = os.path.join("themes/userthemes", current_distribusi) if os.path.exists(newcssfolder): shutil.rmtree(newcssfolder) @@ -44,22 +44,22 @@ def ValidateEditCssForm(editorform, current_distribusi): shutil.rmtree(publicfolder) if editorform.public.data: - MakePublicTheme(editorform, current_distribusi) + make_public_theme(editorform, current_distribusi) if editorform.cssfile.data: - SaveUploadCssFile(editorform, publicfolder) - CopyPublicToUserFolder(editorform, publicfolder, newcssfolder) + save_upload_css_file(editorform, publicfolder) + copy_public_to_user_folder(editorform, publicfolder, newcssfolder) return else: - WriteCssToFile(editorform, publicfolder) + write_css_to_file(editorform, publicfolder) if editorform.cssfile.data: - SaveUploadCssFile(editorform, newcssfolder) + save_upload_css_file(editorform, newcssfolder) return if editorform.cssname.data: - WriteCssToFile(editorform, newcssfolder) + write_css_to_file(editorform, newcssfolder) -def SaveUploadCssFile(editorform, newcssfolder): +def save_upload_css_file(editorform, newcssfolder): if not os.path.exists(newcssfolder): os.mkdir(newcssfolder) cssfile = editorform.cssfile.data @@ -74,7 +74,7 @@ def SaveUploadCssFile(editorform, newcssfolder): cleanfile.close() -def WriteCssToFile(editorform, newcssfolder): +def write_css_to_file(editorform, newcssfolder): if not os.path.exists(newcssfolder): os.mkdir(newcssfolder) @@ -86,7 +86,7 @@ def WriteCssToFile(editorform, newcssfolder): cssfile.close -def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder): +def copy_public_to_user_folder(editorform, publicfolder, newcssfolder): if not os.path.exists(newcssfolder): os.mkdir(newcssfolder) copycssfile = os.path.join( @@ -97,7 +97,7 @@ def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder): shutil.copy(copycssfile, newcssfolder) -def MakePublicTheme(editorform, current_distribusi): +def make_public_theme(editorform, current_distribusi): try: distribusi = Distribusis.query.filter_by( distribusiname=current_distribusi @@ -119,12 +119,12 @@ def MakePublicTheme(editorform, current_distribusi): editorform.public.errors.append("Error connecting to the database") -def RenderDistribusiTemplate(current_distribusi): +def render_distribusi_template(current_distribusi): uploadform = UploadForm() distribusiform = DistribusiForm() themeform = ThemeForm() publicthemeform = PublicThemeForm() - publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() + publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() selectorform = SelectorForm() files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) @@ -148,11 +148,11 @@ def RenderDistribusiTemplate(current_distribusi): return template -def RenderEditorTemplate(editorform, current_distribusi): - htmlplaceholder = HtmlPlaceholder() +def render_editor_template(editorform, current_distribusi): + html_placeholder = get_html_placeholder() - cssplaceholder = CssPlaceholder(current_distribusi) - editorform.css.data = cssplaceholder + css_placeholder = get_css_placeholder(current_distribusi) + editorform.css.data = css_placeholder files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi) @@ -161,33 +161,33 @@ def RenderEditorTemplate(editorform, current_distribusi): files_uploaded=files_uploaded, distribusi_live=distribusi_live, editorform=editorform, - htmlplaceholder=htmlplaceholder, + html_placeholder=html_placeholder, ) return template -def CssPlaceholder(current_distribusi): - cssplaceholder = "Try out your CSS here" +def get_css_placeholder(current_distribusi): + css_placeholder = "Try out your CSS here" distribusi = Distribusis.query.filter_by( distribusiname=current_distribusi ).first() if distribusi is not None and distribusi.publictheme is not None: - cssplaceholder = GetPublicCssFile(distribusi) + css_placeholder = get_public_css_file(distribusi) else: with open("themes/editor/placeholder.css") as f: - cssplaceholder = f.read() - return cssplaceholder + css_placeholder = f.read() + return css_placeholder -def HtmlPlaceholder(): - htmlplaceholder = "Write some test HTML here" +def get_html_placeholder(): + html_placeholder = "Write some test HTML here" with open("themes/editor/placeholder.html") as f: - htmlplaceholder = f.read() - return htmlplaceholder + html_placeholder = f.read() + return html_placeholder -def GetPublicCssFile(distribusi): - cssplaceholder = "" +def get_public_css_file(distribusi): + css_placeholder = "" publicthemefolder = os.path.join( "themes/publicthemes", distribusi.distribusiname ) @@ -195,5 +195,5 @@ def GetPublicCssFile(distribusi): if filename.endswith(".css"): cssfile = os.path.join(publicthemefolder, filename) with open(cssfile) as f: - cssplaceholder = f.read() - return cssplaceholder + css_placeholder = f.read() + return css_placeholder diff --git a/verse/distribusikan/distribusiselector.py b/verse/distribusikan/distribusi_selector.py similarity index 69% rename from verse/distribusikan/distribusiselector.py rename to verse/distribusikan/distribusi_selector.py index ccc5770..b47b227 100644 --- a/verse/distribusikan/distribusiselector.py +++ b/verse/distribusikan/distribusi_selector.py @@ -1,7 +1,7 @@ import os import shutil -from flask import flash, render_template +from flask import flash, render_template, redirect, url_for from flask_login import current_user from sqlalchemy.exc import ( DatabaseError, @@ -11,12 +11,12 @@ from sqlalchemy.exc import ( ) from app import db -from distribusikan.distribusisinfo import DistribusisInfo -from forms.distribusiform import DistribusiForm -from forms.publicthemeform import PublicThemeForm -from forms.selectorform import SelectorForm -from forms.themeform import ThemeForm -from forms.uploadform import UploadForm +from distribusikan.distribusis_info import DistribusisInfo +from distribusikan.forms.distribusiform import DistribusiForm +from distribusikan.forms.publicthemeform import PublicThemeForm +from distribusikan.forms.selectorform import SelectorForm +from distribusikan.forms.themeform import ThemeForm +from distribusikan.forms.uploadform import UploadForm from models.distribusi_model import Distribusis from models.user_model import User @@ -24,52 +24,66 @@ from models.user_model import User from statuspengguna.helper import UserHelper -def DistribusiSelector(): +def distribusi_selector(): uploadform = UploadForm() selectorform = SelectorForm() - selectorform.distribusis.choices = DistribusisInfo.userdistribusinames() + selectorform.distribusis.choices = DistribusisInfo.user_distribusinames() current_distribusi = UserHelper.current_distribusi() if selectorform.validate_on_submit(): if selectorform.new.data: - SelectNewDistribusi() + select_new_distribusi() + if selectorform.describe.data: + return select_describe_distribusi(selectorform.distribusis.data) if selectorform.delete.data: - selectorform = DeleteDistribusi(selectorform.distribusis.data) + selectorform = delete_distribusi(selectorform.distribusis.data) selectorform.distribusis.choices = ( - DistribusisInfo.userdistribusinames() + DistribusisInfo.user_distribusinames() ) if selectorform.update.data: - SelectUpdateDistribusi(selectorform.distribusis.data) + select_update_distribusi(selectorform.distribusis.data) current_distribusi = UserHelper.current_distribusi() - uploadform = AutoFillInUploadForm(uploadform, current_distribusi) + uploadform = auto_fill_in_upload_form( + uploadform, current_distribusi + ) - return RenderDistribusiTemplate( + return render_distribusi_template( selectorform, uploadform, current_distribusi ) -def AutoFillInUploadForm(uploadform, current_distribusi): +def auto_fill_in_upload_form(uploadform, current_distribusi): distribusi = Distribusis.query.filter_by( distribusiname=current_distribusi ).first() uploadform.sitename.data = distribusi.distribusiname uploadform.sitename.render_kw = {"readonly": True} + uploadform.description.data = distribusi.description uploadform.category.data = distribusi.category uploadform.year.data = distribusi.year uploadform.tags.data = distribusi.tags return uploadform -def SelectNewDistribusi(): +def select_new_distribusi(): print("make a new distribusi") - SelectCurrentDistribusi("new") + select_current_distribusi("new") + + +def select_describe_distribusi(distribusiname): + return redirect( + url_for( + "describer.show_distribusi_files", + distribusiname=distribusiname, + ) + ) -def SelectUpdateDistribusi(distribusiname): +def select_update_distribusi(distribusiname): print(f"Update this distribusi {distribusiname}") - SelectCurrentDistribusi(distribusiname) + select_current_distribusi(distribusiname) -def DeleteDistribusi(distribusiname): +def delete_distribusi(distribusiname): print(f"delete this distribusi {distribusiname}") selectorform = SelectorForm() try: @@ -103,7 +117,7 @@ def DeleteDistribusi(distribusiname): return selectorform -def SelectCurrentDistribusi(distribusiname): +def select_current_distribusi(distribusiname): if not current_user.is_authenticated: return user = User.query.filter_by(email=current_user.email).first() @@ -115,35 +129,35 @@ def SelectCurrentDistribusi(distribusiname): flash("An error occured !", "danger") -def DistribusiSelected(): +def distribusi_selected(): user = User.query.filter_by(email=current_user.email).first() if user.currentdistribusi is None: return False return True -def SelectorVisible(): +def selector_visible(): has_distribusi = UserHelper.has_distribusi() - distribusi_selected = DistribusiSelected() - if distribusi_selected: + is_distribusi_selected = distribusi_selected() + if is_distribusi_selected: return False if not has_distribusi: return False return True -def RenderDistribusiTemplate(selectorform, uploadform, current_distribusi): +def render_distribusi_template(selectorform, uploadform, current_distribusi): distribusiform = DistribusiForm() themeform = ThemeForm() publicthemeform = PublicThemeForm() - publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() + publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi) # because the user has chosen to update his distribusi, we assume # no selected css. css_selected = False - selectorvisible = SelectorVisible() + selectorvisible = selector_visible() limit_reached = UserHelper.distribusi_limit_reached() template = render_template( "distribusi.html", diff --git a/verse/distribusikan/distribusiworkflow.py b/verse/distribusikan/distribusi_workflow.py similarity index 67% rename from verse/distribusikan/distribusiworkflow.py rename to verse/distribusikan/distribusi_workflow.py index 4e3a376..f9977fb 100644 --- a/verse/distribusikan/distribusiworkflow.py +++ b/verse/distribusikan/distribusi_workflow.py @@ -15,15 +15,16 @@ from sqlalchemy.exc import ( ) from app import db -from distribusikan.distribusiselector import SelectorVisible -from distribusikan.distribusisinfo import DistribusisInfo -from forms.distribusiform import DistribusiForm -from forms.publicthemeform import PublicThemeForm -from forms.selectorform import SelectorForm -from forms.themeform import ThemeForm +from distribusikan.add_files_to_describer import add_distribusi_files_to_db +from distribusikan.distribusi_selector import selector_visible +from distribusikan.distribusis_info import DistribusisInfo +from distribusikan.forms.distribusiform import DistribusiForm +from distribusikan.forms.publicthemeform import PublicThemeForm +from distribusikan.forms.selectorform import SelectorForm +from distribusikan.forms.themeform import ThemeForm # Forms! -from forms.uploadform import UploadForm +from distribusikan.forms.uploadform import UploadForm from models.distribusi_model import Distribusis from models.user_model import User @@ -31,7 +32,7 @@ from models.user_model import User from statuspengguna.helper import UserHelper -def DistribusiWorkflow(): +def distribusi_workflow(): distribusiform = DistribusiForm() current_distribusi = UserHelper.current_distribusi() user = User.query.filter_by(email=current_user.email).first() @@ -41,18 +42,19 @@ def DistribusiWorkflow(): if distribusiform.validate_on_submit(): userfolder = os.path.join("stash", distribusi.distribusiname) - cssfile = GetCssFile(distribusi) - UnzipDistribusiFiles(distribusi, userfolder) - CleanUpDistribusiFiles(userfolder) - RunDistribusi(userfolder, cssfile) - SetDistribusiToVisible(distribusi, user) - DeleteCssFile(cssfile) + cssfile = get_css_file(distribusi) + unzip_distribusi_files(distribusi, userfolder) + clean_up_distribusi_files(userfolder) + add_distribusi_files_to_db(distribusi.distribusiname) + run_distribusi(userfolder, cssfile) + set_distribusi_to_visible(distribusi, user) + delete_css_file(cssfile) return redirect(url_for("index")) - return RenderDistribusiTemplate(distribusiform, current_distribusi) + return render_distribusi_template(distribusiform, current_distribusi) -def UnzipDistribusiFiles(distribusi, userfolder): +def unzip_distribusi_files(distribusi, userfolder): zipfilename = "{}.zip".format(distribusi.distribusiname) unzipfile = os.path.join(userfolder, zipfilename) @@ -64,12 +66,12 @@ def UnzipDistribusiFiles(distribusi, userfolder): os.remove(os.path.join(userfolder, zipfilename)) -def CleanUpDistribusiFiles(userfolder): +def clean_up_distribusi_files(userfolder): if os.path.exists(userfolder): - RemoveMacFolders(userfolder) + remove_mac_folders(userfolder) -def RemoveMacFolders(path): +def remove_mac_folders(path): for filename in os.listdir(path): fullpath = os.path.join(path, filename) if filename.startswith("."): @@ -80,10 +82,10 @@ def RemoveMacFolders(path): if filename == "__MACOSX": shutil.rmtree(fullpath) if os.path.isdir(fullpath): - RemoveMacFolders(fullpath) + remove_mac_folders(fullpath) -def GetCssFile(distribusi): +def get_css_file(distribusi): cssfile = "" cssfolder = os.path.join("themes/userthemes", distribusi.distribusiname) if os.path.exists(cssfolder): @@ -93,13 +95,14 @@ def GetCssFile(distribusi): return cssfile -def RunDistribusi(userfolder, cssfile): +def run_distribusi(userfolder, cssfile): + print(f"Run distribusi on this folder: {userfolder} with css:{cssfile}") parser = build_argparser() - args = parser.parse_args(["-t", "--menu-with-index", "-s", cssfile]) + args = parser.parse_args(["-t", "-a", "--menu-with-index", "-s", cssfile]) distribusify(args, userfolder) -def SetDistribusiToVisible(distribusi, user): +def set_distribusi_to_visible(distribusi, user): try: distribusi.visible = True user.currentdistribusi = None @@ -109,19 +112,19 @@ def SetDistribusiToVisible(distribusi, user): flash("Unknown error occured!") -def DeleteCssFile(cssfile): +def delete_css_file(cssfile): if os.path.exists(cssfile): os.remove(cssfile) -def RenderDistribusiTemplate(distribusiform, current_distribusi): +def render_distribusi_template(distribusiform, current_distribusi): uploadform = UploadForm() themeform = ThemeForm() publicthemeform = PublicThemeForm() - publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() + publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() selectorform = SelectorForm() - selectorform.distribusis.choices = DistribusisInfo.userdistribusinames() - selectorvisible = SelectorVisible() + selectorform.distribusis.choices = DistribusisInfo.user_distribusinames() + selectorvisible = selector_visible() files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi) diff --git a/verse/distribusikan/distribusikan.py b/verse/distribusikan/distribusikan.py index 4ba50ae..870ac47 100644 --- a/verse/distribusikan/distribusikan.py +++ b/verse/distribusikan/distribusikan.py @@ -1,14 +1,13 @@ from flask import Blueprint from flask_login import login_required -from distribusikan.distribusiselector import DistribusiSelector +from distribusikan.distribusi_selector import distribusi_selector # Distribusi Information -from distribusikan.distribusisinfo import DistribusisInfo -from distribusikan.distribusiworkflow import DistribusiWorkflow -from distribusikan.editor import Editor -from distribusikan.themeselector import ThemeSelector -from distribusikan.uploadpage import UploadPage +from distribusikan.distribusi_workflow import distribusi_workflow +from distribusikan.css_editor_page import css_editor_page +from distribusikan.theme_selector import theme_selector +from distribusikan.upload_page import upload_page distribusikan = Blueprint( "distribusikan", @@ -21,28 +20,28 @@ distribusikan = Blueprint( @distribusikan.route("/distribusi", methods=["GET", "POST"]) @login_required def distribusi(): - return DistribusiWorkflow() + return distribusi_workflow() @distribusikan.route("/upload", methods=["POST"]) @login_required def upload(): - return UploadPage() + return upload_page() @distribusikan.route("/theme", methods=["GET", "POST"]) @login_required def theme(): - return ThemeSelector() + return theme_selector() @distribusikan.route("/editor", methods=["GET", "POST"]) @login_required def editor(): - return Editor() + return css_editor_page() @distribusikan.route("/selector", methods=["GET", "POST"]) @login_required def selector(): - return DistribusiSelector() + return distribusi_selector() diff --git a/verse/distribusikan/distribusisinfo.py b/verse/distribusikan/distribusis_info.py similarity index 90% rename from verse/distribusikan/distribusisinfo.py rename to verse/distribusikan/distribusis_info.py index 19ef284..aa614bb 100644 --- a/verse/distribusikan/distribusisinfo.py +++ b/verse/distribusikan/distribusis_info.py @@ -5,14 +5,14 @@ from models.user_model import User class DistribusisInfo: - def userdistribusinames(): + def user_distribusinames(): distribusinames = [] user = User.query.filter_by(email=current_user.email).first() for distribusi in Distribusis.query.filter_by(userid=user.id).all(): distribusinames.append(distribusi.distribusiname) return distribusinames - def publicthemes(): + def public_themes(): publicthemes = [] distribusis = Distribusis.query.filter( Distribusis.publictheme.isnot(None) @@ -27,12 +27,12 @@ made by {user.username}""", publicthemes.append(publictheme) return publicthemes - def visibledistribusis(): + def visible_distribusis(): distribusis = Distribusis.query.filter( Distribusis.visible.isnot(False) ).all() return distribusis - def getuserdistribusis(useremail): + def get_user_distribusis(useremail): user = User.query.filter_by(email=useremail).first() return Distribusis.query.filter_by(userid=user.id).all() diff --git a/verse/forms/distribusiform.py b/verse/distribusikan/forms/distribusiform.py similarity index 100% rename from verse/forms/distribusiform.py rename to verse/distribusikan/forms/distribusiform.py diff --git a/verse/forms/editorform.py b/verse/distribusikan/forms/editorform.py similarity index 100% rename from verse/forms/editorform.py rename to verse/distribusikan/forms/editorform.py diff --git a/verse/forms/publicthemeform.py b/verse/distribusikan/forms/publicthemeform.py similarity index 100% rename from verse/forms/publicthemeform.py rename to verse/distribusikan/forms/publicthemeform.py diff --git a/verse/forms/selectorform.py b/verse/distribusikan/forms/selectorform.py similarity index 87% rename from verse/forms/selectorform.py rename to verse/distribusikan/forms/selectorform.py index d726971..f2f9530 100644 --- a/verse/forms/selectorform.py +++ b/verse/distribusikan/forms/selectorform.py @@ -9,4 +9,6 @@ class SelectorForm(FlaskForm): update = SubmitField("update") + describe = SubmitField("describe") + delete = SubmitField("delete") diff --git a/verse/forms/themeform.py b/verse/distribusikan/forms/themeform.py similarity index 100% rename from verse/forms/themeform.py rename to verse/distribusikan/forms/themeform.py diff --git a/verse/forms/uploadform.py b/verse/distribusikan/forms/uploadform.py similarity index 82% rename from verse/forms/uploadform.py rename to verse/distribusikan/forms/uploadform.py index 5d1f21f..f0af89b 100644 --- a/verse/forms/uploadform.py +++ b/verse/distribusikan/forms/uploadform.py @@ -1,18 +1,18 @@ from flask_wtf import FlaskForm from flask_wtf.file import FileAllowed, FileField, FileRequired, FileSize from wtforms import ( - IntegerField, SelectField, StringField, SubmitField, + TextAreaField, validators, ) from wtforms.validators import ( DataRequired, Length, - NumberRange, ValidationError, ) +from wtforms.widgets import TextArea from app import settings @@ -50,6 +50,13 @@ class UploadForm(FlaskForm): distribusiname, ], ) + description = StringField( + "Description of this distribusi:", + validators=[ + Length(10, 32000), + ], + widget=TextArea(), + ) year = SelectField( "Year:", validate_choice=True, @@ -68,8 +75,8 @@ class UploadForm(FlaskForm): ) tags = StringField( - "Add tags, seperated by commas. No need for the '#' sign:", - validators=[validators.InputRequired(), Length(2, 500)], + "Add search tags, seperated by commas. No need for the '#' sign:", + validators=[validators.InputRequired(), Length(3, 500)], ) zipfile = FileField( @@ -79,7 +86,7 @@ class UploadForm(FlaskForm): FileRequired(), FileSize( max_size=1073741824, - message="Zipfile size must be smaller than 100MB", + message="Zipfile size must be smaller than 1024MB", ), ], ) diff --git a/verse/distribusikan/static/css/distribusikan.css b/verse/distribusikan/static/css/distribusikan.css new file mode 100644 index 0000000..2083035 --- /dev/null +++ b/verse/distribusikan/static/css/distribusikan.css @@ -0,0 +1,32 @@ +#publicthemes > ul { + max-height: 20em; + overflow: auto; +} + +#publicthemes > ul > li{ + word-break: break-all; +} + +.workflow{ + margin-top: 1em; + padding: 0.5em; + background-color:#fdfdfd; + text-decoration: none; + scroll-behavior: smooth; + border-style: outset; +} + +.workflow > p { + padding-left: 1em; +} + +.workflow > h2 { + padding-left: 0.4em;; +} + +.workflow input{ + max-width: 20em; +} +.new_divider { + height: 5em; +} diff --git a/verse/static/css/editor.css b/verse/distribusikan/static/css/editor.css similarity index 86% rename from verse/static/css/editor.css rename to verse/distribusikan/static/css/editor.css index d087622..d8f2ed6 100644 --- a/verse/static/css/editor.css +++ b/verse/distribusikan/static/css/editor.css @@ -5,7 +5,7 @@ } .editarea { width: 30%; - border: 3px solid #E0B0FF; + border: 3px solid #9de457; border-style: outset; margin-right: 1em; margin-left: 0; @@ -31,7 +31,7 @@ textarea { height: 100%; box-sizing: border-box; min-height: 250px; - background: #E0B0FF; + background: #9de457; outline: none; font-family: Courier, sans-serif; font-size: 16px; @@ -45,6 +45,6 @@ iframe { height: 30em; } #html { - background-color: #60337F; - color: lightgrey; + background-color: #9de457; + color: black; } diff --git a/verse/distribusikan/templates/distribusikan/distribusi.html b/verse/distribusikan/templates/distribusikan/distribusi.html index e85f04c..1e9c563 100644 --- a/verse/distribusikan/templates/distribusikan/distribusi.html +++ b/verse/distribusikan/templates/distribusikan/distribusi.html @@ -20,27 +20,28 @@
{% if selectorvisible %} {% block selector %} - {% include "distribusiworkflow/selector.html" %} + {% include "distribusi_workflow/selector.html" %} {% endblock selector%} {% else %} {% block upload %} - {% include "distribusiworkflow/upload.html" %} + {% include "distribusi_workflow/upload.html" %} {% endblock upload%} {% block theme %} - {% include "distribusiworkflow/theme.html" %} + {% include "distribusi_workflow/theme.html" %} {% endblock theme%} {% block editcss %} - {% include "distribusiworkflow/editcss.html" %} + {% include "distribusi_workflow/editcss.html" %} {% endblock editcss%} {% block launch %} - {% include "distribusiworkflow/launch.html" %} + {% include "distribusi_workflow/launch.html" %} {% endblock launch%} {%endif%}
{% if css_selected %} {% endif %} + {% endblock main %} diff --git a/verse/distribusikan/templates/distribusikan/distribusiworkflow/editcss.html b/verse/distribusikan/templates/distribusikan/distribusi_workflow/editcss.html similarity index 83% rename from verse/distribusikan/templates/distribusikan/distribusiworkflow/editcss.html rename to verse/distribusikan/templates/distribusikan/distribusi_workflow/editcss.html index 0170599..bd003fd 100644 --- a/verse/distribusikan/templates/distribusikan/distribusiworkflow/editcss.html +++ b/verse/distribusikan/templates/distribusikan/distribusi_workflow/editcss.html @@ -1,7 +1,7 @@

Step 3: Edit Custom CSS (Optional)

{% if files_uploaded or distribusi_live %} -

Go to CSS editor

+

Go to CSS editor

{% else %}

You need to upload your files first before you can select a css theme diff --git a/verse/distribusikan/templates/distribusikan/distribusiworkflow/launch.html b/verse/distribusikan/templates/distribusikan/distribusi_workflow/launch.html similarity index 100% rename from verse/distribusikan/templates/distribusikan/distribusiworkflow/launch.html rename to verse/distribusikan/templates/distribusikan/distribusi_workflow/launch.html diff --git a/verse/distribusikan/templates/distribusikan/distribusiworkflow/selector.html b/verse/distribusikan/templates/distribusikan/distribusi_workflow/selector.html similarity index 84% rename from verse/distribusikan/templates/distribusikan/distribusiworkflow/selector.html rename to verse/distribusikan/templates/distribusikan/distribusi_workflow/selector.html index 88dac97..3880148 100644 --- a/verse/distribusikan/templates/distribusikan/distribusiworkflow/selector.html +++ b/verse/distribusikan/templates/distribusikan/distribusi_workflow/selector.html @@ -18,6 +18,13 @@ {{ selectorform.update }}


+

+ Describe your distribusi files. Add description texts, tags for search + or add alt-text for images

+
+ {{ selectorform.describe }} +
+

This will delete your distribusi site. This action cannot be undone! @@ -29,6 +36,7 @@ {% endfor %}


+
{% if limit_reached %}

You have reached your limit of distribusi websites

{% else %} diff --git a/verse/distribusikan/templates/distribusikan/distribusiworkflow/theme.html b/verse/distribusikan/templates/distribusikan/distribusi_workflow/theme.html similarity index 100% rename from verse/distribusikan/templates/distribusikan/distribusiworkflow/theme.html rename to verse/distribusikan/templates/distribusikan/distribusi_workflow/theme.html diff --git a/verse/distribusikan/templates/distribusikan/distribusiworkflow/upload.html b/verse/distribusikan/templates/distribusikan/distribusi_workflow/upload.html similarity index 87% rename from verse/distribusikan/templates/distribusikan/distribusiworkflow/upload.html rename to verse/distribusikan/templates/distribusikan/distribusi_workflow/upload.html index fe3aa78..f8a0502 100644 --- a/verse/distribusikan/templates/distribusikan/distribusiworkflow/upload.html +++ b/verse/distribusikan/templates/distribusikan/distribusi_workflow/upload.html @@ -10,6 +10,13 @@
{{ message }}
{% endfor %} +
+ {{ uploadform.description.label }} + {{ uploadform.description }} + {% for message in uploadform.description.errors %} +
{{ message }}
+ {% endfor %} +
{{ uploadform.year.label }}
diff --git a/verse/distribusikan/templates/distribusikan/editor.html b/verse/distribusikan/templates/distribusikan/editor.html index b6e39f4..7ed5b84 100644 --- a/verse/distribusikan/templates/distribusikan/editor.html +++ b/verse/distribusikan/templates/distribusikan/editor.html @@ -5,7 +5,7 @@
@@ -54,6 +54,6 @@ - + {% endblock main %} diff --git a/verse/distribusikan/themeselector.py b/verse/distribusikan/theme_selector.py similarity index 71% rename from verse/distribusikan/themeselector.py rename to verse/distribusikan/theme_selector.py index 96b2d8a..30388e4 100644 --- a/verse/distribusikan/themeselector.py +++ b/verse/distribusikan/theme_selector.py @@ -3,45 +3,45 @@ import shutil from flask import render_template -from distribusikan.distribusisinfo import DistribusisInfo -from forms.distribusiform import DistribusiForm -from forms.publicthemeform import PublicThemeForm -from forms.selectorform import SelectorForm -from forms.themeform import ThemeForm -from forms.uploadform import UploadForm +from distribusikan.distribusis_info import DistribusisInfo +from distribusikan.forms.distribusiform import DistribusiForm +from distribusikan.forms.publicthemeform import PublicThemeForm +from distribusikan.forms.selectorform import SelectorForm +from distribusikan.forms.themeform import ThemeForm +from distribusikan.forms.uploadform import UploadForm from statuspengguna.helper import UserHelper -def ThemeSelector(): +def theme_selector(): themeform = ThemeForm() publicthemeform = PublicThemeForm() - publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() + publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() current_distribusi = UserHelper.current_distribusi() if themeform.validate_on_submit(): copycssfile = os.path.join( "themes", f"{themeform.theme.data}.css", ) - MoveCssToUserFolder(current_distribusi, copycssfile) + move_css_to_user_folder(current_distribusi, copycssfile) if publicthemeform.validate_on_submit(): copycssfile = os.path.join( "themes/publicthemes/", f"{publicthemeform.publicthemes.data}.css", ) - MoveCssToUserFolder(current_distribusi, copycssfile) - return RenderDistribusiTemplate( + move_css_to_user_folder(current_distribusi, copycssfile) + return render_distribusi_template( themeform, publicthemeform, current_distribusi ) -def MoveCssToUserFolder(current_distribusi, copycssfile): +def move_css_to_user_folder(current_distribusi, copycssfile): newcssfolder = os.path.join("themes/userthemes", current_distribusi) if not os.path.exists(newcssfolder): os.mkdir(newcssfolder) shutil.copy(copycssfile, newcssfolder) -def RenderDistribusiTemplate(themeform, publicthemeform, current_distribusi): +def render_distribusi_template(themeform, publicthemeform, current_distribusi): uploadform = UploadForm() distribusiform = DistribusiForm() selectorform = SelectorForm() diff --git a/verse/distribusikan/upload.py b/verse/distribusikan/upload.py index 83110b5..b81e3e6 100644 --- a/verse/distribusikan/upload.py +++ b/verse/distribusikan/upload.py @@ -12,14 +12,14 @@ from sqlalchemy.exc import ( ) from app import db -from distribusikan.distribusiselector import SelectCurrentDistribusi -from forms.uploadform import UploadForm +from distribusikan.distribusi_selector import select_current_distribusi +from distribusikan.forms.uploadform import UploadForm from models.distribusi_model import Distribusis from models.user_model import User from statuspengguna.helper import UserHelper -def UploadNewDistribusi(uploadfolder): +def upload_new_distribusi(uploadfolder): uploadform = UploadForm() if uploadform.validate_on_submit(): user = User.query.filter_by(email=current_user.email).first() @@ -28,6 +28,7 @@ def UploadNewDistribusi(uploadfolder): distribusiname=uploadform.sitename.data, userid=user.id, category=uploadform.category.data, + description=uploadform.description.data, year=uploadform.year.data, tags=uploadform.tags.data, ) @@ -46,7 +47,7 @@ def UploadNewDistribusi(uploadfolder): uploadform.sitename.errors.append("Something went wrong!") flash("Something went wrong!", "danger") return uploadform - SelectCurrentDistribusi(newdistribusi.distribusiname) + select_current_distribusi(newdistribusi.distribusiname) zipfilename = "{}.zip".format(newdistribusi.distribusiname) zipfile = uploadform.zipfile.data zipfile.save(os.path.join(uploadfolder, zipfilename)) @@ -62,7 +63,7 @@ def UploadNewDistribusi(uploadfolder): return uploadform -def UploadUpdatedFiles(uploadfolder): +def upload_updates_files(uploadfolder): uploadform = UploadForm() if uploadform.validate_on_submit(): try: @@ -71,6 +72,7 @@ def UploadUpdatedFiles(uploadfolder): distribusiname=current_distribusi ).first() distribusi.category = uploadform.category.data + distribusi.description = (uploadform.description.data,) distribusi.year = uploadform.year.data distribusi.tags = uploadform.tags.data distribusi.visible = False diff --git a/verse/distribusikan/uploadpage.py b/verse/distribusikan/upload_page.py similarity index 64% rename from verse/distribusikan/uploadpage.py rename to verse/distribusikan/upload_page.py index a8f2510..06070f3 100644 --- a/verse/distribusikan/uploadpage.py +++ b/verse/distribusikan/upload_page.py @@ -1,34 +1,34 @@ from flask import render_template from app import APP -from distribusikan.distribusiselector import SelectorVisible -from distribusikan.distribusisinfo import DistribusisInfo -from distribusikan.upload import UploadNewDistribusi, UploadUpdatedFiles -from forms.distribusiform import DistribusiForm -from forms.publicthemeform import PublicThemeForm -from forms.selectorform import SelectorForm -from forms.themeform import ThemeForm +from distribusikan.distribusi_selector import selector_visible +from distribusikan.distribusis_info import DistribusisInfo +from distribusikan.upload import upload_new_distribusi, upload_updates_files +from distribusikan.forms.distribusiform import DistribusiForm +from distribusikan.forms.publicthemeform import PublicThemeForm +from distribusikan.forms.selectorform import SelectorForm +from distribusikan.forms.themeform import ThemeForm # UserPengguna from statuspengguna.helper import UserHelper -def UploadPage(): +def upload_page(): "render upload page section of distribusi workflow" uploadfolder = APP.config["UPLOAD_FOLDER"] distribusiform = DistribusiForm() themeform = ThemeForm() publicthemeform = PublicThemeForm() - publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() + publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() selectorform = SelectorForm() - selectorform.distribusis.choices = DistribusisInfo.userdistribusinames() - selectorvisible = SelectorVisible() + selectorform.distribusis.choices = DistribusisInfo.user_distribusinames() + selectorvisible = selector_visible() current_distribusi = UserHelper.current_distribusi() if current_distribusi == "new" or UserHelper.has_distribusi() is False: - uploadform = UploadNewDistribusi(uploadfolder) + uploadform = upload_new_distribusi(uploadfolder) else: - uploadform = UploadUpdatedFiles(uploadfolder) + uploadform = upload_updates_files(uploadfolder) files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data) distribusi_live = UserHelper.is_distribusi_live(current_distribusi) diff --git a/verse/migrations/env.py b/verse/migrations/env.py index 847c719..68a0091 100644 --- a/verse/migrations/env.py +++ b/verse/migrations/env.py @@ -3,9 +3,10 @@ from __future__ import with_statement import logging from logging.config import fileConfig -from alembic import context from flask import current_app +from alembic import context + # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config diff --git a/verse/models/distribusi_file_model.py b/verse/models/distribusi_file_model.py index 503f7bb..edddc71 100644 --- a/verse/models/distribusi_file_model.py +++ b/verse/models/distribusi_file_model.py @@ -7,11 +7,12 @@ class DistribusiFiles(db.Model): __tablename__ = "distribusi_files" id = db.Column(db.Integer, primary_key=True) - type = db.Column(db.String(300), nullable=False, unique=True) + type = db.Column(db.String(100), nullable=True, unique=False) distribusi = db.Column(db.Integer, db.ForeignKey("distribusis.id")) - path = db.Column(db.String(4096), nullable=True, unique=False) - description = db.Column(db.String(9), nullable=True, unique=False) + path = db.Column(db.String(4096), nullable=True, unique=True) + alttext = db.Column(db.String(255), nullable=True, unique=False) tags = db.Column(db.String(500), nullable=True, unique=False) + description = db.Column(db.String(4096), nullable=True, unique=False) def __repr__(self): - return "" % self.distribusiname + return "" % self.path diff --git a/verse/models/distribusi_model.py b/verse/models/distribusi_model.py index d8f114e..dd9f040 100644 --- a/verse/models/distribusi_model.py +++ b/verse/models/distribusi_model.py @@ -11,6 +11,7 @@ class Distribusis(db.Model): userid = db.Column(db.Integer, db.ForeignKey("users.id")) category = db.Column(db.String(500), nullable=True, unique=False) year = db.Column(db.String(9), nullable=True, unique=False) + description = db.Column(db.String(32000), nullable=True, unique=False) tags = db.Column(db.String(500), nullable=True, unique=False) publictheme = db.Column(db.String(300), unique=True, nullable=True) visible = db.Column(db.Boolean, default=False) diff --git a/verse/search/forms/searchform.py b/verse/search/forms/searchform.py new file mode 100644 index 0000000..707c9b7 --- /dev/null +++ b/verse/search/forms/searchform.py @@ -0,0 +1,11 @@ +"""SearchForm to search files and distribusis in the distribusi archive""" + +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField, validators +from wtforms.validators import Length +from wtforms.widgets import TextArea + + +class SearchForm(FlaskForm): + searchfield = StringField("Search distribusi-verse archive") + submit = SubmitField("Search") diff --git a/verse/search/search.py b/verse/search/search.py new file mode 100644 index 0000000..d38a0e6 --- /dev/null +++ b/verse/search/search.py @@ -0,0 +1,42 @@ +import os +from flask import Blueprint, render_template +from whoosh.fields import * +from whoosh.index import open_dir +from whoosh.qparser import QueryParser +from search.forms.searchform import SearchForm + +searchpages = Blueprint( + "search", + __name__, + template_folder="templates/search", + static_folder="static", +) + +SCRIPT_DIR = os.path.dirname(__file__) +SEARCH_DATA_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "searchdata")) + + +@searchpages.route("/", methods=["GET", "POST"]) +def searchpage(): + searchform = SearchForm() + found_distribusis = [] + if searchform.validate_on_submit(): + found_distribusis = search(searchform.searchfield.data) + template = render_template( + "search.html", + searchform=searchform, + found_distribusis=found_distribusis, + ) + return template + + +def search(searchinput): + """search and get search result titles and return them as distribusi ids""" + ix = open_dir(SEARCH_DATA_DIR) + with ix.searcher() as searcher: + query = QueryParser("content", ix.schema).parse(searchinput) + search_results = searcher.search(query) + found_distribusis = [] + for result in search_results: + found_distribusis.append(result["title"]) + return found_distribusis diff --git a/verse/search/search_index.py b/verse/search/search_index.py new file mode 100644 index 0000000..88c9dd0 --- /dev/null +++ b/verse/search/search_index.py @@ -0,0 +1,52 @@ +import os +from whoosh.fields import * +from whoosh.index import create_in +from whoosh.qparser import QueryParser +from models.distribusi_model import Distribusis +import flask_apscheduler + + +SCRIPT_DIR = os.path.dirname(__file__) +SEARCH_DATA_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "searchdata")) + + +def init_search_index(APP): + scheduler = flask_apscheduler.APScheduler() + scheduler.api_enabled = False + scheduler.init_app(APP) + scheduler.start() + index_distribusis(APP) + index_distribusi_files(APP) + + @scheduler.task("interval", id="update", minutes=60) + def update_search_index(): + index_distribusis(APP) + index_distribusi_files(APP) + + +def index_distribusis(APP): + schema = Schema( + title=TEXT(stored=True), path=ID(stored=True), content=TEXT + ) + ix = create_in(SEARCH_DATA_DIR, schema) + writer = ix.writer() + distribusis = _visible_distribusis(APP) + for distribusi in distribusis: + writer.add_document( + title=distribusi.distribusiname, + path="/a", + content=distribusi.description, + ) + writer.commit() + + +def index_distribusi_files(APP): + APP.logger.info("searching distribusi files not implemented yet.") + + +def _visible_distribusis(APP): + with APP.app_context(): + distribusis = Distribusis.query.filter( + Distribusis.visible.isnot(False) + ).all() + return distribusis diff --git a/verse/search/templates/search/search.html b/verse/search/templates/search/search.html new file mode 100644 index 0000000..709b965 --- /dev/null +++ b/verse/search/templates/search/search.html @@ -0,0 +1,23 @@ +{% extends "base/base.html" %} +{% block main %} +
+
+ {{ searchform.csrf_token }} +
+ {{ searchform.searchfield.label }} + {{ searchform.searchfield }} + {% for message in searchform.searchfield.errors %} +
{{ message }}
+ {% endfor %} +
+
+ {{ searchform.submit }} +
+
+
+ {% for found_distribusi in found_distribusis %} + {{found_distribusi}} + {% endfor %} +
+
+{% endblock %} diff --git a/verse/settings.toml b/verse/settings.toml index 287c705..86ee959 100644 --- a/verse/settings.toml +++ b/verse/settings.toml @@ -1,4 +1,7 @@ title = "Varia Archive X Distribusi-Verse" -categories = ["event","gathering","work session","workgroup","performance","music event"] +categories = [ "article", "booklaunch", "broadcast", "curriculum", "game", +"gathering", "lecture", "opencall", "party", "performance", "presentation", +"publication", "report", "screening", "statement", "workgroup", "worksession", +"workshop"] start_time = 2017-11-03 end_time = 2025-12-31 diff --git a/verse/start.py b/verse/start.py index 5cbe8c5..368a594 100644 --- a/verse/start.py +++ b/verse/start.py @@ -11,31 +11,35 @@ from flask import ( url_for, ) from flask_login import current_user, login_required, logout_user -from flask_mail import Mail from flask_wtf.csrf import CSRFError -# Interface! these are seperate files in main folder -from adminpage import AdminPage -from app import create_app, login_manager +from admin import is_adminuser +from admin_page.admin_page import admin_page +from app import create_app, login_manager, db +from describer.describe_files import describer from distribusikan.distribusikan import distribusikan -from distribusikan.distribusisinfo import DistribusisInfo - -# Use upload form to populate filters -from forms.uploadform import UploadForm +from distribusikan.distribusis_info import DistribusisInfo +from distribusikan.forms.uploadform import UploadForm from models.distribusi_model import Distribusis from models.user_model import User from statuspengguna.forgotpassword import forgot_password from statuspengguna.helper import UserHelper from statuspengguna.loginuser import login_section from statuspengguna.registeruser import register_user +from search.search import searchpages +from search.search_index import init_search_index APP = create_app() stash_page = Blueprint("stash_page", __name__, static_folder="stash") +APP.register_blueprint(stash_page) +APP.register_blueprint(describer, url_prefix="/describer") APP.register_blueprint(login_section, url_prefix="/login") APP.register_blueprint(register_user, url_prefix="/register") APP.register_blueprint(forgot_password, url_prefix="/login/forgotpassword") -APP.register_blueprint(distribusikan) -APP.register_blueprint(stash_page) +APP.register_blueprint(admin_page, url_prefix="/admin") +APP.register_blueprint(distribusikan, url_prefix="/distribusikan") +APP.register_blueprint(searchpages, url_prefix="/search") +init_search_index(APP) @APP.before_request @@ -48,7 +52,7 @@ def session_handler(): def index(): UserHelper.reset_user_state() uploadform = UploadForm() - distribusis = DistribusisInfo.visibledistribusis() + distribusis = DistribusisInfo.visible_distribusis() distribusisindex = {} for distribusi in distribusis: user = User.query.filter_by(id=distribusi.userid).first() @@ -60,9 +64,10 @@ def index(): "tags": distribusi.tags.split(","), } distribusisindex[distribusi.distribusiname] = singledistribusi + years = uploadform.year.choices categories = uploadform.category.choices - adminuser = isadminuser() + adminuser = is_adminuser() template = render_template( "base/index.html", distribusisindex=distribusisindex, @@ -91,14 +96,6 @@ def shortstashurl(): return redirect(url_for("index")) -@APP.route("/admin", methods=["GET", "POST"]) -@login_required -def admin(): - if not isadminuser(): - return redirect(url_for("index")) - return AdminPage() - - @APP.route("/logout") @login_required def logout(): @@ -113,14 +110,7 @@ def handle_csrf_error(e): @login_manager.user_loader def load_user(user_id): - return User.query.get(int(user_id)) - - -def isadminuser(): - if not current_user.is_authenticated: - return False - user = User.query.filter_by(email=current_user.email).first() - return user.admin + return db.session.get(User, int(user_id)) if __name__ == "__main__": diff --git a/verse/static/css/dropdown.css b/verse/static/css/dropdown.css index 07509d5..6005155 100644 --- a/verse/static/css/dropdown.css +++ b/verse/static/css/dropdown.css @@ -2,7 +2,7 @@ /* for sorting on year and category */ button { - background-color: #E0B0FF; + background-color: #9de457; text-decoration: none; border: none; } @@ -26,7 +26,7 @@ button { .dropdown-content { display: none; position: absolute; - background-color: #E0B0FF; + background-color: #9de457; min-width: 120px; border: 2px solid; z-index: 1; diff --git a/verse/static/css/selector.css b/verse/static/css/selector.css index a500a61..0f9ec0c 100644 --- a/verse/static/css/selector.css +++ b/verse/static/css/selector.css @@ -4,7 +4,7 @@ max-width: 20em; position: relative; border: none; - background: #E0B0FF; + background: #9de457; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; @@ -18,7 +18,7 @@ max-width: 20em; border: none; box-shadow: none; - background-color: #E0B0FF; + background-color: #9de457; background-image: none; -webkit-appearance: none; -moz-appearance: none; @@ -41,7 +41,7 @@ } select.selector option{ color: white; - background-color: #60337F; + background-color: #9de457; padding: 0 10px; } @@ -49,5 +49,5 @@ select.selector option{ outline: none; } .selector-style select option:hover { - background: #60337F; + background: #9de457; } diff --git a/verse/static/css/style.css b/verse/static/css/style.css index 2f772a8..85aabbf 100644 --- a/verse/static/css/style.css +++ b/verse/static/css/style.css @@ -3,63 +3,16 @@ body font-family: monospace, monospace; font-size: 15px; background-color: #fdfdfd; - color:#29d148; + color:#091411; word-wrap: break-word; line-height: 1.1; } -div#login{ - width: 30%; - margin-left: auto; - margin-right: auto; - background-color:#fdfdfd; - text-decoration: none; -} - -div#login form { - width: 24em; - margin: 0 auto; - padding-left: 15%; - padding-right: 15%; -} - -input[type=text], input[type=password], input[type=file] { - color: #C397DF; - width: 18em; - max-width: 18em; - background-color: #fdfdfd; - border: 1px solid #E0B0FF; -} - -div#upload form { - padding-right: 15%; -} -.workflow{ - margin-top: 1em; - padding: 0.5em; - padding-left: auto; - padding-right: auto; - width: 31em; - background-color:#fdfdfd; - text-decoration: none; - scroll-behavior: smooth; - border-style: outset; -} -.workflow > p { - padding-left: 1em; -} -.workflow > h2 { - padding-left: 0.4em;; -} - -.workflow input{ - max-width: 20em; -} #mainworkflow { - width: 30em; + width: 40em; margin:0 auto; } @@ -69,7 +22,16 @@ div#upload form { #distribusi-index { padding-left: 1em; } - +.description > textarea { + width: 100%; + height: 10em; + resize: none; +} +textarea#description { + width: 100%; + height: 20em; + resize: none; +} div#buttons{ position: fixed; top: 0.5em; @@ -82,13 +44,13 @@ div#buttons{ div#buttons .distribusi input{ border: none; - background: #fff600; + background: #9de457; text-decoration: none; margin: 0.2em; } div#buttons .distribusi input:hover{ - background: #ffbf00; - + background: #091411; + color: #6df2cc; } fieldset.required { border: none; @@ -101,21 +63,15 @@ fieldset.required > ul { fieldset.required > ul > li{ list-style-type: none; } + fieldset.tagfield > input { width: 100%; max-width: 100%; } -#publicthemes > ul { - max-height: 20em; - overflow: auto; -} -#publicthemes > ul > li{ - word-break: break-all; -} input { border: none; - background: #E0B0FF; + background: #9de457; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; @@ -124,7 +80,9 @@ input { } input:hover { - background: #60337F; + background: #091411; + color: #6df2cc; + cursor: pointer; } input[type="submit"]:disabled:hover, @@ -144,31 +102,11 @@ input[type="submit"]:disabled:focus { background-color: #F92020; } -#update { +#update, #describe { color: black; background-color: #62b264; } -/* unvisited link */ -a:link { - color: #fff600; -} - -/* visited link */ -a:visited { - color: #d28cff; -} - -/* mouse over link */ -a:hover { - color: #60337F; -} - -/* selected link */ -a:active { - color: white; -} - /* STOLEN GOODS */ #fancyboi::before { content: "$ "; @@ -189,7 +127,7 @@ a:active { white-space: nowrap; animation: reveal 4s linear; text-overflow: "█"; - background-color: #2D3039; + background-color: #9de457; } #fancyboi::after { content: "█"; @@ -199,7 +137,7 @@ a:active { div.maincontent{ width: 55%; - border: 3px #E0B0FF; + border: 3px #9de457; margin-top: 0.5em; padding: 0.5em; border-style: outset; @@ -238,8 +176,6 @@ div.maincontent{ bottom: 100%; left: 50%; margin-left: -60px; - - /* Fade in tooltip - takes 1 second to go from 0% to 100% opac: */ opacity: 0; transition: opacity 2s; } @@ -254,7 +190,7 @@ div.maincontent{ color: black; padding: 1em; box-sizing: border-box; - background: #E0B0FF; + background: #9de457; outline: none; font-family: Courier, sans-serif; font-size: 16px; @@ -262,11 +198,11 @@ div.maincontent{ /* Project colors so far. light -#E0B0FF +#9de457 medium #d28cff dark -#60337F +#9de457 background dark #2D3039 diff --git a/verse/statuspengguna/forgotpassword.py b/verse/statuspengguna/forgotpassword.py index dbb8049..3137e1f 100644 --- a/verse/statuspengguna/forgotpassword.py +++ b/verse/statuspengguna/forgotpassword.py @@ -11,7 +11,7 @@ from sqlalchemy.exc import ( ) from app import db, get_app -from forms.forgotpasswordform import ForgotPasswordForm +from statuspengguna.forms.forgotpasswordform import ForgotPasswordForm from models.user_model import User mail = Mail(get_app()) diff --git a/verse/forms/forgotpasswordform.py b/verse/statuspengguna/forms/forgotpasswordform.py similarity index 100% rename from verse/forms/forgotpasswordform.py rename to verse/statuspengguna/forms/forgotpasswordform.py diff --git a/verse/forms/loginform.py b/verse/statuspengguna/forms/loginform.py similarity index 100% rename from verse/forms/loginform.py rename to verse/statuspengguna/forms/loginform.py diff --git a/verse/forms/registerform.py b/verse/statuspengguna/forms/registerform.py similarity index 93% rename from verse/forms/registerform.py rename to verse/statuspengguna/forms/registerform.py index cca23ab..89c42d6 100644 --- a/verse/forms/registerform.py +++ b/verse/statuspengguna/forms/registerform.py @@ -2,7 +2,7 @@ from flask_wtf import FlaskForm from wtforms import PasswordField, StringField, SubmitField, validators -from wtforms.validators import Email, EqualTo, Length, ValidationError +from wtforms.validators import Email, EqualTo, Length class RegisterForm(FlaskForm): diff --git a/verse/forms/resetpasswordform.py b/verse/statuspengguna/forms/resetpasswordform.py similarity index 100% rename from verse/forms/resetpasswordform.py rename to verse/statuspengguna/forms/resetpasswordform.py diff --git a/verse/statuspengguna/helper.py b/verse/statuspengguna/helper.py index a8b26bd..c227155 100644 --- a/verse/statuspengguna/helper.py +++ b/verse/statuspengguna/helper.py @@ -10,7 +10,7 @@ from sqlalchemy.exc import ( ) from app import db -from distribusikan.distribusisinfo import DistribusisInfo +from distribusikan.distribusis_info import DistribusisInfo from models.distribusi_model import Distribusis from models.user_model import User @@ -76,7 +76,9 @@ class UserHelper: def distribusi_limit_reached(): user = User.query.filter_by(email=current_user.email).first() - distribusiamount = len(DistribusisInfo.getuserdistribusis(user.email)) + distribusiamount = len( + DistribusisInfo.get_user_distribusis(user.email) + ) if distribusiamount > 19: print("user already has 20 distribusis") return True diff --git a/verse/statuspengguna/loginuser.py b/verse/statuspengguna/loginuser.py index db08cac..ba28c72 100644 --- a/verse/statuspengguna/loginuser.py +++ b/verse/statuspengguna/loginuser.py @@ -5,14 +5,12 @@ from flask import ( redirect, render_template, request, - send_from_directory, - session, url_for, ) from flask_bcrypt import check_password_hash from flask_login import login_user -from forms.loginform import LoginForm +from statuspengguna.forms.loginform import LoginForm from models.user_model import User login_section = Blueprint( @@ -37,7 +35,6 @@ def LoginUser(): loginform.password.errors.append("Invalid email or password!") return render_template("login.html", loginform=loginform) if check_password_hash(user.password, loginform.password.data): - print(type(user)) login_user(user) flash("Logged in successfully.", "success") next = request.args.get("next") diff --git a/verse/statuspengguna/registeruser.py b/verse/statuspengguna/registeruser.py index e97f1ee..af1216f 100644 --- a/verse/statuspengguna/registeruser.py +++ b/verse/statuspengguna/registeruser.py @@ -11,7 +11,7 @@ from sqlalchemy.exc import ( from werkzeug.routing import BuildError from app import db -from forms.registerform import RegisterForm +from statuspengguna.forms.registerform import RegisterForm from models.user_model import User register_user = Blueprint( diff --git a/verse/statuspengguna/resetpassword.py b/verse/statuspengguna/resetpassword.py index a75f86e..a9fc1b5 100644 --- a/verse/statuspengguna/resetpassword.py +++ b/verse/statuspengguna/resetpassword.py @@ -1,6 +1,6 @@ from datetime import datetime -from flask import flash, redirect, render_template, url_for +from flask import Blueprint, flash, redirect, render_template, url_for from flask_bcrypt import generate_password_hash from flask_login import login_user from sqlalchemy.exc import ( @@ -13,9 +13,8 @@ from sqlalchemy.exc import ( from werkzeug.routing import BuildError from app import db -from forms.resetpasswordform import ResetPasswordForm +from statuspengguna.forms.resetpasswordform import ResetPasswordForm from models.user_model import User -from statuspengguna import statuspengguna reset_password = Blueprint( "reset_password", diff --git a/verse/statuspengguna/static/css/dropdown.css b/verse/statuspengguna/static/css/dropdown.css deleted file mode 100644 index 07509d5..0000000 --- a/verse/statuspengguna/static/css/dropdown.css +++ /dev/null @@ -1,69 +0,0 @@ -/* Dropdown Button */ -/* for sorting on year and category -*/ -button { - background-color: #E0B0FF; - text-decoration: none; - border: none; -} -.filter { - display: none; -} - -.activebtn { - background-color: #62b264; -} - -.show { - display: block; -} -.dropdown { - position: relative; - display: inline-block; -} - -/* Dropdown Content (Hidden by Default) */ -.dropdown-content { - display: none; - position: absolute; - background-color: #E0B0FF; - min-width: 120px; - border: 2px solid; - z-index: 1; - border-style: outset; -} - -/* Links inside the dropdown */ -.dropdown-content button { - color: black; - padding: 6px; - border: none; - min-width: inherit; - text-align: left; - text-decoration: none; - display: block; -} -.dropbtn { - margin-top: 1em; -} -/* Change color of dropdown links on hover */ -.dropdown-content button:hover {background-color: #62b264;} - - -/* Show the dropdown menu on hover */ -.dropdown:hover .dropdown-content {display: block;} - -/* Change the background color of the dropdown button when the dropdown content is shown */ -.dropdown:hover .dropbtn {background-color: #62b264;} - -@media only screen and (min-device-width: 320px) and (max-device-width: 480px) { - .dropdown-content button { - font-size: 0.7em; - } - .container > button { - font-size: 0.7em; - } - .dropdown > button { - font-size: 0.7em; - } -} diff --git a/verse/statuspengguna/static/css/editor.css b/verse/statuspengguna/static/css/editor.css deleted file mode 100644 index d087622..0000000 --- a/verse/statuspengguna/static/css/editor.css +++ /dev/null @@ -1,50 +0,0 @@ -.editareas { - margin: auto; - display: flex; - justify-content: flex-start; -} -.editarea { - width: 30%; - border: 3px solid #E0B0FF; - border-style: outset; - margin-right: 1em; - margin-left: 0; -} - -.editor { - min-width: 35%; -} -.editform { - width: 100%%; - margin: 0 auto; -} -#editorsubmitform { - padding-top: 1em; -} -.required label { - display: block; - padding-bottom: 2px; - width: 100% -} -textarea { - width: 100%; - height: 100%; - box-sizing: border-box; - min-height: 250px; - background: #E0B0FF; - outline: none; - font-family: Courier, sans-serif; - font-size: 16px; -} - -iframe { - bottom: 0; - position: relative; - margin-top: 1em; - width: 100%; - height: 30em; -} -#html { - background-color: #60337F; - color: lightgrey; -} diff --git a/verse/statuspengguna/static/css/login.css b/verse/statuspengguna/static/css/login.css new file mode 100644 index 0000000..74308d0 --- /dev/null +++ b/verse/statuspengguna/static/css/login.css @@ -0,0 +1,22 @@ +div#login{ + width: 30%; + margin-left: auto; + margin-right: auto; + background-color:#fdfdfd; + text-decoration: none; +} + +div#login form { + width: 24em; + margin: 0 auto; + padding-left: 15%; + padding-right: 15%; +} + +input[type=text], input[type=password], input[type=file] { + color: #091411; + width: 18em; + max-width: 18em; + background-color: #fdfdfd; + border: 1px solid #9de457; +} diff --git a/verse/statuspengguna/static/css/selector.css b/verse/statuspengguna/static/css/selector.css deleted file mode 100644 index a500a61..0000000 --- a/verse/statuspengguna/static/css/selector.css +++ /dev/null @@ -1,53 +0,0 @@ -.selector-style { - padding: 0; - width: 20em; - max-width: 20em; - position: relative; - border: none; - background: #E0B0FF; - text-decoration: none; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - margin: 1px; -} - -.selector-style select { - padding: 0.2em 0.2em; - width: 20em; - max-width: 20em; - border: none; - box-shadow: none; - background-color: #E0B0FF; - background-image: none; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.selector-style:after { - top: 50%; - left: 95%; - border: solid; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(0, 0, 0, 0); - border-top-color: #000000; - margin-top: -2px; - z-index: 100; -} -select.selector option{ - color: white; - background-color: #60337F; - padding: 0 10px; -} - -.selector-style select:focus { - outline: none; -} -.selector-style select option:hover { - background: #60337F; -} diff --git a/verse/statuspengguna/static/css/style.css b/verse/statuspengguna/static/css/style.css deleted file mode 100644 index fb743fc..0000000 --- a/verse/statuspengguna/static/css/style.css +++ /dev/null @@ -1,281 +0,0 @@ -body -{ - font-family: monospace, monospace; - font-size: 15px; - background-color: #fdfdfd; - color:#29d148; - word-wrap: break-word; - line-height: 1.1; -} - -div#login{ - width: 30%; - margin-left: auto; - margin-right: auto; - background-color:#fdfdfd; - text-decoration: none; -} - -div#login form { - width: 24em; - margin: 0 auto; - padding-left: 15%; - padding-right: 15%; -} - -input[type=text], input[type=password], input[type=file] { - color: #C397DF; - width: 18em; - max-width: 18em; - background-color: #fdfdfd; - border: 1px solid #E0B0FF; -} - -div#upload form { - padding-right: 15%; -} - -.workflow{ - margin-top: 1em; - padding: 0.5em; - padding-left: auto; - padding-right: auto; - width: 31em; - background-color:#fdfdfd; - text-decoration: none; - scroll-behavior: smooth; - border-style: outset; -} -.workflow > p { - padding-left: 1em; -} -.workflow > h2 { - padding-left: 0.4em;; -} - -.workflow input{ - max-width: 20em; -} - -#mainworkflow -{ - width: 30em; - margin:0 auto; -} - -#distribusiverse { - margin-bottom: 11em; -} -#distribusi-index { - padding-left: 1em; -} - -div#buttons{ - position: fixed; - top: 0.5em; - right: 0.5em; - display:flex; - flex-direction: row; - justify-content: center; - align-items: center; -} - -div#buttons .distribusi input{ - border: none; - background: #fff600; - text-decoration: none; - margin: 0.2em; -} -div#buttons .distribusi input:hover{ - background: #ffbf00; - -} -fieldset.required { - border: none; -} - -fieldset.required > ul { - padding-left: 0px; -} - -fieldset.required > ul > li{ - list-style-type: none; -} -fieldset.tagfield > input { - width: 100%; - max-width: 100%; -} -#publicthemes > ul { - max-height: 20em; - overflow: auto; -} -#publicthemes > ul > li{ - word-break: break-all; -} - -input { - border: none; - background: #E0B0FF; - text-decoration: none; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - margin: 0.2em; -} - -input:hover { - background: #60337F; -} - -input[type="submit"]:disabled:hover, -input[type="submit"]:disabled, -input[type="submit"]:disabled:focus { - background-color: #2D3039; - color: #d28cff; -} - -.error { - font-size: 110%; - color: #F92020; -} - -#delete { - color: black; - background-color: #F92020; -} - -#update { - color: black; - background-color: #62b264; -} - - -/* unvisited link */ -a:link { - color: #fff600; -} - -/* visited link */ -a:visited { - color: #d28cff; -} - -/* mouse over link */ -a:hover { - color: #60337F; -} - -/* selected link */ -a:active { - color: white; -} - -/* STOLEN GOODS */ -#fancyboi::before { - content: "$ "; -} - -@media (prefers-reduced-motion: no-preference) { - @keyframes flash { - 50% { opacity: 0; } - } - @keyframes reveal { - from { width: 2em; } /* Width of ::before */ - to { width: 55%; } - } - #fancyboi { - width: 55%; - padding: 0.5em; - overflow: hidden; - white-space: nowrap; - animation: reveal 4s linear; - text-overflow: "█"; - background-color: #2D3039; - } - #fancyboi::after { - content: "█"; - animation: flash 0.5s step-end infinite; - } -} - -div.maincontent{ - width: 55%; - border: 3px #E0B0FF; - margin-top: 0.5em; - padding: 0.5em; - border-style: outset; -} - -.tags{ - background-color: #000; - color: #fff; - display: inline-block; - padding-left: 4px; - padding-right: 4px; - text-align: center; - margin: 1px; -} - -.searched { - background: #fff600 !important; - color: black !important; -} - -.tooltip { - position: relative; - display: inline-block; - border-bottom: 1px dotted black; -} - -.tooltip .tooltiptext { - visibility: hidden; - width: 120px; - background-color: black; - color: #fff; - text-align: center; - padding: 5px 0; - position: absolute; - z-index: 1; - bottom: 100%; - left: 50%; - margin-left: -60px; - - /* Fade in tooltip - takes 1 second to go from 0% to 100% opac: */ - opacity: 0; - transition: opacity 2s; -} - -.tooltip:hover .tooltiptext { - visibility: visible; - opacity: 1; -} - -.code-example { - width: 100%; - color: black; - padding: 1em; - box-sizing: border-box; - background: #E0B0FF; - outline: none; - font-family: Courier, sans-serif; - font-size: 16px; -} -/* -Project colors so far. -light -#E0B0FF -medium -#d28cff -dark -#60337F - -background dark -#2D3039 - -yellow important -#fff600 - -red: danger -ff5a5a -backgrounds -*/ diff --git a/verse/statuspengguna/static/icons/about.txt b/verse/statuspengguna/static/icons/about.txt deleted file mode 100644 index f6a9f45..0000000 --- a/verse/statuspengguna/static/icons/about.txt +++ /dev/null @@ -1,6 +0,0 @@ -This favicon was generated using the following font: - -- Font Title: Klee One -- Font Author: Copyright 2020 The Klee Project Authors (https://github.com/fontworks-fonts/Klee) -- Font Source: http://fonts.gstatic.com/s/kleeone/v5/LDIxapCLNRc6A8oT4q4AOeekWPrP.ttf -- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL)) diff --git a/verse/statuspengguna/static/icons/android-chrome-192x192.png b/verse/statuspengguna/static/icons/android-chrome-192x192.png deleted file mode 100644 index 3b958ff..0000000 Binary files a/verse/statuspengguna/static/icons/android-chrome-192x192.png and /dev/null differ diff --git a/verse/statuspengguna/static/icons/android-chrome-512x512.png b/verse/statuspengguna/static/icons/android-chrome-512x512.png deleted file mode 100644 index 1d68c63..0000000 Binary files a/verse/statuspengguna/static/icons/android-chrome-512x512.png and /dev/null differ diff --git a/verse/statuspengguna/static/icons/apple-touch-icon.png b/verse/statuspengguna/static/icons/apple-touch-icon.png deleted file mode 100644 index 97255bd..0000000 Binary files a/verse/statuspengguna/static/icons/apple-touch-icon.png and /dev/null differ diff --git a/verse/statuspengguna/static/icons/favicon-16x16.png b/verse/statuspengguna/static/icons/favicon-16x16.png deleted file mode 100644 index 05a6e48..0000000 Binary files a/verse/statuspengguna/static/icons/favicon-16x16.png and /dev/null differ diff --git a/verse/statuspengguna/static/icons/favicon-32x32.png b/verse/statuspengguna/static/icons/favicon-32x32.png deleted file mode 100644 index 8478c1e..0000000 Binary files a/verse/statuspengguna/static/icons/favicon-32x32.png and /dev/null differ diff --git a/verse/statuspengguna/static/icons/favicon.ico b/verse/statuspengguna/static/icons/favicon.ico deleted file mode 100644 index f3757b9..0000000 Binary files a/verse/statuspengguna/static/icons/favicon.ico and /dev/null differ diff --git a/verse/statuspengguna/static/icons/site.webmanifest b/verse/statuspengguna/static/icons/site.webmanifest deleted file mode 100644 index 45dc8a2..0000000 --- a/verse/statuspengguna/static/icons/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/verse/statuspengguna/static/js/dropdown.js b/verse/statuspengguna/static/js/dropdown.js deleted file mode 100644 index 505d4a8..0000000 --- a/verse/statuspengguna/static/js/dropdown.js +++ /dev/null @@ -1,92 +0,0 @@ -filterSelection("all", "None"); -function filterSelection(c, name, id) { - resetDropDownButtons(); - var i; - var button = document.getElementById(id); - if(button){ - button.innerText = name; - addClass(button, "activebtn"); - } - var alldistribusis = document.getElementsByClassName("filter"); - if (c == "all") { - for (i = 0; i < alldistribusis.length; i++) { - addClass(alldistribusis[i], "show"); - } - } - else { - for (i = 0; i < alldistribusis.length; i++) { - removeClass(alldistribusis[i], "show"); - if (alldistribusis[i].className.indexOf(c) > -1) { - addClass(alldistribusis[i], "show"); - } - } - } -} - -function resetDropDownButtons(){ - document.getElementById("Year").innerText = "Year"; - document.getElementById("Category").innerText = "Category"; - allactivebuttons = document.getElementsByClassName("activebtn"); - for(var i = 0;allactivebuttons.length; i++) { - removeClass(allactivebuttons[i], "activebtn"); - } -} -function addClass(element, name) { - var i, arr1, arr2; - arr1 = element.className.split(" "); - arr2 = name.split(" "); - for (i = 0; i < arr2.length; i++) { - if (arr1.indexOf(arr2[i]) == -1) {element.className += " " + arr2[i];} - } -} - -function removeClass(element, name) { - var i, arr1, arr2; - arr1 = element.className.split(" "); - arr2 = name.split(" "); - for (i = 0; i < arr2.length; i++) { - while (arr1.indexOf(arr2[i]) > -1) { - arr1.splice(arr1.indexOf(arr2[i]), 1); - } - } - element.className = arr1.join(" "); -} - - -let searchInput = document.getElementById('tagsearch'); -let timeout = null; -// Listen for keystroke events -searchInput.addEventListener('keyup', function (e) { - // Clear the timeout if it has already been set. - clearTimeout(timeout); - // Make a new timeout set to go off in 1000ms (1 second) - timeout = setTimeout(function () { - console.log('Input Value:', searchInput.value); - if (searchInput.value.length > 2) { - searchTags(searchInput.value); - } else { - clearSearchTags(); - } - }, 1000); -}); - -function searchTags(searchInput) { - let tag_ele = document.getElementsByClassName('tags'); - for (var i = 0; i < tag_ele.length; ++i) { - let searchText = searchInput.toLowerCase().trim(); - let tagtext = tag_ele[i].innerText.toLowerCase(); - if(searchText.includes(tagtext) || tagtext.includes(searchText)) { - addClass(tag_ele[i], "searched"); - } - else { - removeClass(tag_ele[i], "searched"); - } - } -} - -function clearSearchTags() { - let tag_ele = document.getElementsByClassName('tags'); - for (var i = 0; i < tag_ele.length; ++i) { - removeClass(tag_ele[i], "searched"); - } -} diff --git a/verse/statuspengguna/static/js/editorupdate.js b/verse/statuspengguna/static/js/editorupdate.js deleted file mode 100644 index f76219e..0000000 --- a/verse/statuspengguna/static/js/editorupdate.js +++ /dev/null @@ -1,19 +0,0 @@ -function update() { - -var html = document.getElementById("html"); -var css = document.getElementById("css"); -var code = document.getElementById("code").contentWindow.document; - -document.body.onkeyup = function(){ - code.open(); - code.writeln(html.value+""); - code.close(); - }; -document.addEventListener("DOMContentLoaded", function(){ - code.open(); - code.writeln(html.value+""); - code.close(); - }); -}; - -update(); diff --git a/verse/statuspengguna/static/js/script.js b/verse/statuspengguna/static/js/script.js deleted file mode 100644 index 2bd662b..0000000 --- a/verse/statuspengguna/static/js/script.js +++ /dev/null @@ -1,25 +0,0 @@ -console.log("everything is still smooth") - -function scrollToTheme() { - var uploadsuccessful = document.getElementById("uploadsuccessful"); - if(uploadsuccessful){ - const theme = document.getElementById('theme') - theme.scrollIntoView({ behavior: 'smooth', block: 'start' }); - } -} - -function scrollToLaunch() { - var cssSelected = document.getElementById("cssSelected"); - if(cssSelected){ - const launch = document.getElementById('launch') - launch.scrollIntoView({ behavior: 'smooth', block: 'end' }); - } -} - - -document.addEventListener("DOMContentLoaded", scrollToTheme); -document.addEventListener("DOMContentLoaded", scrollToLaunch); - -// function(e) { -// (e.keyCode === 13 || e.keyCode === 32) && $(this).trigger("click") -// } diff --git a/verse/statuspengguna/static/svg/arrow_1.svg b/verse/statuspengguna/static/svg/arrow_1.svg deleted file mode 100644 index 21073fd..0000000 --- a/verse/statuspengguna/static/svg/arrow_1.svg +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/verse/statuspengguna/static/svg/arrow_2.svg b/verse/statuspengguna/static/svg/arrow_2.svg deleted file mode 100644 index ea2a026..0000000 --- a/verse/statuspengguna/static/svg/arrow_2.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/verse/statuspengguna/static/svg/arrow_3.svg b/verse/statuspengguna/static/svg/arrow_3.svg deleted file mode 100644 index c447811..0000000 --- a/verse/statuspengguna/static/svg/arrow_3.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/verse/statuspengguna/templates/statuspengguna/forgotpassword.html b/verse/statuspengguna/templates/statuspengguna/forgotpassword.html index bed8afc..59416fc 100644 --- a/verse/statuspengguna/templates/statuspengguna/forgotpassword.html +++ b/verse/statuspengguna/templates/statuspengguna/forgotpassword.html @@ -1,7 +1,7 @@ {% extends "base/base.html" %} {% block main %}
-
+
- + {% endblock main %} diff --git a/verse/statuspengguna/templates/statuspengguna/login.html b/verse/statuspengguna/templates/statuspengguna/login.html index 70a02b2..6cde1d3 100644 --- a/verse/statuspengguna/templates/statuspengguna/login.html +++ b/verse/statuspengguna/templates/statuspengguna/login.html @@ -23,4 +23,5 @@ + {% endblock main %} diff --git a/verse/statuspengguna/templates/statuspengguna/register.html b/verse/statuspengguna/templates/statuspengguna/register.html index dcdcbad..8a3b152 100644 --- a/verse/statuspengguna/templates/statuspengguna/register.html +++ b/verse/statuspengguna/templates/statuspengguna/register.html @@ -36,4 +36,5 @@ + {% endblock main %} diff --git a/verse/statuspengguna/templates/statuspengguna/resetpassword.html b/verse/statuspengguna/templates/statuspengguna/resetpassword.html index bf2438e..e97dfc0 100644 --- a/verse/statuspengguna/templates/statuspengguna/resetpassword.html +++ b/verse/statuspengguna/templates/statuspengguna/resetpassword.html @@ -26,4 +26,5 @@

Password reset link no longer valid.

{% endif %} + {% endblock main %} diff --git a/verse/templates/base/help.html b/verse/templates/base/help.html index 2abef0c..8858b58 100644 --- a/verse/templates/base/help.html +++ b/verse/templates/base/help.html @@ -19,7 +19,7 @@ {% else %} diff --git a/verse/templates/base/index.html b/verse/templates/base/index.html index e828dcd..65ed3b4 100644 --- a/verse/templates/base/index.html +++ b/verse/templates/base/index.html @@ -15,7 +15,7 @@ {% else %} diff --git a/verse/themes/editor/placeholder.html b/verse/themes/editor/placeholder.html index ffbc168..8846a56 100644 --- a/verse/themes/editor/placeholder.html +++ b/verse/themes/editor/placeholder.html @@ -6,14 +6,14 @@
example_video.mp4