diff --git a/verse/adminpage.py b/verse/adminpage.py index c12fac3..7504d30 100644 --- a/verse/adminpage.py +++ b/verse/adminpage.py @@ -1,15 +1,16 @@ import os import shutil -from app import db -from distribusisinfo import DistribusisInfo from flask import render_template +from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, + InvalidRequestError) + +from app import db +from distribusikan.distribusisinfo import DistribusisInfo from forms.admindistribusiform import AdminDistribusiForm from forms.adminuserform import AdminUserForm from models.distribusimodel import Distribusis from models.usermodel import User -from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, - InvalidRequestError) def AdminPage(): diff --git a/verse/admintool.py b/verse/admintool.py index 8fc9e2e..21aa782 100644 --- a/verse/admintool.py +++ b/verse/admintool.py @@ -1,10 +1,11 @@ import sys +from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, + InvalidRequestError) + from app import create_app, db from models.distribusimodel import Distribusis # noqa: F401 from models.usermodel import User # noqa: F401 -from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, - InvalidRequestError) def admintool(): diff --git a/verse/app.py b/verse/app.py index 8112e94..56dd762 100644 --- a/verse/app.py +++ b/verse/app.py @@ -16,7 +16,7 @@ login_manager = LoginManager() def create_app(): - APP.secret_key = "secret-key" + 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 @@ -59,6 +59,10 @@ def settings(): return APP +def get_app(): + return APP + + def settings_from_file(): settings = {} if os.path.isfile("settings_development.toml"): diff --git a/verse/deploydb.py b/verse/deploydb.py index 6ebd4eb..26c2e5b 100644 --- a/verse/deploydb.py +++ b/verse/deploydb.py @@ -1,7 +1,8 @@ def deploy(): """Run deployment of database.""" - from app import create_app, db from flask_migrate import init, migrate, stamp, upgrade + + from app import create_app, db from models.distribusimodel import Distribusis # noqa: F401 # This model is required for flask_migrate to make the table from models.usermodel import User # noqa: F401 diff --git a/verse/distribusikan/distribusikan.py b/verse/distribusikan/distribusikan.py new file mode 100644 index 0000000..6350228 --- /dev/null +++ b/verse/distribusikan/distribusikan.py @@ -0,0 +1,46 @@ +from flask import Blueprint +from flask_login import login_required + +from distribusikan.distribusiselector import DistribusiSelector +# 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 + +distribusikan = Blueprint( + "distribusikan", + __name__, + template_folder="templates/distribusikan", + static_folder="static", +) + + +@distribusikan.route("/distribusi", methods=["GET", "POST"]) +@login_required +def distribusi(): + return DistribusiWorkflow() + + +@distribusikan.route("/upload", methods=["POST"]) +@login_required +def upload(): + return UploadPage() + + +@distribusikan.route("/theme", methods=["GET", "POST"]) +@login_required +def theme(): + return ThemeSelector() + +@distribusikan.route("/editor", methods=["GET", "POST"]) +@login_required +def editor(): + return Editor() + + +@distribusikan.route("/selector", methods=["GET", "POST"]) +@login_required +def selector(): + return DistribusiSelector() diff --git a/verse/distribusiselector.py b/verse/distribusikan/distribusiselector.py similarity index 98% rename from verse/distribusiselector.py rename to verse/distribusikan/distribusiselector.py index 3a5d72f..64a8ef4 100644 --- a/verse/distribusiselector.py +++ b/verse/distribusikan/distribusiselector.py @@ -1,10 +1,13 @@ import os import shutil -from app import db -from distribusisinfo import DistribusisInfo from flask import flash, render_template from flask_login import current_user +from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, + InvalidRequestError) + +from app import db +from distribusikan.distribusisinfo import DistribusisInfo from forms.distribusiform import DistribusiForm from forms.publicthemeform import PublicThemeForm from forms.selectorform import SelectorForm @@ -12,8 +15,6 @@ from forms.themeform import ThemeForm from forms.uploadform import UploadForm from models.distribusimodel import Distribusis from models.usermodel import User -from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, - InvalidRequestError) # UserPengguna from statuspengguna.helper import UserHelper diff --git a/verse/distribusisinfo.py b/verse/distribusikan/distribusisinfo.py similarity index 99% rename from verse/distribusisinfo.py rename to verse/distribusikan/distribusisinfo.py index 0b40c1b..5a47d5f 100644 --- a/verse/distribusisinfo.py +++ b/verse/distribusikan/distribusisinfo.py @@ -1,4 +1,5 @@ from flask_login import current_user + from models.distribusimodel import Distribusis from models.usermodel import User diff --git a/verse/distribusiworkflow.py b/verse/distribusikan/distribusiworkflow.py similarity index 97% rename from verse/distribusiworkflow.py rename to verse/distribusikan/distribusiworkflow.py index f073232..bd7260f 100644 --- a/verse/distribusiworkflow.py +++ b/verse/distribusikan/distribusiworkflow.py @@ -2,13 +2,17 @@ import os import shutil import zipfile -from app import db # Tada! from distribusi.cli import build_argparser -from distribusiselector import SelectorVisible -from distribusisinfo import DistribusisInfo +from distribusi.distribusi import distribusify from flask import flash, redirect, render_template, url_for from flask_login import current_user +from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, + InvalidRequestError) + +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 @@ -17,13 +21,9 @@ from forms.themeform import ThemeForm from forms.uploadform import UploadForm from models.distribusimodel import Distribusis from models.usermodel import User -from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, - InvalidRequestError) # UserPengguna from statuspengguna.helper import UserHelper -from distribusi.distribusi import distribusify - def DistribusiWorkflow(): distribusiform = DistribusiForm() diff --git a/verse/editor.py b/verse/distribusikan/editor.py similarity index 99% rename from verse/editor.py rename to verse/distribusikan/editor.py index bfbfaeb..8fb0c9c 100644 --- a/verse/editor.py +++ b/verse/distribusikan/editor.py @@ -2,10 +2,14 @@ import os import shutil import bleach -from app import db from bleach_allowlist import all_styles -from distribusisinfo import DistribusisInfo from flask import render_template +from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, + InvalidRequestError) +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 @@ -13,10 +17,7 @@ from forms.selectorform import SelectorForm from forms.themeform import ThemeForm from forms.uploadform import UploadForm from models.distribusimodel import Distribusis -from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, - InvalidRequestError) from statuspengguna.helper import UserHelper -from werkzeug.utils import secure_filename def Editor(): diff --git a/verse/templates/distribusi.html b/verse/distribusikan/templates/distribusikan/distribusi.html similarity index 97% rename from verse/templates/distribusi.html rename to verse/distribusikan/templates/distribusikan/distribusi.html index 8182e00..e85f04c 100644 --- a/verse/templates/distribusi.html +++ b/verse/distribusikan/templates/distribusikan/distribusi.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
diff --git a/verse/templates/distribusiworkflow/editcss.html b/verse/distribusikan/templates/distribusikan/distribusiworkflow/editcss.html similarity index 100% rename from verse/templates/distribusiworkflow/editcss.html rename to verse/distribusikan/templates/distribusikan/distribusiworkflow/editcss.html diff --git a/verse/templates/distribusiworkflow/launch.html b/verse/distribusikan/templates/distribusikan/distribusiworkflow/launch.html similarity index 95% rename from verse/templates/distribusiworkflow/launch.html rename to verse/distribusikan/templates/distribusikan/distribusiworkflow/launch.html index 3c4685a..562b616 100644 --- a/verse/templates/distribusiworkflow/launch.html +++ b/verse/distribusikan/templates/distribusikan/distribusiworkflow/launch.html @@ -3,7 +3,7 @@

