Compare commits
No commits in common. "main" and "current_wdka_release" have entirely different histories.
main
...
current_wd
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,12 +3,10 @@
|
||||
*.pyc
|
||||
*.egg-info/
|
||||
.eggs/
|
||||
.ruff_cache
|
||||
build/
|
||||
dist/
|
||||
pip-wheel-metadata/
|
||||
|
||||
verse/tmpupload/*
|
||||
verse/stash/*
|
||||
verse/search/searchdata/*
|
||||
*.db
|
||||
|
@ -8,15 +8,10 @@ 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 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)
|
||||
|
||||
|
||||
This project is made for Autonomous Practices at the WDKA in Rotterdam.
|
||||
## Work in progress
|
||||
|
||||
Currently this repo is transforming the academic based search filters into adjustable
|
||||
small Autonomous space filters.
|
||||
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.
|
||||
|
||||
## Start your engines!
|
||||
|
||||
|
34
notes.md
Normal file
34
notes.md
Normal file
@ -0,0 +1,34 @@
|
||||
# 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
|
@ -1,49 +1,25 @@
|
||||
[tool.ruff]
|
||||
line-length = 79
|
||||
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.black]
|
||||
line-length = 79
|
||||
target-version = ['py37', 'py38', 'py39']
|
||||
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
|
||||
)/
|
||||
'''
|
||||
|
||||
[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
|
||||
|
@ -1,57 +1,48 @@
|
||||
alembic==1.7.5
|
||||
APScheduler==3.10.4
|
||||
Babel==2.9.1
|
||||
bcrypt==3.2.0
|
||||
black==24.4.0
|
||||
black==21.11b1
|
||||
bleach==4.1.0
|
||||
bleach-allowlist==1.0.3
|
||||
blinker==1.7.0
|
||||
cffi
|
||||
click==8.1.7
|
||||
distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@3eefd6e5ca7048555d441df8c6fbf4f2e255acac
|
||||
blinker==1.4
|
||||
cffi==1.15.0
|
||||
click==8.0.3
|
||||
dnspython==2.1.0
|
||||
email-validator==1.1.3
|
||||
Flask==3.0.3
|
||||
Flask-APScheduler==1.13.1
|
||||
Flask==2.0.2
|
||||
Flask-BabelEx==0.9.4
|
||||
Flask-Bcrypt==1.0.1
|
||||
Flask-Login==0.6.3
|
||||
Flask-Bcrypt==0.7.1
|
||||
Flask-Login==0.5.0
|
||||
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==3.1.1
|
||||
Flask-WTF==1.2.1
|
||||
greenlet==3.0.3
|
||||
Flask-SQLAlchemy==2.5.1
|
||||
Flask-WTF==1.0.0
|
||||
greenlet==1.1.2
|
||||
idna==3.3
|
||||
isort==5.13.2
|
||||
itsdangerous==2.2.0
|
||||
Jinja2==3.1.3
|
||||
itsdangerous==2.0.1
|
||||
Jinja2==3.0.3
|
||||
Mako==1.1.6
|
||||
MarkupSafe==2.1.5
|
||||
msgpack==1.0.8
|
||||
MarkupSafe==2.0.1
|
||||
mypy-extensions==0.4.3
|
||||
neovim==0.3.1
|
||||
packaging==24.0
|
||||
packaging==21.3
|
||||
passlib==1.7.4
|
||||
pathspec==0.9.0
|
||||
Pillow
|
||||
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
|
||||
regex==2021.11.10
|
||||
six==1.16.0
|
||||
speaklater==1.3
|
||||
SQLAlchemy==2.0.29
|
||||
SQLAlchemy==1.4.27
|
||||
tomli==1.2.2
|
||||
typing_extensions==4.11.0
|
||||
tzlocal==5.2
|
||||
typing_extensions==4.0.1
|
||||
webencodings==0.5.1
|
||||
Werkzeug==3.0.2
|
||||
Whoosh==2.7.4
|
||||
Werkzeug==2.0.2
|
||||
WTForms==3.0.0
|
||||
distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi
|
||||
|
4
setup.py
4
setup.py
@ -1,3 +1,3 @@
|
||||
from setuptools import find_packages, setup
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name="library", version="1.0", packages=find_packages())
|
||||
setup(name='library', version='1.0', packages=find_packages())
|
||||
|
@ -1,9 +0,0 @@
|
||||
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
|
@ -1,44 +1,36 @@
|
||||
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,
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
|
||||
from app import db
|
||||
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",
|
||||
)
|
||||
from usermodel import User
|
||||
from distribusimodel import Distribusis
|
||||
from distribusisinfo import DistribusisInfo
|
||||
|
||||
from forms.adminuserform import AdminUserForm
|
||||
from forms.admindistribusiform import 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())
|
||||
def AdminPage():
|
||||
adminuserform = AddUsersToForm(AdminUserForm())
|
||||
admindistribusiform = AddDistribusisToForm(AdminDistribusiForm())
|
||||
if admindistribusiform.validate_on_submit():
|
||||
delete_distribusis(admindistribusiform)
|
||||
DeleteDistribusis(admindistribusiform)
|
||||
|
||||
if adminuserform.validate_on_submit():
|
||||
if adminuserform.delete.data:
|
||||
delete_users(adminuserform)
|
||||
DeleteUsers(adminuserform)
|
||||
if adminuserform.tutors.data:
|
||||
ToggleUsersAsTutors(adminuserform, True)
|
||||
if adminuserform.nottutors.data:
|
||||
ToggleUsersAsTutors(adminuserform, False)
|
||||
|
||||
template = render_template(
|
||||
"admin.html",
|
||||
@ -48,18 +40,36 @@ def admin():
|
||||
return template
|
||||
|
||||
|
||||
def delete_users(adminuserform):
|
||||
def DeleteUsers(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()
|
||||
delete_User_distribusis(user)
|
||||
delete_user_from_db(user)
|
||||
DeleteUserDistribusis(user)
|
||||
DeleteUserFromDb(user)
|
||||
userform.errors.append(f"User {useremail} deleted!")
|
||||
|
||||
|
||||
def delete_user_from_db(user):
|
||||
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:
|
||||
db.session.delete(user)
|
||||
db.session.commit()
|
||||
@ -67,14 +77,14 @@ def delete_user_from_db(user):
|
||||
db.session.rollback()
|
||||
|
||||
|
||||
def delete_User_distribusis(user):
|
||||
distribusis = DistribusisInfo.get_user_distribusis(user.email)
|
||||
def DeleteUserDistribusis(user):
|
||||
distribusis = DistribusisInfo.getuserdistribusis(user.email)
|
||||
for distribusi in distribusis:
|
||||
delete_distribusi_files(distribusi.distribusiname)
|
||||
delete_distribusi_from_db(distribusi)
|
||||
DeleteDistribusiFiles(distribusi.distribusiname)
|
||||
DeleteDistribusiFromDb(distribusi)
|
||||
|
||||
|
||||
def delete_distribusis(admindistribusiform):
|
||||
def DeleteDistribusis(admindistribusiform):
|
||||
for distribusiform in admindistribusiform:
|
||||
if "distribusi" in distribusiform.id:
|
||||
if distribusiform.data:
|
||||
@ -82,12 +92,12 @@ def delete_distribusis(admindistribusiform):
|
||||
distribusi = Distribusis.query.filter_by(
|
||||
distribusiname=distribusiname
|
||||
).first()
|
||||
delete_distribusi_from_db(distribusi)
|
||||
delete_distribusi_files(distribusiname)
|
||||
DeleteDistribusiFromDb(distribusi)
|
||||
DeleteDistribusiFiles(distribusiname)
|
||||
distribusiform.errors.append("Deleted distribusi")
|
||||
|
||||
|
||||
def delete_distribusi_from_db(distribusi):
|
||||
def DeleteDistribusiFromDb(distribusi):
|
||||
try:
|
||||
db.session.delete(distribusi)
|
||||
db.session.commit()
|
||||
@ -95,7 +105,7 @@ def delete_distribusi_from_db(distribusi):
|
||||
db.session.rollback()
|
||||
|
||||
|
||||
def delete_distribusi_files(distribusiname):
|
||||
def DeleteDistribusiFiles(distribusiname):
|
||||
userfolder = os.path.join("stash", distribusiname)
|
||||
if os.path.exists(userfolder):
|
||||
shutil.rmtree(userfolder)
|
||||
@ -104,15 +114,15 @@ def delete_distribusi_files(distribusiname):
|
||||
shutil.rmtree(cssfolder)
|
||||
|
||||
|
||||
def add_distribusis_to_form(admindistribusiform):
|
||||
distribusis = DistribusisInfo.visible_distribusis()
|
||||
def AddDistribusisToForm(admindistribusiform):
|
||||
distribusis = DistribusisInfo.visibledistribusis()
|
||||
admindistribusiform = AdminDistribusiForm.distribusi_list_form_builder(
|
||||
distribusis
|
||||
)
|
||||
return admindistribusiform
|
||||
|
||||
|
||||
def add_users_to_form(adminuserform):
|
||||
def AddUsersToForm(adminuserform):
|
||||
users = User.query.all()
|
||||
adminuserform = AdminUserForm.user_list_form_builder(users)
|
||||
return adminuserform
|
@ -1,15 +1,13 @@
|
||||
import sys
|
||||
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
|
||||
from app import create_app, db
|
||||
from models.distribusi_model import Distribusis # noqa: F401
|
||||
from models.user_model import User # noqa: F401
|
||||
from sqlalchemy.exc import (
|
||||
InvalidRequestError,
|
||||
InterfaceError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
)
|
||||
from usermodel import User # noqa: F401
|
||||
from distribusimodel import Distribusis # noqa: F401
|
||||
|
||||
|
||||
def admintool():
|
||||
|
49
verse/app.py
49
verse/app.py
@ -1,15 +1,13 @@
|
||||
import os
|
||||
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_bcrypt import Bcrypt
|
||||
from flask_migrate import Migrate
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
from flask_login import (
|
||||
LoginManager,
|
||||
)
|
||||
|
||||
|
||||
APP = Flask(__name__, static_folder="static")
|
||||
db = SQLAlchemy()
|
||||
migrate = Migrate()
|
||||
bcrypt = Bcrypt()
|
||||
@ -17,16 +15,18 @@ login_manager = LoginManager()
|
||||
|
||||
|
||||
def create_app():
|
||||
APP.secret_key = os.urandom(24)
|
||||
APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///distribusiverse.db"
|
||||
APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
|
||||
APP = Flask(__name__, static_folder="static")
|
||||
|
||||
APP.secret_key = "secret-key"
|
||||
APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data/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,35 +38,10 @@ 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():
|
||||
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)
|
||||
|
3
verse/data/.gitignore
vendored
Normal file
3
verse/data/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*
|
||||
*/
|
||||
!.gitignore
|
@ -1,13 +1,11 @@
|
||||
def deploy():
|
||||
"""Run deployment of database."""
|
||||
from flask_migrate import init, migrate, stamp, upgrade
|
||||
|
||||
from app import create_app, db
|
||||
from models.distribusi_model import Distribusis # noqa: F401
|
||||
from models.distribusi_file_model import DistribusiFiles # noqa: F401
|
||||
from flask_migrate import upgrade, migrate, init, stamp
|
||||
|
||||
# This model is required for flask_migrate to make the table
|
||||
from models.user_model import User # noqa: F401
|
||||
from usermodel import User # noqa: F401
|
||||
from distribusimodel import Distribusis # noqa: F401
|
||||
|
||||
app = create_app()
|
||||
app.app_context().push()
|
||||
|
@ -1,160 +0,0 @@
|
||||
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("/<string:distribusiname>")
|
||||
@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/<string:distribusiname>", 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/<int:file_id>", 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/<path:path>")
|
||||
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
|
@ -1,48 +0,0 @@
|
||||
"""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', {})})
|
@ -1,8 +0,0 @@
|
||||
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!")
|
@ -1,32 +0,0 @@
|
||||
#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%;
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% block main %}
|
||||
<div id="buttons">
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="distribusi">
|
||||
<a href="{{ url_for('distribusikan.distribusi') }}">
|
||||
<input type="button" name="button" value="Distribusi"></input>
|
||||
</a>
|
||||
</div>
|
||||
{% if adminuser %}
|
||||
<div class="admin">
|
||||
<a href="/admin">
|
||||
<input type="button" name="button" value="Admin"></input>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="logout">
|
||||
<a href="/logout">
|
||||
<input type="button" name="button" value="Logout"></input>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="help">
|
||||
<a href="/help">
|
||||
<input type="button" name="button" value="Help"></input>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="describe_workflow">
|
||||
<div class="distribusi_files">
|
||||
{% for id, describe_form in distribusi_file_forms.items() %}
|
||||
<div class="distribusi_file">
|
||||
{% if describe_form.type == "image" %}
|
||||
<img src="{{describe_form.file_path}}" alt="" data-src="{{describe_form.file_path}}" loading="lazy"/>
|
||||
{% elif describe_form.type == "video" %}
|
||||
<video src="{{describe_form.file_path}}" preload="auto" alt="" controls loading="lazy"></video>
|
||||
{% elif describe_form.type == "audio" %}
|
||||
<audio src="{{describe_form.file_path}}" preload="auto" alt="" controls loading="lazy"> </audio>
|
||||
{% else %}
|
||||
<a href="{{describe_form.file_path}}">file: {{describe_form.file_path}}</a>
|
||||
{% endif %}
|
||||
<form id={{id}} method="POST" enctype="multipart/form-data" action="{{ url_for('describer.describe_file', file_id=id) }}">
|
||||
{{ describe_form.csrf_token }}
|
||||
<p>File path: {{describe_form.file_path}}</p>
|
||||
<fieldset class="description">
|
||||
{{ describe_form.description.label }}
|
||||
{{ describe_form.description }}
|
||||
{% for message in describe_form.description.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="">
|
||||
{{ describe_form.searchtags.label }}
|
||||
{{ describe_form.searchtags }}
|
||||
{% for message in describe_form.searchtags.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="">
|
||||
{{ describe_form.alttext.label }}
|
||||
{{ describe_form.alttext }}
|
||||
{% for message in describe_form.alttext.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="button">
|
||||
{{ describe_form.save }}
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor%}
|
||||
</div>
|
||||
{% block redistribusi %}
|
||||
{% include "redistribusi.html" %}
|
||||
{% endblock redistribusi%}
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('describer.static', filename='css/describer.css')}}">
|
||||
{% endblock %}
|
@ -1,13 +0,0 @@
|
||||
<div class="redistribusi">
|
||||
<p class="tooltip">Run distribusi again after describing your files.<span class="tooltiptext">Distribusi will run again and add your alttext and descriptions.
|
||||
</span></p>
|
||||
<form id={{distribusiname}} method="POST" enctype="multipart/form-data" action="{{ url_for('describer.re_distribusi_files', distribusiname=distribusiname) }}">
|
||||
{{ redistribusi_form.csrf_token }}
|
||||
<fieldset class="">
|
||||
{{ redistribusi_form.submit }}
|
||||
{% for message in redistribusi_form.submit.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
@ -1,82 +0,0 @@
|
||||
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)
|
@ -1,47 +0,0 @@
|
||||
from flask import Blueprint
|
||||
from flask_login import login_required
|
||||
|
||||
from distribusikan.distribusi_selector import distribusi_selector
|
||||
|
||||
# Distribusi Information
|
||||
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",
|
||||
__name__,
|
||||
template_folder="templates/distribusikan",
|
||||
static_folder="static",
|
||||
)
|
||||
|
||||
|
||||
@distribusikan.route("/distribusi", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def distribusi():
|
||||
return distribusi_workflow()
|
||||
|
||||
|
||||
@distribusikan.route("/upload", methods=["POST"])
|
||||
@login_required
|
||||
def upload():
|
||||
return upload_page()
|
||||
|
||||
|
||||
@distribusikan.route("/theme", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def theme():
|
||||
return theme_selector()
|
||||
|
||||
|
||||
@distribusikan.route("/editor", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def editor():
|
||||
return css_editor_page()
|
||||
|
||||
|
||||
@distribusikan.route("/selector", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def selector():
|
||||
return distribusi_selector()
|
@ -1,94 +0,0 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileAllowed, FileField, FileRequired, FileSize
|
||||
from wtforms import (
|
||||
SelectField,
|
||||
StringField,
|
||||
SubmitField,
|
||||
TextAreaField,
|
||||
validators,
|
||||
)
|
||||
from wtforms.validators import (
|
||||
DataRequired,
|
||||
Length,
|
||||
ValidationError,
|
||||
)
|
||||
from wtforms.widgets import TextArea
|
||||
|
||||
from app import settings
|
||||
|
||||
|
||||
class UploadForm(FlaskForm):
|
||||
"""File upload class for a new site in distribusi-verse"""
|
||||
|
||||
def distribusiname(form, field):
|
||||
if field.data.lower() == "new":
|
||||
raise ValidationError("Name has to be unique and not just new.")
|
||||
|
||||
def category_choices():
|
||||
APP = settings()
|
||||
config_categories = APP.config["categories"]
|
||||
categories = []
|
||||
for config_category in config_categories:
|
||||
categories.append((config_category, config_category))
|
||||
return categories
|
||||
|
||||
def year_choices():
|
||||
APP = settings()
|
||||
start_time = APP.config["start_time"]
|
||||
end_time = APP.config["end_time"]
|
||||
year_range = range(start_time.year, end_time.year, 1)
|
||||
year_choices = []
|
||||
for year in year_range:
|
||||
year_choices.append((str(year), str(year)))
|
||||
return year_choices
|
||||
|
||||
sitename = StringField(
|
||||
"Name of your archive section:",
|
||||
validators=[
|
||||
validators.InputRequired(),
|
||||
Length(2, 100),
|
||||
distribusiname,
|
||||
],
|
||||
)
|
||||
description = StringField(
|
||||
"Description of this distribusi:",
|
||||
validators=[
|
||||
Length(10, 32000),
|
||||
],
|
||||
widget=TextArea(),
|
||||
)
|
||||
year = SelectField(
|
||||
"Year:",
|
||||
validate_choice=True,
|
||||
coerce=str,
|
||||
choices=year_choices,
|
||||
option_widget=None,
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
category = SelectField(
|
||||
"Category:",
|
||||
validate_choice=True,
|
||||
coerce=str,
|
||||
choices=category_choices,
|
||||
option_widget=None,
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
tags = StringField(
|
||||
"Add search tags, seperated by commas. No need for the '#' sign:",
|
||||
validators=[validators.InputRequired(), Length(3, 500)],
|
||||
)
|
||||
|
||||
zipfile = FileField(
|
||||
"Upload your zip file with content here:",
|
||||
validators=[
|
||||
FileAllowed(["zip"], "Zip archives only!"),
|
||||
FileRequired(),
|
||||
FileSize(
|
||||
max_size=1073741824,
|
||||
message="Zipfile size must be smaller than 1024MB",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
submit = SubmitField("Upload")
|
@ -1,32 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -9,11 +9,14 @@ class Distribusis(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
distribusiname = db.Column(db.String(300), nullable=False, unique=True)
|
||||
userid = db.Column(db.Integer, db.ForeignKey("users.id"))
|
||||
category = db.Column(db.String(500), nullable=True, unique=False)
|
||||
term = db.Column(db.String(5), nullable=False, unique=False)
|
||||
course = db.Column(db.String(500), nullable=True, unique=False)
|
||||
|
||||
# Academic year eg:2020-2021, so no need for a Datetime object
|
||||
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)
|
||||
|
||||
def __repr__(self):
|
@ -1,89 +1,77 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from flask import flash, render_template, redirect, url_for
|
||||
from flask import flash, render_template
|
||||
from flask_login import current_user
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
|
||||
from app import db
|
||||
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
|
||||
from usermodel import User
|
||||
from distribusimodel import Distribusis
|
||||
from distribusisinfo import DistribusisInfo
|
||||
|
||||
from forms.selectorform import SelectorForm
|
||||
from forms.uploadform import UploadForm
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.themeform import ThemeForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
|
||||
# UserPengguna
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
from app import db
|
||||
|
||||
def distribusi_selector():
|
||||
|
||||
def DistribusiSelector():
|
||||
uploadform = UploadForm()
|
||||
selectorform = SelectorForm()
|
||||
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames()
|
||||
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if selectorform.validate_on_submit():
|
||||
if selectorform.new.data:
|
||||
select_new_distribusi()
|
||||
if selectorform.describe.data:
|
||||
return select_describe_distribusi(selectorform.distribusis.data)
|
||||
SelectNewDistribusi()
|
||||
if selectorform.delete.data:
|
||||
selectorform = delete_distribusi(selectorform.distribusis.data)
|
||||
selectorform = DeleteDistribusi(selectorform.distribusis.data)
|
||||
selectorform.distribusis.choices = (
|
||||
DistribusisInfo.user_distribusinames()
|
||||
DistribusisInfo.userdistribusinames()
|
||||
)
|
||||
if selectorform.update.data:
|
||||
select_update_distribusi(selectorform.distribusis.data)
|
||||
SelectUpdateDistribusi(selectorform.distribusis.data)
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
uploadform = auto_fill_in_upload_form(
|
||||
uploadform, current_distribusi
|
||||
)
|
||||
uploadform = AutoFillInUploadForm(uploadform, current_distribusi)
|
||||
|
||||
return render_distribusi_template(
|
||||
return RenderDistribusiTemplate(
|
||||
selectorform, uploadform, current_distribusi
|
||||
)
|
||||
|
||||
|
||||
def auto_fill_in_upload_form(uploadform, current_distribusi):
|
||||
def AutoFillInUploadForm(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.term.data = distribusi.term
|
||||
uploadform.course.data = distribusi.course
|
||||
uploadform.academicyear.data = distribusi.year
|
||||
uploadform.tags.data = distribusi.tags
|
||||
return uploadform
|
||||
|
||||
|
||||
def select_new_distribusi():
|
||||
def SelectNewDistribusi():
|
||||
print("make a new distribusi")
|
||||
select_current_distribusi("new")
|
||||
SelectCurrentDistribusi("new")
|
||||
|
||||
|
||||
def select_describe_distribusi(distribusiname):
|
||||
return redirect(
|
||||
url_for(
|
||||
"describer.show_distribusi_files",
|
||||
distribusiname=distribusiname,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def select_update_distribusi(distribusiname):
|
||||
def SelectUpdateDistribusi(distribusiname):
|
||||
print(f"Update this distribusi {distribusiname}")
|
||||
select_current_distribusi(distribusiname)
|
||||
SelectCurrentDistribusi(distribusiname)
|
||||
|
||||
|
||||
def delete_distribusi(distribusiname):
|
||||
def DeleteDistribusi(distribusiname):
|
||||
print(f"delete this distribusi {distribusiname}")
|
||||
selectorform = SelectorForm()
|
||||
try:
|
||||
@ -117,7 +105,7 @@ def delete_distribusi(distribusiname):
|
||||
return selectorform
|
||||
|
||||
|
||||
def select_current_distribusi(distribusiname):
|
||||
def SelectCurrentDistribusi(distribusiname):
|
||||
if not current_user.is_authenticated:
|
||||
return
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
@ -129,35 +117,35 @@ def select_current_distribusi(distribusiname):
|
||||
flash("An error occured !", "danger")
|
||||
|
||||
|
||||
def distribusi_selected():
|
||||
def DistribusiSelected():
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
if user.currentdistribusi is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def selector_visible():
|
||||
def SelectorVisible():
|
||||
has_distribusi = UserHelper.has_distribusi()
|
||||
is_distribusi_selected = distribusi_selected()
|
||||
if is_distribusi_selected:
|
||||
distribusi_selected = DistribusiSelected()
|
||||
if distribusi_selected:
|
||||
return False
|
||||
if not has_distribusi:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def render_distribusi_template(selectorform, uploadform, current_distribusi):
|
||||
def RenderDistribusiTemplate(selectorform, uploadform, current_distribusi):
|
||||
distribusiform = DistribusiForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
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 = selector_visible()
|
||||
selectorvisible = SelectorVisible()
|
||||
limit_reached = UserHelper.distribusi_limit_reached()
|
||||
template = render_template(
|
||||
"distribusi.html",
|
@ -1,18 +1,18 @@
|
||||
from flask_login import current_user
|
||||
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
from usermodel import User
|
||||
from distribusimodel import Distribusis
|
||||
|
||||
|
||||
class DistribusisInfo:
|
||||
def user_distribusinames():
|
||||
def userdistribusinames():
|
||||
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 public_themes():
|
||||
def publicthemes():
|
||||
publicthemes = []
|
||||
distribusis = Distribusis.query.filter(
|
||||
Distribusis.publictheme.isnot(None)
|
||||
@ -27,12 +27,12 @@ made by {user.username}""",
|
||||
publicthemes.append(publictheme)
|
||||
return publicthemes
|
||||
|
||||
def visible_distribusis():
|
||||
def visibledistribusis():
|
||||
distribusis = Distribusis.query.filter(
|
||||
Distribusis.visible.isnot(False)
|
||||
).all()
|
||||
return distribusis
|
||||
|
||||
def get_user_distribusis(useremail):
|
||||
def getuserdistribusis(useremail):
|
||||
user = User.query.filter_by(email=useremail).first()
|
||||
return Distribusis.query.filter_by(userid=user.id).all()
|
@ -1,38 +1,43 @@
|
||||
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.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 distribusikan.forms.uploadform import UploadForm
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
|
||||
# UserPengguna
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
|
||||
def distribusi_workflow():
|
||||
def DistribusiWorkflow():
|
||||
distribusiform = DistribusiForm()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
@ -42,19 +47,18 @@ def distribusi_workflow():
|
||||
|
||||
if distribusiform.validate_on_submit():
|
||||
userfolder = os.path.join("stash", distribusi.distribusiname)
|
||||
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)
|
||||
cssfile = GetCssFile(distribusi)
|
||||
UnzipDistribusiFiles(distribusi, userfolder)
|
||||
CleanUpDistribusiFiles(userfolder)
|
||||
RunDistribusi(userfolder, cssfile)
|
||||
SetDistribusiToVisible(distribusi, user)
|
||||
DeleteCssFile(cssfile)
|
||||
return redirect(url_for("index"))
|
||||
|
||||
return render_distribusi_template(distribusiform, current_distribusi)
|
||||
return RenderDistribusiTemplate(distribusiform, current_distribusi)
|
||||
|
||||
|
||||
def unzip_distribusi_files(distribusi, userfolder):
|
||||
def UnzipDistribusiFiles(distribusi, userfolder):
|
||||
zipfilename = "{}.zip".format(distribusi.distribusiname)
|
||||
unzipfile = os.path.join(userfolder, zipfilename)
|
||||
|
||||
@ -66,15 +70,15 @@ def unzip_distribusi_files(distribusi, userfolder):
|
||||
os.remove(os.path.join(userfolder, zipfilename))
|
||||
|
||||
|
||||
def clean_up_distribusi_files(userfolder):
|
||||
def CleanUpDistribusiFiles(userfolder):
|
||||
if os.path.exists(userfolder):
|
||||
remove_mac_folders(userfolder)
|
||||
RemoveMacFolders(userfolder)
|
||||
|
||||
|
||||
def remove_mac_folders(path):
|
||||
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:
|
||||
@ -82,10 +86,10 @@ def remove_mac_folders(path):
|
||||
if filename == "__MACOSX":
|
||||
shutil.rmtree(fullpath)
|
||||
if os.path.isdir(fullpath):
|
||||
remove_mac_folders(fullpath)
|
||||
RemoveMacFolders(fullpath)
|
||||
|
||||
|
||||
def get_css_file(distribusi):
|
||||
def GetCssFile(distribusi):
|
||||
cssfile = ""
|
||||
cssfolder = os.path.join("themes/userthemes", distribusi.distribusiname)
|
||||
if os.path.exists(cssfolder):
|
||||
@ -95,14 +99,13 @@ def get_css_file(distribusi):
|
||||
return cssfile
|
||||
|
||||
|
||||
def run_distribusi(userfolder, cssfile):
|
||||
print(f"Run distribusi on this folder: {userfolder} with css:{cssfile}")
|
||||
def RunDistribusi(userfolder, cssfile):
|
||||
parser = build_argparser()
|
||||
args = parser.parse_args(["-t", "-a", "--menu-with-index", "-s", cssfile])
|
||||
args = parser.parse_args(["--menu-with-index", "-s", cssfile])
|
||||
distribusify(args, userfolder)
|
||||
|
||||
|
||||
def set_distribusi_to_visible(distribusi, user):
|
||||
def SetDistribusiToVisible(distribusi, user):
|
||||
try:
|
||||
distribusi.visible = True
|
||||
user.currentdistribusi = None
|
||||
@ -112,19 +115,19 @@ def set_distribusi_to_visible(distribusi, user):
|
||||
flash("Unknown error occured!")
|
||||
|
||||
|
||||
def delete_css_file(cssfile):
|
||||
def DeleteCssFile(cssfile):
|
||||
if os.path.exists(cssfile):
|
||||
os.remove(cssfile)
|
||||
|
||||
|
||||
def render_distribusi_template(distribusiform, current_distribusi):
|
||||
def RenderDistribusiTemplate(distribusiform, current_distribusi):
|
||||
uploadform = UploadForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
selectorform = SelectorForm()
|
||||
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames()
|
||||
selectorvisible = selector_visible()
|
||||
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
|
||||
selectorvisible = SelectorVisible()
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
|
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
|
@ -1,40 +1,41 @@
|
||||
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 (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from app import db
|
||||
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 distribusimodel import Distribusis
|
||||
|
||||
from statuspengguna.helper import UserHelper
|
||||
from distribusisinfo import DistribusisInfo
|
||||
|
||||
from forms.uploadform import UploadForm
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.themeform import ThemeForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
from forms.editorform import EditorForm
|
||||
from forms.selectorform import SelectorForm
|
||||
|
||||
|
||||
def css_editor_page():
|
||||
def Editor():
|
||||
editorform = EditorForm()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if editorform.validate_on_submit():
|
||||
validate_edit_css_form(editorform, current_distribusi)
|
||||
return render_distribusi_template(current_distribusi)
|
||||
ValidateEditCssForm(editorform, current_distribusi)
|
||||
return RenderDistribusiTemplate(current_distribusi)
|
||||
|
||||
return render_editor_template(editorform, current_distribusi)
|
||||
return RenderEditorTemplate(editorform, current_distribusi)
|
||||
|
||||
|
||||
def validate_edit_css_form(editorform, current_distribusi):
|
||||
def ValidateEditCssForm(editorform, current_distribusi):
|
||||
newcssfolder = os.path.join("themes/userthemes", current_distribusi)
|
||||
if os.path.exists(newcssfolder):
|
||||
shutil.rmtree(newcssfolder)
|
||||
@ -44,22 +45,22 @@ def validate_edit_css_form(editorform, current_distribusi):
|
||||
shutil.rmtree(publicfolder)
|
||||
|
||||
if editorform.public.data:
|
||||
make_public_theme(editorform, current_distribusi)
|
||||
MakePublicTheme(editorform, current_distribusi)
|
||||
if editorform.cssfile.data:
|
||||
save_upload_css_file(editorform, publicfolder)
|
||||
copy_public_to_user_folder(editorform, publicfolder, newcssfolder)
|
||||
SaveUploadCssFile(editorform, publicfolder)
|
||||
CopyPublicToUserFolder(editorform, publicfolder, newcssfolder)
|
||||
return
|
||||
else:
|
||||
write_css_to_file(editorform, publicfolder)
|
||||
WriteCssToFile(editorform, publicfolder)
|
||||
|
||||
if editorform.cssfile.data:
|
||||
save_upload_css_file(editorform, newcssfolder)
|
||||
SaveUploadCssFile(editorform, newcssfolder)
|
||||
return
|
||||
if editorform.cssname.data:
|
||||
write_css_to_file(editorform, newcssfolder)
|
||||
WriteCssToFile(editorform, newcssfolder)
|
||||
|
||||
|
||||
def save_upload_css_file(editorform, newcssfolder):
|
||||
def SaveUploadCssFile(editorform, newcssfolder):
|
||||
if not os.path.exists(newcssfolder):
|
||||
os.mkdir(newcssfolder)
|
||||
cssfile = editorform.cssfile.data
|
||||
@ -67,37 +68,38 @@ def save_upload_css_file(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)
|
||||
cleanfile.close()
|
||||
|
||||
|
||||
def write_css_to_file(editorform, newcssfolder):
|
||||
def WriteCssToFile(editorform, newcssfolder):
|
||||
if not os.path.exists(newcssfolder):
|
||||
os.mkdir(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
|
||||
|
||||
|
||||
def copy_public_to_user_folder(editorform, publicfolder, newcssfolder):
|
||||
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}")
|
||||
shutil.copy(copycssfile, newcssfolder)
|
||||
|
||||
|
||||
def make_public_theme(editorform, current_distribusi):
|
||||
def MakePublicTheme(editorform, current_distribusi):
|
||||
try:
|
||||
distribusi = Distribusis.query.filter_by(
|
||||
distribusiname=current_distribusi
|
||||
@ -119,12 +121,12 @@ def make_public_theme(editorform, current_distribusi):
|
||||
editorform.public.errors.append("Error connecting to the database")
|
||||
|
||||
|
||||
def render_distribusi_template(current_distribusi):
|
||||
def RenderDistribusiTemplate(current_distribusi):
|
||||
uploadform = UploadForm()
|
||||
distribusiform = DistribusiForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
selectorform = SelectorForm()
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
|
||||
@ -148,11 +150,11 @@ def render_distribusi_template(current_distribusi):
|
||||
return template
|
||||
|
||||
|
||||
def render_editor_template(editorform, current_distribusi):
|
||||
html_placeholder = get_html_placeholder()
|
||||
def RenderEditorTemplate(editorform, current_distribusi):
|
||||
htmlplaceholder = HtmlPlaceholder()
|
||||
|
||||
css_placeholder = get_css_placeholder(current_distribusi)
|
||||
editorform.css.data = css_placeholder
|
||||
cssplaceholder = CssPlaceholder(current_distribusi)
|
||||
editorform.css.data = cssplaceholder
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
|
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
|
||||
@ -161,33 +163,33 @@ def render_editor_template(editorform, current_distribusi):
|
||||
files_uploaded=files_uploaded,
|
||||
distribusi_live=distribusi_live,
|
||||
editorform=editorform,
|
||||
html_placeholder=html_placeholder,
|
||||
htmlplaceholder=htmlplaceholder,
|
||||
)
|
||||
return template
|
||||
|
||||
|
||||
def get_css_placeholder(current_distribusi):
|
||||
css_placeholder = "Try out your CSS here"
|
||||
def CssPlaceholder(current_distribusi):
|
||||
cssplaceholder = "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:
|
||||
css_placeholder = get_public_css_file(distribusi)
|
||||
cssplaceholder = GetPublicCssFile(distribusi)
|
||||
else:
|
||||
with open("themes/editor/placeholder.css") as f:
|
||||
css_placeholder = f.read()
|
||||
return css_placeholder
|
||||
cssplaceholder = f.read()
|
||||
return cssplaceholder
|
||||
|
||||
|
||||
def get_html_placeholder():
|
||||
html_placeholder = "Write some test HTML here"
|
||||
def HtmlPlaceholder():
|
||||
htmlplaceholder = "Write some test HTML here"
|
||||
with open("themes/editor/placeholder.html") as f:
|
||||
html_placeholder = f.read()
|
||||
return html_placeholder
|
||||
htmlplaceholder = f.read()
|
||||
return htmlplaceholder
|
||||
|
||||
|
||||
def get_public_css_file(distribusi):
|
||||
css_placeholder = ""
|
||||
def GetPublicCssFile(distribusi):
|
||||
cssplaceholder = ""
|
||||
publicthemefolder = os.path.join(
|
||||
"themes/publicthemes", distribusi.distribusiname
|
||||
)
|
||||
@ -195,5 +197,5 @@ def get_public_css_file(distribusi):
|
||||
if filename.endswith(".css"):
|
||||
cssfile = os.path.join(publicthemefolder, filename)
|
||||
with open(cssfile) as f:
|
||||
css_placeholder = f.read()
|
||||
return css_placeholder
|
||||
cssplaceholder = f.read()
|
||||
return cssplaceholder
|
@ -1,7 +1,9 @@
|
||||
"""Form object declaration."""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import BooleanField, SubmitField
|
||||
from wtforms import (
|
||||
BooleanField,
|
||||
SubmitField,
|
||||
)
|
||||
|
||||
|
||||
class AdminDistribusiForm(FlaskForm):
|
||||
@ -13,7 +15,7 @@ class AdminDistribusiForm(FlaskForm):
|
||||
class DistribusiListForm(AdminDistribusiForm):
|
||||
pass
|
||||
|
||||
for i, distribusi in enumerate(distribusis):
|
||||
for (i, distribusi) in enumerate(distribusis):
|
||||
setattr(
|
||||
DistribusiListForm,
|
||||
f"distribusi_{i}",
|
@ -1,7 +1,9 @@
|
||||
"""Form object declaration."""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import BooleanField, SubmitField
|
||||
from wtforms import (
|
||||
SubmitField,
|
||||
BooleanField,
|
||||
)
|
||||
|
||||
|
||||
class AdminUserForm(FlaskForm):
|
||||
@ -11,7 +13,7 @@ class AdminUserForm(FlaskForm):
|
||||
class UserListForm(AdminUserForm):
|
||||
pass
|
||||
|
||||
for i, user in enumerate(users):
|
||||
for (i, user) in enumerate(users):
|
||||
setattr(
|
||||
UserListForm,
|
||||
f"user_{i}",
|
||||
@ -20,4 +22,8 @@ class AdminUserForm(FlaskForm):
|
||||
|
||||
return UserListForm()
|
||||
|
||||
tutors = SubmitField("Are tutors")
|
||||
|
||||
nottutors = SubmitField("Are not tutors")
|
||||
|
||||
delete = SubmitField("Delete")
|
@ -1,15 +1,15 @@
|
||||
"""Form to save your CSS editor work."""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileAllowed, FileField, FileSize
|
||||
from wtforms import (
|
||||
BooleanField,
|
||||
StringField,
|
||||
SubmitField,
|
||||
TextAreaField,
|
||||
validators,
|
||||
BooleanField,
|
||||
SubmitField,
|
||||
)
|
||||
|
||||
from wtforms import validators
|
||||
from wtforms.validators import Length
|
||||
from flask_wtf.file import FileField, FileAllowed, FileSize
|
||||
from flask_wtf import FlaskForm
|
||||
|
||||
|
||||
class EditorForm(FlaskForm):
|
@ -1,8 +1,12 @@
|
||||
"""Forgotten password form to help user."""
|
||||
from wtforms import (
|
||||
StringField,
|
||||
SubmitField,
|
||||
)
|
||||
|
||||
from wtforms import validators
|
||||
from wtforms.validators import Length, Email
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, validators
|
||||
from wtforms.validators import Email, Length
|
||||
|
||||
|
||||
class ForgotPasswordForm(FlaskForm):
|
@ -1,8 +1,13 @@
|
||||
"""Login form to validate user."""
|
||||
from wtforms import (
|
||||
StringField,
|
||||
SubmitField,
|
||||
PasswordField,
|
||||
)
|
||||
|
||||
from wtforms import validators
|
||||
from wtforms.validators import Length, Email
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import PasswordField, StringField, SubmitField, validators
|
||||
from wtforms.validators import Email, Length
|
||||
|
||||
|
||||
class LoginForm(FlaskForm):
|
@ -1,7 +1,9 @@
|
||||
"""Form object declaration."""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import RadioField, SubmitField
|
||||
from wtforms import (
|
||||
RadioField,
|
||||
SubmitField,
|
||||
)
|
||||
|
||||
|
||||
class PublicThemeForm(FlaskForm):
|
@ -1,13 +1,22 @@
|
||||
"""Register form to make a new user."""
|
||||
from wtforms import (
|
||||
StringField,
|
||||
SubmitField,
|
||||
PasswordField,
|
||||
)
|
||||
|
||||
from wtforms import validators
|
||||
from wtforms.validators import Length, Email, EqualTo, ValidationError
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import PasswordField, StringField, SubmitField, validators
|
||||
from wtforms.validators import Email, EqualTo, Length
|
||||
|
||||
|
||||
class RegisterForm(FlaskForm):
|
||||
"""Register for distribusi-verse form class"""
|
||||
|
||||
def hremail(form, field):
|
||||
if not field.data.endswith("@hr.nl"):
|
||||
raise ValidationError("Only HRO accounts are allowed.")
|
||||
|
||||
username = StringField(
|
||||
"Username:",
|
||||
validators=[validators.InputRequired(), Length(3, 150)],
|
||||
@ -18,8 +27,9 @@ class RegisterForm(FlaskForm):
|
||||
validators=[
|
||||
validators.InputRequired(),
|
||||
Email(),
|
||||
Length(6, 128),
|
||||
],
|
||||
Length(6, 64),
|
||||
hremail,
|
||||
]
|
||||
)
|
||||
|
||||
password = PasswordField(
|
@ -1,8 +1,12 @@
|
||||
"""Reset Password Form form to reset a users PasswordField."""
|
||||
from wtforms import (
|
||||
SubmitField,
|
||||
PasswordField,
|
||||
)
|
||||
|
||||
from wtforms import validators
|
||||
from wtforms.validators import Length, EqualTo
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import PasswordField, SubmitField, validators
|
||||
from wtforms.validators import EqualTo, Length
|
||||
|
||||
|
||||
class ResetPasswordForm(FlaskForm):
|
@ -1,5 +1,5 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import SelectField, SubmitField
|
||||
from wtforms import SubmitField, SelectField
|
||||
|
||||
|
||||
class SelectorForm(FlaskForm):
|
||||
@ -9,6 +9,4 @@ class SelectorForm(FlaskForm):
|
||||
|
||||
update = SubmitField("update")
|
||||
|
||||
describe = SubmitField("describe")
|
||||
|
||||
delete = SubmitField("delete")
|
@ -1,7 +1,9 @@
|
||||
"""Form object declaration."""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import RadioField, SubmitField
|
||||
from wtforms import (
|
||||
RadioField,
|
||||
SubmitField,
|
||||
)
|
||||
|
||||
|
||||
class ThemeForm(FlaskForm):
|
88
verse/forms/uploadform.py
Normal file
88
verse/forms/uploadform.py
Normal file
@ -0,0 +1,88 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileField, FileAllowed, FileRequired, FileSize
|
||||
from wtforms import validators
|
||||
from wtforms.validators import (
|
||||
Length,
|
||||
NumberRange,
|
||||
DataRequired,
|
||||
ValidationError,
|
||||
)
|
||||
from wtforms import (
|
||||
SubmitField,
|
||||
StringField,
|
||||
IntegerField,
|
||||
SelectField,
|
||||
)
|
||||
|
||||
|
||||
class UploadForm(FlaskForm):
|
||||
"""File upload class for a new site in distribusi-verse"""
|
||||
|
||||
def distribusiname(form, field):
|
||||
if field.data.lower() == "new":
|
||||
raise ValidationError("Name has to be unique and not just new.")
|
||||
|
||||
sitename = StringField(
|
||||
"Name of your website:",
|
||||
validators=[validators.InputRequired(), Length(2, 100), distribusiname],
|
||||
)
|
||||
academicyear = SelectField(
|
||||
"Academic year:",
|
||||
validate_choice=True,
|
||||
coerce=str,
|
||||
choices=[
|
||||
(u'2021-2022', u'2021-2022'),
|
||||
(u'2022-2023', u'2022-2023'),
|
||||
(u'2023-2024', u'2023-2024'),
|
||||
(u'2024-2025', u'2024-2025'),
|
||||
(u'2020-2021', u'past: 2020-2021'),
|
||||
],
|
||||
option_widget=None,
|
||||
validators=[DataRequired()]
|
||||
)
|
||||
term = SelectField(
|
||||
"Term:",
|
||||
validate_choice=True,
|
||||
coerce=str,
|
||||
choices=[
|
||||
(u'1.2', u'1.2'),
|
||||
(u'2.3', u'2.3'),
|
||||
(u'3.1', u'3.1'),
|
||||
(u'4.1', u'4.1'),
|
||||
(u'4.2', u'4.2'),
|
||||
],
|
||||
option_widget=None,
|
||||
validators=[DataRequired()]
|
||||
)
|
||||
tags = StringField(
|
||||
"Add tags, seperated by commas. No need for the '#' sign:",
|
||||
validators=[validators.InputRequired(), Length(2, 500)],
|
||||
)
|
||||
|
||||
course = SelectField(
|
||||
u'Course:',
|
||||
validate_choice=True,
|
||||
coerce=str,
|
||||
choices=[
|
||||
('hacking', u'Autonomous - Hacking'),
|
||||
('digitalcraft', u'Autonomous - Digital Craft'),
|
||||
('criticalstudies', u'Autonomous - Critical Studies'),
|
||||
('publicprivate', u'Autonomous - Public&Private'),
|
||||
],
|
||||
option_widget=None,
|
||||
validators=[DataRequired()]
|
||||
)
|
||||
|
||||
zipfile = FileField(
|
||||
"Upload your zip file with content here:",
|
||||
validators=[
|
||||
FileAllowed(["zip"], "Zip archives only!"),
|
||||
FileRequired(),
|
||||
FileSize(
|
||||
max_size=104857600,
|
||||
message="Zipfile size must be smaller than 100MB",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
submit = SubmitField("Upload")
|
@ -14,19 +14,17 @@ config = context.config
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
logger = logging.getLogger("alembic.env")
|
||||
logger = logging.getLogger('alembic.env')
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
config.set_main_option(
|
||||
"sqlalchemy.url",
|
||||
str(current_app.extensions["migrate"].db.get_engine().url).replace(
|
||||
"%", "%%"
|
||||
),
|
||||
)
|
||||
target_metadata = current_app.extensions["migrate"].db.metadata
|
||||
'sqlalchemy.url',
|
||||
str(current_app.extensions['migrate'].db.get_engine().url).replace(
|
||||
'%', '%%'))
|
||||
target_metadata = current_app.extensions['migrate'].db.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
@ -67,20 +65,20 @@ def run_migrations_online():
|
||||
# when there are no changes to the schema
|
||||
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
||||
def process_revision_directives(context, revision, directives):
|
||||
if getattr(config.cmd_opts, "autogenerate", False):
|
||||
if getattr(config.cmd_opts, 'autogenerate', False):
|
||||
script = directives[0]
|
||||
if script.upgrade_ops.is_empty():
|
||||
directives[:] = []
|
||||
logger.info("No changes in schema detected.")
|
||||
logger.info('No changes in schema detected.')
|
||||
|
||||
connectable = current_app.extensions["migrate"].db.get_engine()
|
||||
connectable = current_app.extensions['migrate'].db.get_engine()
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata,
|
||||
process_revision_directives=process_revision_directives,
|
||||
**current_app.extensions["migrate"].configure_args,
|
||||
**current_app.extensions['migrate'].configure_args
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
|
@ -1,18 +0,0 @@
|
||||
from app import db
|
||||
|
||||
|
||||
class DistribusiFiles(db.Model):
|
||||
"""Distribusi file model class for a single file in a distribusi"""
|
||||
|
||||
__tablename__ = "distribusi_files"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=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=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 "<Distribusi_File %r>" % self.path
|
@ -1,11 +0,0 @@
|
||||
"""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")
|
@ -1,42 +0,0 @@
|
||||
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
|
@ -1,52 +0,0 @@
|
||||
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
|
@ -1,23 +0,0 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% block main %}
|
||||
<div id="distribusiverse" class="maincontent">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('search.searchpage') }}">
|
||||
{{ searchform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ searchform.searchfield.label }}
|
||||
{{ searchform.searchfield }}
|
||||
{% for message in searchform.searchfield.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="button required">
|
||||
{{ searchform.submit }}
|
||||
</fieldset>
|
||||
</form>
|
||||
<div class="searchresults">
|
||||
{% for found_distribusi in found_distribusis %}
|
||||
<a href='{{ url_for('shortstashurl')}}/{{found_distribusi}}/index.html'>{{found_distribusi}}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,7 +0,0 @@
|
||||
title = "Varia Archive X Distribusi-Verse"
|
||||
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
|
152
verse/start.py
152
verse/start.py
@ -1,45 +1,50 @@
|
||||
"""This is the main flask distribusi page"""
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from flask import (
|
||||
Blueprint,
|
||||
redirect,
|
||||
render_template,
|
||||
send_from_directory,
|
||||
session,
|
||||
redirect,
|
||||
url_for,
|
||||
session,
|
||||
send_from_directory,
|
||||
Blueprint,
|
||||
)
|
||||
from flask_login import current_user, login_required, logout_user
|
||||
from flask_login import (
|
||||
logout_user,
|
||||
login_required,
|
||||
current_user,
|
||||
)
|
||||
from flask_mail import Mail
|
||||
from flask_wtf.csrf import CSRFError
|
||||
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.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 usermodel import User
|
||||
from distribusimodel import Distribusis
|
||||
|
||||
# Use upload form to populate filters
|
||||
from forms.uploadform import UploadForm
|
||||
|
||||
# Interface! these are seperate files in main folder
|
||||
from adminpage import AdminPage
|
||||
from editor import Editor
|
||||
from themeselector import ThemeSelector
|
||||
from distribusiworkflow import DistribusiWorkflow
|
||||
from distribusiselector import DistribusiSelector
|
||||
from uploadpage import UploadPage
|
||||
|
||||
# UserPengguna
|
||||
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
|
||||
from statuspengguna.loginuser import LoginUser
|
||||
from statuspengguna.registeruser import RegisterUser
|
||||
from statuspengguna.forgotpassword import ForgotPassword
|
||||
from statuspengguna.resetpassword import ResetPassword
|
||||
|
||||
# Distribusi Information
|
||||
from distribusisinfo import DistribusisInfo
|
||||
|
||||
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(admin_page, url_prefix="/admin")
|
||||
APP.register_blueprint(distribusikan, url_prefix="/distribusikan")
|
||||
APP.register_blueprint(searchpages, url_prefix="/search")
|
||||
init_search_index(APP)
|
||||
mail = Mail(APP)
|
||||
|
||||
|
||||
@APP.before_request
|
||||
@ -51,28 +56,32 @@ def session_handler():
|
||||
@APP.route("/")
|
||||
def index():
|
||||
UserHelper.reset_user_state()
|
||||
# http://localhost:5000/themes/publicthemes/RomeroTape/blueskies.css
|
||||
uploadform = UploadForm()
|
||||
distribusis = DistribusisInfo.visible_distribusis()
|
||||
distribusis = DistribusisInfo.visibledistribusis()
|
||||
distribusisindex = {}
|
||||
for distribusi in distribusis:
|
||||
user = User.query.filter_by(id=distribusi.userid).first()
|
||||
singledistribusi = {
|
||||
"username": user.username,
|
||||
"publictheme": distribusi.publictheme,
|
||||
"category": distribusi.category,
|
||||
"term": distribusi.term,
|
||||
"course": distribusi.course,
|
||||
"year": distribusi.year,
|
||||
"tags": distribusi.tags.split(","),
|
||||
}
|
||||
distribusisindex[distribusi.distribusiname] = singledistribusi
|
||||
years = uploadform.academicyear.choices
|
||||
terms = uploadform.term.choices
|
||||
courses = uploadform.course.choices
|
||||
|
||||
years = uploadform.year.choices
|
||||
categories = uploadform.category.choices
|
||||
adminuser = is_adminuser()
|
||||
adminuser = isadminuser()
|
||||
template = render_template(
|
||||
"base/index.html",
|
||||
"index.html",
|
||||
distribusisindex=distribusisindex,
|
||||
years=years,
|
||||
categories=categories,
|
||||
terms=terms,
|
||||
courses=courses,
|
||||
adminuser=adminuser,
|
||||
)
|
||||
return template
|
||||
@ -80,7 +89,26 @@ def index():
|
||||
|
||||
@APP.route("/help")
|
||||
def help():
|
||||
return render_template("base/help.html")
|
||||
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():
|
||||
uploadfolder = APP.config["UPLOAD_FOLDER"]
|
||||
return UploadPage(uploadfolder)
|
||||
|
||||
|
||||
@APP.route("/theme", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def theme():
|
||||
return ThemeSelector()
|
||||
|
||||
|
||||
@APP.route("/publicthemes/<path>")
|
||||
@ -88,14 +116,35 @@ def publicthemes(path):
|
||||
distribusi = Distribusis.query.filter_by(distribusiname=path).first()
|
||||
publicthemefolder = f"publicthemes/{distribusi.distribusiname}/"
|
||||
cssfile = f"{publicthemefolder}/{distribusi.publictheme}.css"
|
||||
print(cssfile)
|
||||
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"))
|
||||
|
||||
|
||||
@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():
|
||||
@ -103,6 +152,26 @@ 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/<path>", 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
|
||||
@ -110,7 +179,14 @@ def handle_csrf_error(e):
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return db.session.get(User, int(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
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Dropdown Button */
|
||||
/* for sorting on year and category
|
||||
/* for sorting on Academicyear, Term, Course
|
||||
*/
|
||||
button {
|
||||
background-color: #9de457;
|
||||
background-color: #E0B0FF;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
}
|
||||
@ -26,7 +26,7 @@ button {
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #9de457;
|
||||
background-color: #E0B0FF;
|
||||
min-width: 120px;
|
||||
border: 2px solid;
|
||||
z-index: 1;
|
||||
|
@ -5,7 +5,7 @@
|
||||
}
|
||||
.editarea {
|
||||
width: 30%;
|
||||
border: 3px solid #9de457;
|
||||
border: 3px solid #E0B0FF;
|
||||
border-style: outset;
|
||||
margin-right: 1em;
|
||||
margin-left: 0;
|
||||
@ -31,7 +31,7 @@ textarea {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 250px;
|
||||
background: #9de457;
|
||||
background: #E0B0FF;
|
||||
outline: none;
|
||||
font-family: Courier, sans-serif;
|
||||
font-size: 16px;
|
||||
@ -45,6 +45,6 @@ iframe {
|
||||
height: 30em;
|
||||
}
|
||||
#html {
|
||||
background-color: #9de457;
|
||||
color: black;
|
||||
background-color: #60337F;
|
||||
color: lightgrey;
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
max-width: 20em;
|
||||
position: relative;
|
||||
border: none;
|
||||
background: #9de457;
|
||||
background: #E0B0FF;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@ -18,7 +18,7 @@
|
||||
max-width: 20em;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: #9de457;
|
||||
background-color: #E0B0FF;
|
||||
background-image: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
@ -41,7 +41,7 @@
|
||||
}
|
||||
select.selector option{
|
||||
color: white;
|
||||
background-color: #9de457;
|
||||
background-color: #60337F;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
@ -49,5 +49,5 @@ select.selector option{
|
||||
outline: none;
|
||||
}
|
||||
.selector-style select option:hover {
|
||||
background: #9de457;
|
||||
background: #60337F;
|
||||
}
|
||||
|
@ -2,17 +2,64 @@ body
|
||||
{
|
||||
font-family: monospace, monospace;
|
||||
font-size: 15px;
|
||||
background-color: #fdfdfd;
|
||||
color:#091411;
|
||||
background-color: #272a33;
|
||||
color:#E0B0FF;
|
||||
word-wrap: break-word;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
div#login{
|
||||
width: 30%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-color:#272a33;
|
||||
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: white;
|
||||
width: 18em;
|
||||
max-width: 18em;
|
||||
background-color: #2D3039;
|
||||
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:#30333f;
|
||||
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: 40em;
|
||||
width: 30em;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
@ -22,16 +69,7 @@ body
|
||||
#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;
|
||||
@ -44,13 +82,13 @@ div#buttons{
|
||||
|
||||
div#buttons .distribusi input{
|
||||
border: none;
|
||||
background: #9de457;
|
||||
background: #fff600;
|
||||
text-decoration: none;
|
||||
margin: 0.2em;
|
||||
}
|
||||
div#buttons .distribusi input:hover{
|
||||
background: #091411;
|
||||
color: #6df2cc;
|
||||
background: #ffbf00;
|
||||
|
||||
}
|
||||
fieldset.required {
|
||||
border: none;
|
||||
@ -63,15 +101,21 @@ 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: #9de457;
|
||||
background: #E0B0FF;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@ -80,9 +124,7 @@ input {
|
||||
}
|
||||
|
||||
input:hover {
|
||||
background: #091411;
|
||||
color: #6df2cc;
|
||||
cursor: pointer;
|
||||
background: #60337F;
|
||||
}
|
||||
|
||||
input[type="submit"]:disabled:hover,
|
||||
@ -102,11 +144,37 @@ input[type="submit"]:disabled:focus {
|
||||
background-color: #F92020;
|
||||
}
|
||||
|
||||
#update, #describe {
|
||||
#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: "$ ";
|
||||
@ -127,7 +195,7 @@ input[type="submit"]:disabled:focus {
|
||||
white-space: nowrap;
|
||||
animation: reveal 4s linear;
|
||||
text-overflow: "█";
|
||||
background-color: #9de457;
|
||||
background-color: #2D3039;
|
||||
}
|
||||
#fancyboi::after {
|
||||
content: "█";
|
||||
@ -137,7 +205,7 @@ input[type="submit"]:disabled:focus {
|
||||
|
||||
div.maincontent{
|
||||
width: 55%;
|
||||
border: 3px #9de457;
|
||||
border: 3px #E0B0FF;
|
||||
margin-top: 0.5em;
|
||||
padding: 0.5em;
|
||||
border-style: outset;
|
||||
@ -176,6 +244,8 @@ 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;
|
||||
}
|
||||
@ -190,7 +260,7 @@ div.maincontent{
|
||||
color: black;
|
||||
padding: 1em;
|
||||
box-sizing: border-box;
|
||||
background: #9de457;
|
||||
background: #E0B0FF;
|
||||
outline: none;
|
||||
font-family: Courier, sans-serif;
|
||||
font-size: 16px;
|
||||
@ -198,11 +268,11 @@ div.maincontent{
|
||||
/*
|
||||
Project colors so far.
|
||||
light
|
||||
#9de457
|
||||
#E0B0FF
|
||||
medium
|
||||
#d28cff
|
||||
dark
|
||||
#9de457
|
||||
#60337F
|
||||
|
||||
background dark
|
||||
#2D3039
|
||||
|
@ -24,8 +24,9 @@ function filterSelection(c, name, id) {
|
||||
}
|
||||
|
||||
function resetDropDownButtons(){
|
||||
document.getElementById("Year").innerText = "Year";
|
||||
document.getElementById("Category").innerText = "Category";
|
||||
document.getElementById("Academicyear").innerText = "Academic year";
|
||||
document.getElementById("Term").innerText = "Term";
|
||||
document.getElementById("Course").innerText = "Course";
|
||||
allactivebuttons = document.getElementsByClassName("activebtn");
|
||||
for(var i = 0;allactivebuttons.length; i++) {
|
||||
removeClass(allactivebuttons[i], "activebtn");
|
||||
|
@ -1,31 +1,17 @@
|
||||
from datetime import datetime
|
||||
from uuid import uuid1
|
||||
|
||||
from flask import Blueprint, render_template
|
||||
from flask_mail import Mail, Message
|
||||
from datetime import datetime
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
from flask import render_template
|
||||
from flask_mail import Message
|
||||
|
||||
from app import db, get_app
|
||||
from statuspengguna.forms.forgotpasswordform import ForgotPasswordForm
|
||||
from models.user_model 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)
|
||||
from usermodel import User
|
||||
from forms.forgotpasswordform import ForgotPasswordForm
|
||||
from app import db
|
||||
|
||||
|
||||
def ForgotPassword(mail):
|
||||
|
@ -1,18 +1,17 @@
|
||||
import os
|
||||
|
||||
from flask import flash
|
||||
from flask_login import current_user
|
||||
from flask import flash
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
|
||||
from usermodel import User
|
||||
from distribusimodel import Distribusis
|
||||
from distribusisinfo import DistribusisInfo
|
||||
from app import db
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
|
||||
|
||||
class UserHelper:
|
||||
@ -76,10 +75,11 @@ class UserHelper:
|
||||
|
||||
def distribusi_limit_reached():
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
distribusiamount = len(
|
||||
DistribusisInfo.get_user_distribusis(user.email)
|
||||
)
|
||||
if distribusiamount > 19:
|
||||
print("user already has 20 distribusis")
|
||||
distribusiamount = len(DistribusisInfo.getuserdistribusis(user.email))
|
||||
if user.tutor and distribusiamount > 14:
|
||||
print("tutor already has 15 distribusis")
|
||||
return True
|
||||
if not user.tutor and distribusiamount > 4:
|
||||
print("user already has 5 distribusis")
|
||||
return True
|
||||
return False
|
||||
|
@ -1,29 +1,15 @@
|
||||
from flask import (
|
||||
Blueprint,
|
||||
abort,
|
||||
flash,
|
||||
redirect,
|
||||
render_template,
|
||||
redirect,
|
||||
request,
|
||||
flash,
|
||||
url_for,
|
||||
abort,
|
||||
)
|
||||
from flask_bcrypt import check_password_hash
|
||||
from usermodel import User
|
||||
from forms.loginform import LoginForm
|
||||
from flask_login import login_user
|
||||
|
||||
from statuspengguna.forms.loginform import LoginForm
|
||||
from models.user_model import User
|
||||
|
||||
login_section = Blueprint(
|
||||
"login",
|
||||
__name__,
|
||||
template_folder="templates/statuspengguna",
|
||||
static_folder="static",
|
||||
)
|
||||
|
||||
|
||||
@login_section.route("/", methods=["GET", "POST"])
|
||||
def login():
|
||||
return LoginUser()
|
||||
from flask_bcrypt import check_password_hash
|
||||
|
||||
|
||||
def LoginUser():
|
||||
@ -39,9 +25,7 @@ def LoginUser():
|
||||
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")
|
||||
|
@ -1,30 +1,22 @@
|
||||
from flask import Blueprint, flash, redirect, render_template, url_for
|
||||
from flask_bcrypt import generate_password_hash
|
||||
from flask_login import login_user
|
||||
from flask import (
|
||||
render_template,
|
||||
redirect,
|
||||
flash,
|
||||
url_for,
|
||||
)
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
IntegrityError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
from werkzeug.routing import BuildError
|
||||
|
||||
from usermodel import User
|
||||
from forms.registerform import RegisterForm
|
||||
from flask_login import login_user
|
||||
from flask_bcrypt import generate_password_hash
|
||||
from app import db
|
||||
from statuspengguna.forms.registerform import RegisterForm
|
||||
from models.user_model 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():
|
||||
|
@ -1,32 +1,23 @@
|
||||
from datetime import datetime
|
||||
|
||||
from flask import Blueprint, flash, redirect, render_template, url_for
|
||||
from flask_bcrypt import generate_password_hash
|
||||
from flask_login import login_user
|
||||
from flask import (
|
||||
render_template,
|
||||
redirect,
|
||||
flash,
|
||||
url_for,
|
||||
)
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
IntegrityError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
from werkzeug.routing import BuildError
|
||||
|
||||
from usermodel import User
|
||||
from forms.resetpasswordform import ResetPasswordForm
|
||||
from flask_login import login_user
|
||||
from flask_bcrypt import generate_password_hash
|
||||
from app import db
|
||||
from statuspengguna.forms.resetpasswordform import ResetPasswordForm
|
||||
from models.user_model import User
|
||||
|
||||
reset_password = Blueprint(
|
||||
"reset_password",
|
||||
__name__,
|
||||
template_folder="templates/statuspengguna",
|
||||
static_folder="static",
|
||||
)
|
||||
|
||||
|
||||
@reset_password.route("/resetpassword/<path>", methods=["GET", "POST"])
|
||||
def resetpassword(path):
|
||||
return ResetPassword(path)
|
||||
|
||||
|
||||
def ResetPassword(path):
|
||||
|
@ -1,22 +0,0 @@
|
||||
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;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="buttons">
|
||||
<div class="overview">
|
||||
@ -14,6 +14,9 @@
|
||||
</div>
|
||||
<div class="maincontent">
|
||||
<h2>Admin Page</h2>
|
||||
<p>Here you can bulk delete distribusis and users or make users into tutors
|
||||
<strong> These actions cannot be undone! </strong>
|
||||
</p>
|
||||
<div id="distribusiverse" class="maincontent">
|
||||
<h2>List of distribusis</h2>
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('admin') }}">
|
||||
@ -50,6 +53,12 @@
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<fieldset class="button required">
|
||||
{{ adminuserform.tutors }}
|
||||
</fieldset>
|
||||
<fieldset class="button required">
|
||||
{{ adminuserform.nottutors }}
|
||||
</fieldset>
|
||||
<fieldset class="button required">
|
||||
{{ adminuserform.delete }}
|
||||
</fieldset>
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{title}}</title>
|
||||
<title>Autonomous Practices X Distribusi-Verse</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css')}}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/selector.css')}}">
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
@ -1,20 +0,0 @@
|
||||
{% block menu %}
|
||||
<button onclick="filterSelection('all')" id="removefilter">Remove filter</button>
|
||||
<div class="dropdown">
|
||||
<button id="Year" class="dropbtn">Year</button>
|
||||
<div class="dropdown-content">
|
||||
{% for year in years %}
|
||||
<button type="button" name="button" onclick="filterSelection('{{ year[0] }}', '{{ year[1] }}', 'Year')" >{{ year[1] }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button id="Category" class="dropbtn">Category</button>
|
||||
<div class="dropdown-content">
|
||||
{% for category in categories %}
|
||||
<button type="button" name="button" onclick="filterSelection('{{ category[0] }}', '{{ category[1] }}', 'Category')" >{{ category[1] }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<input id="tagsearch" type="text" placeholder="Search..">
|
||||
{% endblock menu %}
|
@ -1,4 +1,4 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="buttons">
|
||||
<div class="overview">
|
||||
@ -20,28 +20,27 @@
|
||||
<div id="mainworkflow">
|
||||
{% if selectorvisible %}
|
||||
{% block selector %}
|
||||
{% include "distribusi_workflow/selector.html" %}
|
||||
{% include "distribusiworkflow/selector.html" %}
|
||||
{% endblock selector%}
|
||||
{% else %}
|
||||
{% block upload %}
|
||||
{% include "distribusi_workflow/upload.html" %}
|
||||
{% include "distribusiworkflow/upload.html" %}
|
||||
{% endblock upload%}
|
||||
<img src="{{ url_for('static', filename='svg/arrow_1.svg')}}" />
|
||||
{% block theme %}
|
||||
{% include "distribusi_workflow/theme.html" %}
|
||||
{% include "distribusiworkflow/theme.html" %}
|
||||
{% endblock theme%}
|
||||
<img src="{{ url_for('static', filename='svg/arrow_2.svg')}}" />
|
||||
{% block editcss %}
|
||||
{% include "distribusi_workflow/editcss.html" %}
|
||||
{% include "distribusiworkflow/editcss.html" %}
|
||||
{% endblock editcss%}
|
||||
<img src="{{ url_for('static', filename='svg/arrow_3.svg')}}" />
|
||||
{% block launch %}
|
||||
{% include "distribusi_workflow/launch.html" %}
|
||||
{% include "distribusiworkflow/launch.html" %}
|
||||
{% endblock launch%}
|
||||
{%endif%}
|
||||
</div>
|
||||
{% if css_selected %}
|
||||
<p id="cssSelected" hidden>css selected</p>
|
||||
{% endif %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('distribusikan.static', filename='css/distribusikan.css')}}">
|
||||
{% endblock main %}
|
@ -1,10 +1,10 @@
|
||||
<div id="edit" class="workflow">
|
||||
<h2>Step 3: Edit Custom CSS (Optional)</h2>
|
||||
{% if files_uploaded or distribusi_live %}
|
||||
<p><a href="/distribusikan/editor">Go to CSS editor</a></p>
|
||||
<p><a href="/editor">Go to CSS editor</a></p>
|
||||
{% else %}
|
||||
<p>
|
||||
You need to upload your files first before you can select a css theme
|
||||
You need to upload your files first before you can a css theme
|
||||
for your files.
|
||||
</p>
|
||||
<p><a href="#upload">Go to Step 1</a></p>
|
@ -3,7 +3,7 @@
|
||||
<p class="tooltip">Run distribusi on your files. This will generate your website and make
|
||||
your content public. <span class="tooltiptext">Distribusi will unpack your zip file and turn it into a website!
|
||||
</span></p>
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('distribusikan.distribusi') }}">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('distribusi') }}">
|
||||
{{ distribusiform.csrf_token }}
|
||||
{% if files_uploaded or distribusi_live %}
|
||||
<fieldset class="button required">
|
@ -1,7 +1,7 @@
|
||||
<div id="distribusi" class="workflow">
|
||||
<h2>Welcome back to your Distribusi</h2>
|
||||
<p>You have already uploaded a distribusi website:</p>
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('distribusikan.selector') }}">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('selector') }}">
|
||||
{{ selectorform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ selectorform.distribusis.label }}
|
||||
@ -18,13 +18,6 @@
|
||||
{{ selectorform.update }}
|
||||
</fieldset>
|
||||
<hr>
|
||||
<p>
|
||||
Describe your distribusi files. Add description texts, tags for search
|
||||
or add alt-text for images</p>
|
||||
<fieldset class="button required multiselect">
|
||||
{{ selectorform.describe }}
|
||||
</fieldset>
|
||||
<hr>
|
||||
<p>
|
||||
This will delete your distribusi site.
|
||||
<strong> This action cannot be undone! </strong>
|
||||
@ -36,7 +29,6 @@
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<hr>
|
||||
<div class="new_divider"></div>
|
||||
{% if limit_reached %}
|
||||
<p>You have reached your limit of distribusi websites</p>
|
||||
{% else %}
|
@ -4,7 +4,7 @@
|
||||
step 3.</p>
|
||||
<p>Don't forget to press Save</p>
|
||||
<hr>
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('distribusikan.theme') }}">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('theme') }}">
|
||||
{{ themeform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ themeform.theme.label }}
|
||||
@ -16,14 +16,14 @@
|
||||
</fieldset>
|
||||
{% else %}
|
||||
<p>
|
||||
You need to upload your files first before you can select a css theme
|
||||
You need to upload your files first before you can a css theme
|
||||
for your files.
|
||||
</p>
|
||||
<a href="#upload">Go to Step 1</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
<hr>
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('distribusikan.theme') }}">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('theme') }}">
|
||||
{{ publicthemeform.csrf_token }}
|
||||
<fieldset id="publicthemes" class="required">
|
||||
{{ publicthemeform.publicthemes.label }}
|
||||
@ -35,7 +35,7 @@
|
||||
</fieldset>
|
||||
{% else %}
|
||||
<p>
|
||||
You need to upload your files first before you can select a css theme
|
||||
You need to upload your files first before you can a css theme
|
||||
for your files.
|
||||
</p>
|
||||
<a href="#upload">Go to Step 1</a>
|
@ -1,7 +1,7 @@
|
||||
<div id="upload" class="workflow">
|
||||
<h2>Step 1: Upload</h2>
|
||||
<p>Upload your files here:</p>
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('distribusikan.upload') }}">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('upload') }}">
|
||||
{{ uploadform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ uploadform.sitename.label }}
|
||||
@ -11,26 +11,28 @@
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="required">
|
||||
{{ uploadform.description.label }}
|
||||
{{ uploadform.description }}
|
||||
{% for message in uploadform.description.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="required">
|
||||
{{ uploadform.year.label }}
|
||||
{{ uploadform.academicyear.label }}
|
||||
<div class="selector-style">
|
||||
{{ uploadform.year }}
|
||||
{% for message in uploadform.year.errors %}
|
||||
{{ uploadform.academicyear }}
|
||||
{% for message in uploadform.academicyear.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="required">
|
||||
{{ uploadform.category.label }}
|
||||
{{ uploadform.term.label }}
|
||||
<div class="selector-style">
|
||||
{{ uploadform.category }}
|
||||
{% for message in uploadform.category.errors %}
|
||||
{{ uploadform.term }}
|
||||
{% for message in uploadform.term.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="required">
|
||||
{{ uploadform.course.label }}
|
||||
<div class="selector-style">
|
||||
{{ uploadform.course }}
|
||||
{% for message in uploadform.course.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
@ -1,11 +1,11 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('distribusikan.editor') }}" class="editform">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('editor') }}" class="editform">
|
||||
<div class="editareas">
|
||||
<div class="editarea editor">
|
||||
<fieldset class="required">
|
||||
<textarea id="html" placeholder="Write some test HTML here" readonly>
|
||||
{{html_placeholder}}
|
||||
{{htmlplaceholder}}
|
||||
</textarea>
|
||||
</fieldset>
|
||||
</div>
|
||||
@ -54,6 +54,6 @@
|
||||
</form>
|
||||
<iframe id="code"></iframe>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('distribusikan.static', filename='css/editor.css')}}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/editor.css')}}">
|
||||
<script src="{{ url_for('static', filename='js/editorupdate.js')}}"></script>
|
||||
{% endblock main %}
|
28
verse/templates/filtermenu.html
Normal file
28
verse/templates/filtermenu.html
Normal file
@ -0,0 +1,28 @@
|
||||
{% block menu %}
|
||||
<button onclick="filterSelection('all')" id="removefilter">Remove filter</button>
|
||||
<div class="dropdown">
|
||||
<button id="Academicyear" class="dropbtn">Academic year</button>
|
||||
<div class="dropdown-content">
|
||||
{% for year in years %}
|
||||
<button type="button" name="button" onclick="filterSelection('{{ year[0] }}', '{{ year[1] }}', 'Academicyear')" >{{ year[1] }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button id="Term" class="dropbtn">Term</button>
|
||||
<div class="dropdown-content">
|
||||
{% for term in terms %}
|
||||
<button type="button" name="button" onclick="filterSelection('{{ term[0] }}', '{{ term[1] }}', 'Term')" >{{ term[1] }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button id="Course" class="dropbtn">Course</button>
|
||||
<div class="dropdown-content">
|
||||
{% for course in courses %}
|
||||
<button type="button" name="button" onclick="filterSelection('{{ course[0] }}' , '{{ course[1] }}', 'Course')" >{{ course[1] }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<input id="tagsearch" type="text" placeholder="Search..">
|
||||
{% endblock menu %}
|
@ -1,13 +1,12 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="mainworkflow">
|
||||
<div class="login">
|
||||
<div class="workflow">
|
||||
<h2>Forgot your password?</h2>
|
||||
<p>
|
||||
Enter the email address that was used to register with Distribusiverse.
|
||||
</p>
|
||||
<form class="form" action="{{ url_for('forgotpassword.forgotpassword') }}"
|
||||
method="post">
|
||||
<form class="form" action="{{ url_for('forgotpassword') }}" method="post">
|
||||
{{ forgotpasswordform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ forgotpasswordform.email.label }}
|
||||
@ -26,6 +25,5 @@
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('forgotpassword.static', filename='css/login.css')}}">
|
||||
</div
|
||||
{% endblock main %}
|
@ -1,4 +1,4 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="buttons">
|
||||
<div class="overview">
|
||||
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="distribusi">
|
||||
<a href="distribusikan/distribusi">
|
||||
<a href="/distribusi">
|
||||
<input type="button" name="button" value="Distribusi"></input>
|
||||
</a>
|
||||
</div>
|
@ -1,4 +1,4 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="buttons">
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="distribusi">
|
||||
<a href="distribusikan/distribusi">
|
||||
<a href="/distribusi">
|
||||
<input type="button" name="button" value="Distribusi"></input>
|
||||
</a>
|
||||
</div>
|
||||
@ -46,14 +46,19 @@
|
||||
<div class="maincontent">
|
||||
<p>Distribusi is a content management system for the web that produces static index pages based on folders in the files system. It is inspired by the automatic index functions featured in several popular web servers. Distribusi works by traversing the file system and directory hierarchy to automatically list all the files in the directory, detect the file types and providing them with relevant html classes and tags for easy styling.
|
||||
</p>
|
||||
<hr>
|
||||
<p>
|
||||
This particular work in progress project <strong>Distribusi-verse</strong> is an attempt to make distribusi into a webinterface that can be operated remotely without any knowlegde of CLI. Attempting to combine the ideas of distribusi with the ideas of a <a href="https://tildeverse.org/">Tildeverse</a> and <a href="https://tilde.club/">Tilde club</a>, but also be neither of these ideas. See a full list of tildeverse members <a href="https://tildeverse.org/members/">here</a>.</p>
|
||||
<hr>
|
||||
<p>This project is made for <a href="https://www.wdka.nl/practices/autonomous-practices/">Autonomous Practices </a>at the <a href="https://www.wdka.nl/">WDKA</a> in Rotterdam.</p>
|
||||
</div>
|
||||
<!-- a div with all the distribusis listed in the distribusiverse -->
|
||||
<div id="distribusiverse" class="maincontent">
|
||||
<h2>List of distribusis</h2>
|
||||
{% include 'base/filtermenu.html' %}
|
||||
{% include 'filtermenu.html' %}
|
||||
<ul id="distribusi-index">
|
||||
{% for name, distribusi in distribusisindex.items() %}
|
||||
<li class='distribusi filter {{ distribusi["category"] }} {{ distribusi["year"] }} '>
|
||||
<li class='distribusi filter {{ distribusi["term"] }} {{ distribusi["year"] }} {{ distribusi["course"] }}'>
|
||||
<a href='stash/{{name}}/index.html'>{{distribusi["username"]}}:{{name}}</a>
|
||||
{% for tag in distribusi["tags"] %}
|
||||
<span class="tags">{{tag}}</span>
|
@ -1,7 +1,7 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="login">
|
||||
<form class="form" action="{{ url_for('login.login') }}" method="post">
|
||||
<form class="form" action="{{ url_for('login') }}" method="post">
|
||||
{{ loginform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ loginform.email.label }}
|
||||
@ -19,9 +19,8 @@
|
||||
</fieldset>
|
||||
<fieldset class="button required">
|
||||
{{ loginform.submit }}
|
||||
<a href="forgotpassword">Forgot Password?</a>
|
||||
<a href="/forgotpassword">Forgot Password?</a>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('login.static', filename='css/login.css')}}">
|
||||
{% endblock main %}
|
@ -1,7 +1,7 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="login">
|
||||
<form class="form" action="{{ url_for('register.register') }}" method="post">
|
||||
<form class="form" action="{{ url_for('register') }}" method="post">
|
||||
{{ registerform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ registerform.username.label }}
|
||||
@ -36,5 +36,4 @@
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('register.static', filename='css/login.css')}}">
|
||||
{% endblock main %}
|
@ -1,4 +1,4 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div id="login">
|
||||
{% if linkvalid%}
|
||||
@ -26,5 +26,4 @@
|
||||
<h3>Password reset link no longer valid.</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('reset_password.static', filename='css/login.css')}}">
|
||||
{% endblock main %}
|
@ -6,14 +6,14 @@
|
||||
|
||||
<div id="willemdekooning-logo" class="png">
|
||||
<figure>
|
||||
<img class="image" src="https://varia.zone/archive/00-varia-server/welcome.png">
|
||||
<img class="image" src="https://www.wdka.nl/build/img/willemdekooning-logo.png">
|
||||
<figcaption>logo.png</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div id="example_video" class="mp4">
|
||||
<video controls>
|
||||
<source src="https://vvvvvvaria.org/~crunk/box/tomb_of_doom-2021-02-13_21.41.03.mp4">
|
||||
<source src="example_video.mp4">
|
||||
</video>
|
||||
<span class="filename">example_video.mp4</span>
|
||||
</div>
|
||||
|
@ -1,47 +1,49 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from flask import render_template
|
||||
|
||||
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
|
||||
from distribusisinfo import DistribusisInfo
|
||||
|
||||
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
|
||||
|
||||
|
||||
def theme_selector():
|
||||
def ThemeSelector():
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if themeform.validate_on_submit():
|
||||
copycssfile = os.path.join(
|
||||
"themes",
|
||||
f"{themeform.theme.data}.css",
|
||||
)
|
||||
move_css_to_user_folder(current_distribusi, copycssfile)
|
||||
MoveCssToUserFolder(current_distribusi, copycssfile)
|
||||
if publicthemeform.validate_on_submit():
|
||||
copycssfile = os.path.join(
|
||||
"themes/publicthemes/",
|
||||
f"{publicthemeform.publicthemes.data}.css",
|
||||
)
|
||||
move_css_to_user_folder(current_distribusi, copycssfile)
|
||||
return render_distribusi_template(
|
||||
themeform, publicthemeform, current_distribusi
|
||||
MoveCssToUserFolder(current_distribusi, copycssfile)
|
||||
return RenderDistribusiTemplate(
|
||||
themeform,
|
||||
publicthemeform,
|
||||
current_distribusi
|
||||
)
|
||||
|
||||
|
||||
def move_css_to_user_folder(current_distribusi, copycssfile):
|
||||
def MoveCssToUserFolder(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 render_distribusi_template(themeform, publicthemeform, current_distribusi):
|
||||
def RenderDistribusiTemplate(themeform, publicthemeform, current_distribusi):
|
||||
uploadform = UploadForm()
|
||||
distribusiform = DistribusiForm()
|
||||
selectorform = SelectorForm()
|
@ -1,25 +1,25 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from flask import flash
|
||||
from flask_login import current_user
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
IntegrityError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
DataError,
|
||||
InterfaceError,
|
||||
DatabaseError,
|
||||
)
|
||||
|
||||
from app import db
|
||||
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 usermodel import User
|
||||
from distribusimodel import Distribusis
|
||||
|
||||
from statuspengguna.helper import UserHelper
|
||||
from distribusiselector import SelectCurrentDistribusi
|
||||
from forms.uploadform import UploadForm
|
||||
|
||||
|
||||
def upload_new_distribusi(uploadfolder):
|
||||
def UploadNewDistribusi(uploadfolder):
|
||||
uploadform = UploadForm()
|
||||
if uploadform.validate_on_submit():
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
@ -27,9 +27,9 @@ def upload_new_distribusi(uploadfolder):
|
||||
newdistribusi = Distribusis(
|
||||
distribusiname=uploadform.sitename.data,
|
||||
userid=user.id,
|
||||
category=uploadform.category.data,
|
||||
description=uploadform.description.data,
|
||||
year=uploadform.year.data,
|
||||
term=uploadform.term.data,
|
||||
course=uploadform.course.data,
|
||||
year=uploadform.academicyear.data,
|
||||
tags=uploadform.tags.data,
|
||||
)
|
||||
user.currentdistribusi = uploadform.sitename.data
|
||||
@ -47,7 +47,7 @@ def upload_new_distribusi(uploadfolder):
|
||||
uploadform.sitename.errors.append("Something went wrong!")
|
||||
flash("Something went wrong!", "danger")
|
||||
return uploadform
|
||||
select_current_distribusi(newdistribusi.distribusiname)
|
||||
SelectCurrentDistribusi(newdistribusi.distribusiname)
|
||||
zipfilename = "{}.zip".format(newdistribusi.distribusiname)
|
||||
zipfile = uploadform.zipfile.data
|
||||
zipfile.save(os.path.join(uploadfolder, zipfilename))
|
||||
@ -63,7 +63,7 @@ def upload_new_distribusi(uploadfolder):
|
||||
return uploadform
|
||||
|
||||
|
||||
def upload_updates_files(uploadfolder):
|
||||
def UploadUpdatedFiles(uploadfolder):
|
||||
uploadform = UploadForm()
|
||||
if uploadform.validate_on_submit():
|
||||
try:
|
||||
@ -71,9 +71,9 @@ def upload_updates_files(uploadfolder):
|
||||
distribusi = Distribusis.query.filter_by(
|
||||
distribusiname=current_distribusi
|
||||
).first()
|
||||
distribusi.category = uploadform.category.data
|
||||
distribusi.description = (uploadform.description.data,)
|
||||
distribusi.year = uploadform.year.data
|
||||
distribusi.term = uploadform.term.data
|
||||
distribusi.course = uploadform.course.data
|
||||
distribusi.year = uploadform.academicyear.data
|
||||
distribusi.tags = uploadform.tags.data
|
||||
distribusi.visible = False
|
||||
db.session.commit()
|
@ -1,34 +1,33 @@
|
||||
from flask import render_template
|
||||
|
||||
from app import APP
|
||||
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
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.themeform import ThemeForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
from forms.selectorform import SelectorForm
|
||||
|
||||
# UserPengguna
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
from upload import UploadNewDistribusi, UploadUpdatedFiles
|
||||
from distribusisinfo import DistribusisInfo
|
||||
from distribusiselector import SelectorVisible
|
||||
|
||||
def upload_page():
|
||||
|
||||
def UploadPage(uploadfolder):
|
||||
"render upload page section of distribusi workflow"
|
||||
uploadfolder = APP.config["UPLOAD_FOLDER"]
|
||||
distribusiform = DistribusiForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
selectorform = SelectorForm()
|
||||
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames()
|
||||
selectorvisible = selector_visible()
|
||||
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
|
||||
selectorvisible = SelectorVisible()
|
||||
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if current_distribusi == "new" or UserHelper.has_distribusi() is False:
|
||||
uploadform = upload_new_distribusi(uploadfolder)
|
||||
uploadform = UploadNewDistribusi(uploadfolder)
|
||||
else:
|
||||
uploadform = upload_updates_files(uploadfolder)
|
||||
uploadform = UploadUpdatedFiles(uploadfolder)
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data)
|
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
|
@ -1,6 +1,5 @@
|
||||
from flask_login import UserMixin
|
||||
|
||||
from app import db
|
||||
from flask_login import UserMixin
|
||||
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
@ -15,6 +14,8 @@ class User(UserMixin, db.Model):
|
||||
currentdistribusi = db.Column(db.String(300), nullable=True, unique=False)
|
||||
resethash = db.Column(db.String(300), nullable=True, unique=True)
|
||||
resettime = db.Column(db.DateTime)
|
||||
#active = db.Column(db.Boolean, default=False)
|
||||
tutor = db.Column(db.Boolean, default=False)
|
||||
admin = db.Column(db.Boolean, default=False)
|
||||
|
||||
def __repr__(self):
|
Loading…
Reference in New Issue
Block a user