diff --git a/README.md b/README.md index 877ef9d..f9fef6f 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,15 @@ The contribution consisted of setting up distribusi. ruruhuis.nl (distribusi is This particular work in progress project is an attempt to make distribusi into a webinterface that can be operated remotely without any knowlegde of CLI. Trying to somehow combine the ideas of distribusi with the ideas of a [tildeverse](https://tildeverse.org/) or [Tilde club ](https://tilde.club/), but also be neither of these ideas. -This project is made for Autonomous Practices at the WDKA in Rotterdam. +This project was made for Autonomous Practices at the WDKA in Rotterdam. + +The second stage of this project might be the archiving part of the [Toolsheds fellowship.](https://nieuweinstituut.nl/en/articles/call-for-fellows-tool-sheds) + + ## Work in progress -Amazingly helpful testers, currently I am writing some database upgrades and new functionalities, and they don't work, so have some patience with testing the in development material. +Currently this repo is transforming the academic based search filters into adjustable +small Autonomous space filters. ## Start your engines! diff --git a/notes.md b/notes.md deleted file mode 100644 index 7b002ba..0000000 --- a/notes.md +++ /dev/null @@ -1,34 +0,0 @@ -# these are some notes - -from distribusi.cli import build_argparser -# from distribusi.distribusi import distribusify -Works! - -# Shit! We need entire CRUD functionality. -Done! -## Create: -Done - -### Uploading -Done - -### CSS editing. -a user can edit CSS of a file in the folder called $distribusiname -Todo: render the placeholder for html editor better. - -### Theme selection -a user can select a CSS file from a radio menu - -### Distribusi -A flag in de DB is set to true and distribusi is run on the folder of the users -called $distribusiname - -## Read: -Based on flags set in the user DB the distribusi folders are set to visible. - - -## Update: -Done - -## Delete: -Done diff --git a/pyproject.toml b/pyproject.toml index 27f62cd..9b286c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,25 +1,25 @@ -[tool.black] -line-length = 79 -target-version = ['py37', 'py38', 'py39'] -include = '\.pyi?$' -exclude = ''' -/( - \.eggs - | \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - +[tool.black] +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 + | tests/data | profiling )/ -''' +''' diff --git a/requirements.txt b/requirements.txt index bd1311a..952979d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,48 +1,57 @@ alembic==1.7.5 +APScheduler==3.10.4 Babel==2.9.1 bcrypt==3.2.0 -black==21.11b1 +black==24.4.0 bleach==4.1.0 bleach-allowlist==1.0.3 -blinker==1.4 +blinker==1.7.0 cffi==1.15.0 -click==8.0.3 +click==8.1.7 +distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@e291e7497e40211c2ebd54ca32a1f4bdaed71230 dnspython==2.1.0 email-validator==1.1.3 -Flask==2.0.2 +Flask==3.0.3 +Flask-APScheduler==1.13.1 Flask-BabelEx==0.9.4 -Flask-Bcrypt==0.7.1 -Flask-Login==0.5.0 +Flask-Bcrypt==1.0.1 +Flask-Login==0.6.3 Flask-Mail==0.9.1 Flask-Migrate==3.1.0 Flask-Principal==0.4.0 Flask-Security==3.0.0 Flask-Security-Too==4.1.3 -Flask-SQLAlchemy==2.5.1 -Flask-WTF==1.0.0 -greenlet==1.1.2 +Flask-SQLAlchemy==3.1.1 +Flask-WTF==1.2.1 +greenlet==3.0.3 idna==3.3 -itsdangerous==2.0.1 -Jinja2==3.0.3 +isort==5.13.2 +itsdangerous==2.2.0 +Jinja2==3.1.3 Mako==1.1.6 -MarkupSafe==2.0.1 +MarkupSafe==2.1.5 +msgpack==1.0.8 mypy-extensions==0.4.3 -packaging==21.3 +neovim==0.3.1 +packaging==24.0 passlib==1.7.4 pathspec==0.9.0 Pillow==8.3.2 platformdirs==2.4.0 pycparser==2.21 +pynvim==0.5.0 pyparsing==3.0.7 +python-dateutil==2.9.0.post0 python-magic==0.4.24 pytz==2021.3 regex==2021.11.10 six==1.16.0 speaklater==1.3 -SQLAlchemy==1.4.27 +SQLAlchemy==2.0.29 tomli==1.2.2 -typing_extensions==4.0.1 +typing_extensions==4.11.0 +tzlocal==5.2 webencodings==0.5.1 -Werkzeug==2.0.2 +Werkzeug==3.0.2 +Whoosh==2.7.4 WTForms==3.0.0 -distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi diff --git a/setup.py b/setup.py index 340f994..ce7462a 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,3 @@ -from setuptools import setup, find_packages +from setuptools import find_packages, setup -setup(name='library', version='1.0', packages=find_packages()) +setup(name="library", version="1.0", packages=find_packages()) diff --git a/verse/adminpage.py b/verse/adminpage.py index c310fde..4d78d26 100644 --- a/verse/adminpage.py +++ b/verse/adminpage.py @@ -1,21 +1,20 @@ import os import shutil -from flask import render_template +from flask import render_template from sqlalchemy.exc import ( - DataError, DatabaseError, + DataError, InterfaceError, InvalidRequestError, ) + from app import db - -from usermodel import User -from distribusimodel import Distribusis -from distribusisinfo import DistribusisInfo - -from forms.adminuserform import AdminUserForm +from distribusikan.distribusisinfo import DistribusisInfo from forms.admindistribusiform import AdminDistribusiForm +from forms.adminuserform import AdminUserForm +from models.distribusi_model import Distribusis +from models.user_model import User def AdminPage(): @@ -27,10 +26,6 @@ def AdminPage(): if adminuserform.validate_on_submit(): if adminuserform.delete.data: DeleteUsers(adminuserform) - if adminuserform.tutors.data: - ToggleUsersAsTutors(adminuserform, True) - if adminuserform.nottutors.data: - ToggleUsersAsTutors(adminuserform, False) template = render_template( "admin.html", @@ -51,23 +46,6 @@ def DeleteUsers(adminuserform): userform.errors.append(f"User {useremail} deleted!") -def ToggleUsersAsTutors(adminuserform, is_tutor): - for userform in adminuserform: - if "user" in userform.id: - if userform.data: - useremail = userform.label.text - user = User.query.filter_by(email=useremail).first() - ToggleUserTutorinDb(user, is_tutor) - userform.errors.append(f"Is User {useremail} tutor {is_tutor}") - - -def ToggleUserTutorinDb(user, is_tutor): - try: - user.tutor = is_tutor - db.session.commit() - except (InvalidRequestError, DataError, InterfaceError, DatabaseError): - db.session.rollback() - def DeleteUserFromDb(user): try: diff --git a/verse/admintool.py b/verse/admintool.py index 9410eaa..c8ddac3 100644 --- a/verse/admintool.py +++ b/verse/admintool.py @@ -1,13 +1,15 @@ import sys -from app import create_app, db + from sqlalchemy.exc import ( - InvalidRequestError, - InterfaceError, - DataError, DatabaseError, + DataError, + InterfaceError, + InvalidRequestError, ) -from usermodel import User # noqa: F401 -from distribusimodel import Distribusis # noqa: F401 + +from app import create_app, db +from models.distribusi_model import Distribusis # noqa: F401 +from models.user_model import User # noqa: F401 def admintool(): diff --git a/verse/app.py b/verse/app.py index 18dceb3..56dd762 100644 --- a/verse/app.py +++ b/verse/app.py @@ -1,13 +1,14 @@ import os -from flask import Flask -from flask_sqlalchemy import SQLAlchemy -from flask_bcrypt import Bcrypt -from flask_migrate import Migrate -from flask_wtf.csrf import CSRFProtect -from flask_login import ( - LoginManager, -) +import tomllib +from flask import Flask +from flask_bcrypt import Bcrypt +from flask_login import LoginManager +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() bcrypt = Bcrypt() @@ -15,18 +16,16 @@ login_manager = LoginManager() def create_app(): - APP = Flask(__name__, static_folder="static") - - APP.secret_key = "secret-key" - APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data/distribusiverse.db" + 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"] = 150 * 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 APP.config["MAIL_USE_TLS"] = True - APP.config['MAIL_USERNAME'] = "noreply@vvvvvvaria.org" + APP.config["MAIL_USERNAME"] = "noreply@vvvvvvaria.org" login_manager.session_protection = "strong" login_manager.login_view = "index" @@ -38,10 +37,36 @@ def create_app(): APP.config["UPLOAD_FOLDER"] = "tmpupload" APP.config["PUBLIC_THEMES"] = "themes/publicthemes" + # user settings_file + settings() + csrf.init_app(APP) login_manager.init_app(APP) db.init_app(APP) migrate.init_app(APP, db, render_as_batch=True) bcrypt.init_app(APP) + @APP.context_processor + def inject_title(): + return dict(title=APP.config["title"]) + return APP + + +def settings(): + settings = settings_from_file() + APP.config.update(settings) + return APP + + +def get_app(): + return 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) + with open("settings.toml", "rb") as settings_file: + return tomllib.load(settings_file) diff --git a/verse/deploydb.py b/verse/deploydb.py index 236baf8..9a33cdc 100644 --- a/verse/deploydb.py +++ b/verse/deploydb.py @@ -1,11 +1,12 @@ def deploy(): """Run deployment of database.""" + from flask_migrate import init, migrate, stamp, upgrade + from app import create_app, db - from flask_migrate import upgrade, migrate, init, stamp + from models.distribusi_model import Distribusis # noqa: F401 # This model is required for flask_migrate to make the table - from usermodel import User # noqa: F401 - from distribusimodel import Distribusis # noqa: F401 + from models.user_model import User # noqa: F401 app = create_app() app.app_context().push() diff --git a/verse/distribusikan/distribusikan.py b/verse/distribusikan/distribusikan.py new file mode 100644 index 0000000..4ba50ae --- /dev/null +++ b/verse/distribusikan/distribusikan.py @@ -0,0 +1,48 @@ +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 95% rename from verse/distribusiselector.py rename to verse/distribusikan/distribusiselector.py index 788ec35..ccc5770 100644 --- a/verse/distribusiselector.py +++ b/verse/distribusikan/distribusiselector.py @@ -1,29 +1,28 @@ import os import shutil + from flask import flash, render_template from flask_login import current_user from sqlalchemy.exc import ( - DataError, DatabaseError, + DataError, InterfaceError, InvalidRequestError, ) -from usermodel import User -from distribusimodel import Distribusis -from distribusisinfo import DistribusisInfo - -from forms.selectorform import SelectorForm -from forms.uploadform import UploadForm +from app import db +from distribusikan.distribusisinfo import DistribusisInfo from forms.distribusiform import DistribusiForm -from forms.themeform import ThemeForm from forms.publicthemeform import PublicThemeForm +from forms.selectorform import SelectorForm +from forms.themeform import ThemeForm +from forms.uploadform import UploadForm +from models.distribusi_model import Distribusis +from models.user_model import User # UserPengguna from statuspengguna.helper import UserHelper -from app import db - def DistribusiSelector(): uploadform = UploadForm() @@ -54,9 +53,8 @@ def AutoFillInUploadForm(uploadform, current_distribusi): ).first() uploadform.sitename.data = distribusi.distribusiname uploadform.sitename.render_kw = {"readonly": True} - uploadform.term.data = distribusi.term - uploadform.course.data = distribusi.course - uploadform.academicyear.data = distribusi.year + uploadform.category.data = distribusi.category + uploadform.year.data = distribusi.year uploadform.tags.data = distribusi.tags return uploadform diff --git a/verse/distribusisinfo.py b/verse/distribusikan/distribusisinfo.py similarity index 93% rename from verse/distribusisinfo.py rename to verse/distribusikan/distribusisinfo.py index 9bbd80e..19ef284 100644 --- a/verse/distribusisinfo.py +++ b/verse/distribusikan/distribusisinfo.py @@ -1,7 +1,7 @@ from flask_login import current_user -from usermodel import User -from distribusimodel import Distribusis +from models.distribusi_model import Distribusis +from models.user_model import User class DistribusisInfo: diff --git a/verse/distribusiworkflow.py b/verse/distribusikan/distribusiworkflow.py similarity index 91% rename from verse/distribusiworkflow.py rename to verse/distribusikan/distribusiworkflow.py index cea215b..4e3a376 100644 --- a/verse/distribusiworkflow.py +++ b/verse/distribusikan/distribusiworkflow.py @@ -1,40 +1,34 @@ import os import shutil import zipfile -from flask_login import current_user -from flask import ( - render_template, - redirect, - url_for, - flash, -) -from sqlalchemy.exc import ( - InvalidRequestError, - DataError, - InterfaceError, - DatabaseError, -) -from app import db - -from usermodel import User -from distribusimodel import Distribusis - -# UserPengguna -from statuspengguna.helper import UserHelper -from distribusiselector import SelectorVisible - -# Forms! -from forms.uploadform import UploadForm -from forms.distribusiform import DistribusiForm -from forms.themeform import ThemeForm -from forms.publicthemeform import PublicThemeForm -from forms.selectorform import SelectorForm - -from distribusisinfo import DistribusisInfo # Tada! from distribusi.cli import build_argparser 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 +from forms.themeform import ThemeForm + +# Forms! +from forms.uploadform import UploadForm +from models.distribusi_model import Distribusis +from models.user_model import User + +# UserPengguna +from statuspengguna.helper import UserHelper def DistribusiWorkflow(): @@ -78,7 +72,7 @@ def CleanUpDistribusiFiles(userfolder): def RemoveMacFolders(path): for filename in os.listdir(path): fullpath = os.path.join(path, filename) - if filename.startswith('.'): + if filename.startswith("."): if os.path.isdir(fullpath): shutil.rmtree(fullpath) else: @@ -101,7 +95,7 @@ def GetCssFile(distribusi): def RunDistribusi(userfolder, cssfile): parser = build_argparser() - args = parser.parse_args(["--menu-with-index", "-s", cssfile]) + args = parser.parse_args(["-t", "--menu-with-index", "-s", cssfile]) distribusify(args, userfolder) diff --git a/verse/editor.py b/verse/distribusikan/editor.py similarity index 95% rename from verse/editor.py rename to verse/distribusikan/editor.py index a515d53..88e63c2 100644 --- a/verse/editor.py +++ b/verse/distribusikan/editor.py @@ -1,28 +1,27 @@ import os +import shutil + import bleach from bleach_allowlist import all_styles -import shutil from flask import render_template - -from werkzeug.utils import secure_filename from sqlalchemy.exc import ( - DataError, DatabaseError, + DataError, InterfaceError, InvalidRequestError, ) +from werkzeug.utils import secure_filename + from app import db -from distribusimodel import Distribusis - -from statuspengguna.helper import UserHelper -from distribusisinfo import DistribusisInfo - -from forms.uploadform import UploadForm +from distribusikan.distribusisinfo import DistribusisInfo from forms.distribusiform import DistribusiForm -from forms.themeform import ThemeForm -from forms.publicthemeform import PublicThemeForm 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 models.distribusi_model import Distribusis +from statuspengguna.helper import UserHelper def Editor(): @@ -68,7 +67,7 @@ def SaveUploadCssFile(editorform, newcssfolder): cssfile.save(os.path.join(newcssfolder, cssfilename)) openfile = open(os.path.join(newcssfolder, cssfilename), "r") cleancss = bleach.clean(openfile.read(), all_styles) - cleancss = cleancss.replace('>', '>') + cleancss = cleancss.replace(">", ">") openfile.close() cleanfile = open(os.path.join(newcssfolder, cssfilename), "w") cleanfile.write(cleancss) @@ -81,7 +80,7 @@ def WriteCssToFile(editorform, newcssfolder): cssfilename = f"{secure_filename(editorform.cssname.data)}.css" cleancss = bleach.clean(editorform.css.data, all_styles) - cleancss = cleancss.replace('>', '>') + cleancss = cleancss.replace(">", ">") with open(os.path.join(newcssfolder, cssfilename), "w") as cssfile: cssfile.write(cleancss) cssfile.close @@ -91,8 +90,7 @@ def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder): if not os.path.exists(newcssfolder): os.mkdir(newcssfolder) copycssfile = os.path.join( - publicfolder, - f"{secure_filename(editorform.cssname.data)}.css" + publicfolder, f"{secure_filename(editorform.cssname.data)}.css" ) print(f"copying file: {copycssfile}") print(f"to folder: {newcssfolder}") 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 %}