Run distribusi on your files. This will generate your website and make your content public. Distribusi will unpack your zip file and turn it into a website!

-
+ {{ distribusiform.csrf_token }} {% if files_uploaded or distribusi_live %}
diff --git a/verse/templates/distribusiworkflow/selector.html b/verse/distribusikan/templates/distribusikan/distribusiworkflow/selector.html similarity index 97% rename from verse/templates/distribusiworkflow/selector.html rename to verse/distribusikan/templates/distribusikan/distribusiworkflow/selector.html index 44d6da4..88dac97 100644 --- a/verse/templates/distribusiworkflow/selector.html +++ b/verse/distribusikan/templates/distribusikan/distribusiworkflow/selector.html @@ -1,7 +1,7 @@

Welcome back to your Distribusi

You have already uploaded a distribusi website:

- + {{ selectorform.csrf_token }}
{{ selectorform.distribusis.label }} diff --git a/verse/templates/distribusiworkflow/theme.html b/verse/distribusikan/templates/distribusikan/distribusiworkflow/theme.html similarity index 95% rename from verse/templates/distribusiworkflow/theme.html rename to verse/distribusikan/templates/distribusikan/distribusiworkflow/theme.html index 2b92907..e6a7b1e 100644 --- a/verse/templates/distribusiworkflow/theme.html +++ b/verse/distribusikan/templates/distribusikan/distribusiworkflow/theme.html @@ -4,7 +4,7 @@ step 3.

Don't forget to press Save


- + {{ themeform.csrf_token }}
{{ themeform.theme.label }} @@ -23,7 +23,7 @@ {% endif %}
-
+ {{ publicthemeform.csrf_token }}
{{ publicthemeform.publicthemes.label }} diff --git a/verse/templates/distribusiworkflow/upload.html b/verse/distribusikan/templates/distribusikan/distribusiworkflow/upload.html similarity index 97% rename from verse/templates/distribusiworkflow/upload.html rename to verse/distribusikan/templates/distribusikan/distribusiworkflow/upload.html index 1dba794..fe3aa78 100644 --- a/verse/templates/distribusiworkflow/upload.html +++ b/verse/distribusikan/templates/distribusikan/distribusiworkflow/upload.html @@ -1,7 +1,7 @@

Step 1: Upload

Upload your files here:

- + {{ uploadform.csrf_token }}
{{ uploadform.sitename.label }} diff --git a/verse/templates/editor.html b/verse/distribusikan/templates/distribusikan/editor.html similarity index 98% rename from verse/templates/editor.html rename to verse/distribusikan/templates/distribusikan/editor.html index 69fc8e8..7ce1c24 100644 --- a/verse/templates/editor.html +++ b/verse/distribusikan/templates/distribusikan/editor.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
diff --git a/verse/themeselector.py b/verse/distribusikan/themeselector.py similarity index 97% rename from verse/themeselector.py rename to verse/distribusikan/themeselector.py index 68e2e1b..96b2d8a 100644 --- a/verse/themeselector.py +++ b/verse/distribusikan/themeselector.py @@ -1,8 +1,9 @@ import os import shutil -from distribusisinfo import DistribusisInfo 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 diff --git a/verse/upload.py b/verse/distribusikan/upload.py similarity index 97% rename from verse/upload.py rename to verse/distribusikan/upload.py index a332413..32d8eaa 100644 --- a/verse/upload.py +++ b/verse/distribusikan/upload.py @@ -1,15 +1,16 @@ import os import shutil -from app import db -from distribusiselector import SelectCurrentDistribusi from flask import flash from flask_login import current_user +from sqlalchemy.exc import (DatabaseError, DataError, IntegrityError, + InterfaceError, InvalidRequestError) + +from app import db +from distribusikan.distribusiselector import SelectCurrentDistribusi from forms.uploadform import UploadForm from models.distribusimodel import Distribusis from models.usermodel import User -from sqlalchemy.exc import (DatabaseError, DataError, IntegrityError, - InterfaceError, InvalidRequestError) from statuspengguna.helper import UserHelper diff --git a/verse/uploadpage.py b/verse/distribusikan/uploadpage.py similarity index 89% rename from verse/uploadpage.py rename to verse/distribusikan/uploadpage.py index 8718ec2..aaf9e25 100644 --- a/verse/uploadpage.py +++ b/verse/distribusikan/uploadpage.py @@ -1,14 +1,15 @@ -from app import APP -from distribusiselector import SelectorVisible -from distribusisinfo import DistribusisInfo 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 # UserPengguna from statuspengguna.helper import UserHelper -from upload import UploadNewDistribusi, UploadUpdatedFiles def UploadPage(): diff --git a/verse/forms/uploadform.py b/verse/forms/uploadform.py index 89e56f4..0d9b00a 100644 --- a/verse/forms/uploadform.py +++ b/verse/forms/uploadform.py @@ -1,4 +1,3 @@ -from app import settings from flask_wtf import FlaskForm from flask_wtf.file import FileAllowed, FileField, FileRequired, FileSize from wtforms import (IntegerField, SelectField, StringField, SubmitField, @@ -6,6 +5,8 @@ from wtforms import (IntegerField, SelectField, StringField, SubmitField, from wtforms.validators import (DataRequired, Length, NumberRange, ValidationError) +from app import settings + class UploadForm(FlaskForm): """File upload class for a new site in distribusi-verse""" diff --git a/verse/models/usermodel.py b/verse/models/usermodel.py index 43633ab..254fe3f 100644 --- a/verse/models/usermodel.py +++ b/verse/models/usermodel.py @@ -1,6 +1,7 @@ -from app import db from flask_login import UserMixin +from app import db + class User(UserMixin, db.Model): """User model class for a user in distribusi-verse""" diff --git a/verse/start.py b/verse/start.py index b352c9b..cf7ccb1 100644 --- a/verse/start.py +++ b/verse/start.py @@ -2,36 +2,33 @@ from datetime import timedelta -# Interface! these are seperate files in main folder -from adminpage import AdminPage -from app import create_app, login_manager -from distribusiselector import DistribusiSelector -# Distribusi Information -from distribusisinfo import DistribusisInfo -from distribusiworkflow import DistribusiWorkflow -from editor import Editor from flask import (Blueprint, redirect, render_template, send_from_directory, session, 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 distribusikan.distribusikan import distribusikan +from distribusikan.distribusisinfo import DistribusisInfo # Use upload form to populate filters from forms.uploadform import UploadForm from models.distribusimodel import Distribusis from models.usermodel import User -from statuspengguna.forgotpassword import ForgotPassword -# UserPengguna +from statuspengguna.forgotpassword import forgot_password from statuspengguna.helper import UserHelper -from statuspengguna.loginuser import LoginUser -from statuspengguna.registeruser import RegisterUser -from statuspengguna.resetpassword import ResetPassword -from themeselector import ThemeSelector -from uploadpage import UploadPage +from statuspengguna.loginuser import login_section +from statuspengguna.registeruser import register_user APP = create_app() stash_page = Blueprint("stash_page", __name__, static_folder="stash") +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) -mail = Mail(APP) @APP.before_request @@ -60,7 +57,7 @@ def index(): categories = uploadform.category.choices adminuser = isadminuser() template = render_template( - "index.html", + "base/index.html", distribusisindex=distribusisindex, years=years, categories=categories, @@ -71,25 +68,7 @@ def index(): @APP.route("/help") def help(): - return render_template("help.html") - - -@APP.route("/distribusi", methods=["GET", "POST"]) -@login_required -def distribusi(): - return DistribusiWorkflow() - - -@APP.route("/upload", methods=["POST"]) -@login_required -def upload(): - return UploadPage() - - -@APP.route("/theme", methods=["GET", "POST"]) -@login_required -def theme(): - return ThemeSelector() + return render_template("base/help.html") @APP.route("/publicthemes/") @@ -100,18 +79,6 @@ def publicthemes(path): return send_from_directory("themes", cssfile, as_attachment=True) -@APP.route("/editor", methods=["GET", "POST"]) -@login_required -def editor(): - return Editor() - - -@APP.route("/selector", methods=["GET", "POST"]) -@login_required -def selector(): - return DistribusiSelector() - - @APP.route("/stash") def shortstashurl(): return redirect(url_for("index")) @@ -132,26 +99,6 @@ def logout(): return redirect(url_for("index")) -@APP.route("/login", methods=["GET", "POST"]) -def login(): - return LoginUser() - - -@APP.route("/register", methods=["GET", "POST"]) -def register(): - return RegisterUser() - - -@APP.route("/forgotpassword", methods=["GET", "POST"]) -def forgotpassword(): - return ForgotPassword(mail) - - -@APP.route("/resetpassword/", methods=["GET", "POST"]) -def resetpassword(path): - return ResetPassword(path) - - @APP.errorhandler(CSRFError) def handle_csrf_error(e): return render_template("csrf_error.html", reason=e.description), 400 diff --git a/verse/statuspengguna/__init__.py b/verse/statuspengguna/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/verse/statuspengguna/forgotpassword.py b/verse/statuspengguna/forgotpassword.py index 546cb0a..6c0b2f9 100644 --- a/verse/statuspengguna/forgotpassword.py +++ b/verse/statuspengguna/forgotpassword.py @@ -1,14 +1,28 @@ from datetime import datetime from uuid import uuid1 -from app import db -from flask import render_template -from flask_mail import Message -from forms.forgotpasswordform import ForgotPasswordForm -from models.usermodel import User +from flask import Blueprint, render_template +from flask_mail import Mail, Message from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, InvalidRequestError) +from app import db, get_app +from forms.forgotpasswordform import ForgotPasswordForm +from models.usermodel import User + +mail = Mail(get_app()) +forgot_password = Blueprint( + "forgotpassword", + __name__, + template_folder="templates/statuspengguna", + static_folder="static", +) + + +@forgot_password.route("/", methods=["GET", "POST"]) +def forgotpassword(): + return ForgotPassword(mail) + def ForgotPassword(mail): forgotpasswordform = ForgotPasswordForm() diff --git a/verse/statuspengguna/helper.py b/verse/statuspengguna/helper.py index 1724bce..d90e495 100644 --- a/verse/statuspengguna/helper.py +++ b/verse/statuspengguna/helper.py @@ -1,14 +1,15 @@ import os -from app import db -from distribusisinfo import DistribusisInfo from flask import flash from flask_login import current_user -from models.distribusimodel import Distribusis -from models.usermodel import User from sqlalchemy.exc import (DatabaseError, DataError, InterfaceError, InvalidRequestError) +from app import db +from distribusikan.distribusisinfo import DistribusisInfo +from models.distribusimodel import Distribusis +from models.usermodel import User + class UserHelper: def is_zip_uploaded(distribusiname): diff --git a/verse/statuspengguna/loginuser.py b/verse/statuspengguna/loginuser.py index 1968f56..a1a138a 100644 --- a/verse/statuspengguna/loginuser.py +++ b/verse/statuspengguna/loginuser.py @@ -1,9 +1,23 @@ -from flask import abort, flash, redirect, render_template, request, url_for +from flask import (Blueprint, abort, flash, 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 models.usermodel import User +login_section = Blueprint( + "login", + __name__, + template_folder="templates/statuspengguna", + static_folder="static", +) + + +@login_section.route("/", methods=["GET", "POST"]) +def login(): + return LoginUser() + def LoginUser(): loginform = LoginForm() @@ -14,11 +28,14 @@ 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") if next is not None and not is_safe_url(next): # noqa: F821 + print(next) return abort(400) + print("index") return redirect(next or url_for("index")) else: flash("Invalid email or password!", "danger") diff --git a/verse/statuspengguna/registeruser.py b/verse/statuspengguna/registeruser.py index 4bf8da6..d9f6a61 100644 --- a/verse/statuspengguna/registeruser.py +++ b/verse/statuspengguna/registeruser.py @@ -1,13 +1,26 @@ -from app import db -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 forms.registerform import RegisterForm -from models.usermodel import User from sqlalchemy.exc import (DatabaseError, DataError, IntegrityError, InterfaceError, InvalidRequestError) from werkzeug.routing import BuildError +from app import db +from forms.registerform import RegisterForm +from models.usermodel import User + +register_user = Blueprint( + "register", + __name__, + template_folder="templates/statuspengguna", + static_folder="static", +) + + +@register_user.route("/", methods=["GET", "POST"]) +def register(): + return RegisterUser() + def RegisterUser(): registerform = RegisterForm() diff --git a/verse/statuspengguna/resetpassword.py b/verse/statuspengguna/resetpassword.py index 57f0615..ef1735a 100644 --- a/verse/statuspengguna/resetpassword.py +++ b/verse/statuspengguna/resetpassword.py @@ -1,15 +1,29 @@ from datetime import datetime -from app import db from flask import flash, redirect, render_template, url_for from flask_bcrypt import generate_password_hash from flask_login import login_user -from forms.resetpasswordform import ResetPasswordForm -from models.usermodel import User from sqlalchemy.exc import (DatabaseError, DataError, IntegrityError, InterfaceError, InvalidRequestError) from werkzeug.routing import BuildError +from app import db +from forms.resetpasswordform import ResetPasswordForm +from models.usermodel import User +from statuspengguna import statuspengguna + +reset_password = Blueprint( + "reset_password", + __name__, + template_folder="templates/statuspengguna", + static_folder="static", +) + + +@reset_password.route("/resetpassword/", methods=["GET", "POST"]) +def resetpassword(path): + return ResetPassword(path) + def ResetPassword(path): linkvalid = False diff --git a/verse/statuspengguna/static/css/dropdown.css b/verse/statuspengguna/static/css/dropdown.css new file mode 100644 index 0000000..07509d5 --- /dev/null +++ b/verse/statuspengguna/static/css/dropdown.css @@ -0,0 +1,69 @@ +/* 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 new file mode 100644 index 0000000..d087622 --- /dev/null +++ b/verse/statuspengguna/static/css/editor.css @@ -0,0 +1,50 @@ +.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/selector.css b/verse/statuspengguna/static/css/selector.css new file mode 100644 index 0000000..a500a61 --- /dev/null +++ b/verse/statuspengguna/static/css/selector.css @@ -0,0 +1,53 @@ +.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 new file mode 100644 index 0000000..d244b7e --- /dev/null +++ b/verse/statuspengguna/static/css/style.css @@ -0,0 +1,286 @@ +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; +} + +#tutors { + 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 new file mode 100644 index 0000000..f6a9f45 --- /dev/null +++ b/verse/statuspengguna/static/icons/about.txt @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000..3b958ff Binary files /dev/null and b/verse/statuspengguna/static/icons/android-chrome-192x192.png differ diff --git a/verse/statuspengguna/static/icons/android-chrome-512x512.png b/verse/statuspengguna/static/icons/android-chrome-512x512.png new file mode 100644 index 0000000..1d68c63 Binary files /dev/null and b/verse/statuspengguna/static/icons/android-chrome-512x512.png differ diff --git a/verse/statuspengguna/static/icons/apple-touch-icon.png b/verse/statuspengguna/static/icons/apple-touch-icon.png new file mode 100644 index 0000000..97255bd Binary files /dev/null and b/verse/statuspengguna/static/icons/apple-touch-icon.png differ diff --git a/verse/statuspengguna/static/icons/favicon-16x16.png b/verse/statuspengguna/static/icons/favicon-16x16.png new file mode 100644 index 0000000..05a6e48 Binary files /dev/null and b/verse/statuspengguna/static/icons/favicon-16x16.png differ diff --git a/verse/statuspengguna/static/icons/favicon-32x32.png b/verse/statuspengguna/static/icons/favicon-32x32.png new file mode 100644 index 0000000..8478c1e Binary files /dev/null and b/verse/statuspengguna/static/icons/favicon-32x32.png differ diff --git a/verse/statuspengguna/static/icons/favicon.ico b/verse/statuspengguna/static/icons/favicon.ico new file mode 100644 index 0000000..f3757b9 Binary files /dev/null and b/verse/statuspengguna/static/icons/favicon.ico differ diff --git a/verse/statuspengguna/static/icons/site.webmanifest b/verse/statuspengguna/static/icons/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/verse/statuspengguna/static/icons/site.webmanifest @@ -0,0 +1 @@ +{"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 new file mode 100644 index 0000000..505d4a8 --- /dev/null +++ b/verse/statuspengguna/static/js/dropdown.js @@ -0,0 +1,92 @@ +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 new file mode 100644 index 0000000..f76219e --- /dev/null +++ b/verse/statuspengguna/static/js/editorupdate.js @@ -0,0 +1,19 @@ +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 new file mode 100644 index 0000000..2bd662b --- /dev/null +++ b/verse/statuspengguna/static/js/script.js @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000..21073fd --- /dev/null +++ b/verse/statuspengguna/static/svg/arrow_1.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + diff --git a/verse/statuspengguna/static/svg/arrow_2.svg b/verse/statuspengguna/static/svg/arrow_2.svg new file mode 100644 index 0000000..ea2a026 --- /dev/null +++ b/verse/statuspengguna/static/svg/arrow_2.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/verse/statuspengguna/static/svg/arrow_3.svg b/verse/statuspengguna/static/svg/arrow_3.svg new file mode 100644 index 0000000..c447811 --- /dev/null +++ b/verse/statuspengguna/static/svg/arrow_3.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/verse/templates/forgotpassword.html b/verse/statuspengguna/templates/statuspengguna/forgotpassword.html similarity index 86% rename from verse/templates/forgotpassword.html rename to verse/statuspengguna/templates/statuspengguna/forgotpassword.html index 3932ca0..bed8afc 100644 --- a/verse/templates/forgotpassword.html +++ b/verse/statuspengguna/templates/statuspengguna/forgotpassword.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
@@ -6,7 +6,8 @@

Enter the email address that was used to register with Distribusiverse.

- + {{ forgotpasswordform.csrf_token }}
{{ forgotpasswordform.email.label }} diff --git a/verse/templates/login.html b/verse/statuspengguna/templates/statuspengguna/login.html similarity index 80% rename from verse/templates/login.html rename to verse/statuspengguna/templates/statuspengguna/login.html index b21c11f..70a02b2 100644 --- a/verse/templates/login.html +++ b/verse/statuspengguna/templates/statuspengguna/login.html @@ -1,7 +1,7 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
- + {{ loginform.csrf_token }}
{{ loginform.email.label }} @@ -19,7 +19,7 @@
{{ loginform.submit }} - Forgot Password? + Forgot Password?
diff --git a/verse/templates/register.html b/verse/statuspengguna/templates/statuspengguna/register.html similarity index 91% rename from verse/templates/register.html rename to verse/statuspengguna/templates/statuspengguna/register.html index 729ba7d..dcdcbad 100644 --- a/verse/templates/register.html +++ b/verse/statuspengguna/templates/statuspengguna/register.html @@ -1,7 +1,7 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
-
+ {{ registerform.csrf_token }}
{{ registerform.username.label }} diff --git a/verse/templates/resetpassword.html b/verse/statuspengguna/templates/statuspengguna/resetpassword.html similarity index 96% rename from verse/templates/resetpassword.html rename to verse/statuspengguna/templates/statuspengguna/resetpassword.html index cb7cf54..bf2438e 100644 --- a/verse/templates/resetpassword.html +++ b/verse/statuspengguna/templates/statuspengguna/resetpassword.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
{% if linkvalid%} diff --git a/verse/templates/admin.html b/verse/templates/base/admin.html similarity index 98% rename from verse/templates/admin.html rename to verse/templates/base/admin.html index c1fe24a..2272dc2 100644 --- a/verse/templates/admin.html +++ b/verse/templates/base/admin.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
diff --git a/verse/templates/base.html b/verse/templates/base/base.html similarity index 100% rename from verse/templates/base.html rename to verse/templates/base/base.html diff --git a/verse/templates/filtermenu.html b/verse/templates/base/filtermenu.html similarity index 100% rename from verse/templates/filtermenu.html rename to verse/templates/base/filtermenu.html diff --git a/verse/templates/help.html b/verse/templates/base/help.html similarity index 99% rename from verse/templates/help.html rename to verse/templates/base/help.html index 953a795..2abef0c 100644 --- a/verse/templates/help.html +++ b/verse/templates/base/help.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
diff --git a/verse/templates/index.html b/verse/templates/base/index.html similarity index 97% rename from verse/templates/index.html rename to verse/templates/base/index.html index d18caf6..e828dcd 100644 --- a/verse/templates/index.html +++ b/verse/templates/base/index.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base/base.html" %} {% block main %}
@@ -50,7 +50,7 @@

List of distribusis

- {% include 'filtermenu.html' %} + {% include 'base/filtermenu.html' %}
    {% for name, distribusi in distribusisindex.items() %}