Compare commits

..

No commits in common. "main" and "current_wdka_release" have entirely different histories.

82 changed files with 893 additions and 1466 deletions

2
.gitignore vendored
View File

@ -3,12 +3,10 @@
*.pyc *.pyc
*.egg-info/ *.egg-info/
.eggs/ .eggs/
.ruff_cache
build/ build/
dist/ dist/
pip-wheel-metadata/ pip-wheel-metadata/
verse/tmpupload/* verse/tmpupload/*
verse/stash/* verse/stash/*
verse/search/searchdata/*
*.db *.db

View File

@ -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 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. This project is made for Autonomous Practices at the WDKA in Rotterdam.
The second stage of this project might be the archiving part of the [Toolsheds fellowship.](https://nieuweinstituut.nl/en/articles/call-for-fellows-tool-sheds)
## Work in progress ## Work in progress
Currently this repo is transforming the academic based search filters into adjustable 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.
small Autonomous space filters.
## Start your engines! ## Start your engines!

34
notes.md Normal file
View 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

View File

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

View File

@ -1,57 +1,48 @@
alembic==1.7.5 alembic==1.7.5
APScheduler==3.10.4
Babel==2.9.1 Babel==2.9.1
bcrypt==3.2.0 bcrypt==3.2.0
black==24.4.0 black==21.11b1
bleach==4.1.0 bleach==4.1.0
bleach-allowlist==1.0.3 bleach-allowlist==1.0.3
blinker==1.7.0 blinker==1.4
cffi cffi==1.15.0
click==8.1.7 click==8.0.3
distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@3eefd6e5ca7048555d441df8c6fbf4f2e255acac
dnspython==2.1.0 dnspython==2.1.0
email-validator==1.1.3 email-validator==1.1.3
Flask==3.0.3 Flask==2.0.2
Flask-APScheduler==1.13.1
Flask-BabelEx==0.9.4 Flask-BabelEx==0.9.4
Flask-Bcrypt==1.0.1 Flask-Bcrypt==0.7.1
Flask-Login==0.6.3 Flask-Login==0.5.0
Flask-Mail==0.9.1 Flask-Mail==0.9.1
Flask-Migrate==3.1.0 Flask-Migrate==3.1.0
Flask-Principal==0.4.0 Flask-Principal==0.4.0
Flask-Security==3.0.0 Flask-Security==3.0.0
Flask-Security-Too==4.1.3 Flask-Security-Too==4.1.3
Flask-SQLAlchemy==3.1.1 Flask-SQLAlchemy==2.5.1
Flask-WTF==1.2.1 Flask-WTF==1.0.0
greenlet==3.0.3 greenlet==1.1.2
idna==3.3 idna==3.3
isort==5.13.2 itsdangerous==2.0.1
itsdangerous==2.2.0 Jinja2==3.0.3
Jinja2==3.1.3
Mako==1.1.6 Mako==1.1.6
MarkupSafe==2.1.5 MarkupSafe==2.0.1
msgpack==1.0.8
mypy-extensions==0.4.3 mypy-extensions==0.4.3
neovim==0.3.1 packaging==21.3
packaging==24.0
passlib==1.7.4 passlib==1.7.4
pathspec==0.9.0 pathspec==0.9.0
Pillow Pillow==8.3.2
platformdirs==2.4.0 platformdirs==2.4.0
pycparser==2.21 pycparser==2.21
pynvim==0.5.0
pyparsing==3.0.7 pyparsing==3.0.7
python-dateutil==2.9.0.post0
python-magic==0.4.24 python-magic==0.4.24
pytz==2021.3 pytz==2021.3
regex regex==2021.11.10
six==1.16.0 six==1.16.0
speaklater==1.3 speaklater==1.3
SQLAlchemy==2.0.29 SQLAlchemy==1.4.27
tomli==1.2.2 tomli==1.2.2
typing_extensions==4.11.0 typing_extensions==4.0.1
tzlocal==5.2
webencodings==0.5.1 webencodings==0.5.1
Werkzeug==3.0.2 Werkzeug==2.0.2
Whoosh==2.7.4
WTForms==3.0.0 WTForms==3.0.0
distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi

View File

@ -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())

View File

@ -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

View File

@ -1,44 +1,36 @@
import os import os
import shutil 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 ( from sqlalchemy.exc import (
DatabaseError,
DataError, DataError,
DatabaseError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db 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( from usermodel import User
"admin", from distribusimodel import Distribusis
__name__, from distribusisinfo import DistribusisInfo
template_folder="templates/describe_files",
static_folder="static", from forms.adminuserform import AdminUserForm
) from forms.admindistribusiform import AdminDistribusiForm
@admin_page.route("/admin", methods=["GET", "POST"]) def AdminPage():
@login_required adminuserform = AddUsersToForm(AdminUserForm())
def admin(): admindistribusiform = AddDistribusisToForm(AdminDistribusiForm())
if not is_adminuser():
return redirect(url_for("index"))
adminuserform = add_users_to_form(AdminUserForm())
admindistribusiform = add_distribusis_to_form(AdminDistribusiForm())
if admindistribusiform.validate_on_submit(): if admindistribusiform.validate_on_submit():
delete_distribusis(admindistribusiform) DeleteDistribusis(admindistribusiform)
if adminuserform.validate_on_submit(): if adminuserform.validate_on_submit():
if adminuserform.delete.data: 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( template = render_template(
"admin.html", "admin.html",
@ -48,18 +40,36 @@ def admin():
return template return template
def delete_users(adminuserform): def DeleteUsers(adminuserform):
for userform in adminuserform: for userform in adminuserform:
if "user" in userform.id: if "user" in userform.id:
if userform.data: if userform.data:
useremail = userform.label.text useremail = userform.label.text
user = User.query.filter_by(email=useremail).first() user = User.query.filter_by(email=useremail).first()
delete_User_distribusis(user) DeleteUserDistribusis(user)
delete_user_from_db(user) DeleteUserFromDb(user)
userform.errors.append(f"User {useremail} deleted!") 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: try:
db.session.delete(user) db.session.delete(user)
db.session.commit() db.session.commit()
@ -67,14 +77,14 @@ def delete_user_from_db(user):
db.session.rollback() db.session.rollback()
def delete_User_distribusis(user): def DeleteUserDistribusis(user):
distribusis = DistribusisInfo.get_user_distribusis(user.email) distribusis = DistribusisInfo.getuserdistribusis(user.email)
for distribusi in distribusis: for distribusi in distribusis:
delete_distribusi_files(distribusi.distribusiname) DeleteDistribusiFiles(distribusi.distribusiname)
delete_distribusi_from_db(distribusi) DeleteDistribusiFromDb(distribusi)
def delete_distribusis(admindistribusiform): def DeleteDistribusis(admindistribusiform):
for distribusiform in admindistribusiform: for distribusiform in admindistribusiform:
if "distribusi" in distribusiform.id: if "distribusi" in distribusiform.id:
if distribusiform.data: if distribusiform.data:
@ -82,12 +92,12 @@ def delete_distribusis(admindistribusiform):
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=distribusiname distribusiname=distribusiname
).first() ).first()
delete_distribusi_from_db(distribusi) DeleteDistribusiFromDb(distribusi)
delete_distribusi_files(distribusiname) DeleteDistribusiFiles(distribusiname)
distribusiform.errors.append("Deleted distribusi") distribusiform.errors.append("Deleted distribusi")
def delete_distribusi_from_db(distribusi): def DeleteDistribusiFromDb(distribusi):
try: try:
db.session.delete(distribusi) db.session.delete(distribusi)
db.session.commit() db.session.commit()
@ -95,7 +105,7 @@ def delete_distribusi_from_db(distribusi):
db.session.rollback() db.session.rollback()
def delete_distribusi_files(distribusiname): def DeleteDistribusiFiles(distribusiname):
userfolder = os.path.join("stash", distribusiname) userfolder = os.path.join("stash", distribusiname)
if os.path.exists(userfolder): if os.path.exists(userfolder):
shutil.rmtree(userfolder) shutil.rmtree(userfolder)
@ -104,15 +114,15 @@ def delete_distribusi_files(distribusiname):
shutil.rmtree(cssfolder) shutil.rmtree(cssfolder)
def add_distribusis_to_form(admindistribusiform): def AddDistribusisToForm(admindistribusiform):
distribusis = DistribusisInfo.visible_distribusis() distribusis = DistribusisInfo.visibledistribusis()
admindistribusiform = AdminDistribusiForm.distribusi_list_form_builder( admindistribusiform = AdminDistribusiForm.distribusi_list_form_builder(
distribusis distribusis
) )
return admindistribusiform return admindistribusiform
def add_users_to_form(adminuserform): def AddUsersToForm(adminuserform):
users = User.query.all() users = User.query.all()
adminuserform = AdminUserForm.user_list_form_builder(users) adminuserform = AdminUserForm.user_list_form_builder(users)
return adminuserform return adminuserform

View File

@ -1,15 +1,13 @@
import sys import sys
from sqlalchemy.exc import (
DatabaseError,
DataError,
InterfaceError,
InvalidRequestError,
)
from app import create_app, db from app import create_app, db
from models.distribusi_model import Distribusis # noqa: F401 from sqlalchemy.exc import (
from models.user_model import User # noqa: F401 InvalidRequestError,
InterfaceError,
DataError,
DatabaseError,
)
from usermodel import User # noqa: F401
from distribusimodel import Distribusis # noqa: F401
def admintool(): def admintool():

View File

@ -1,15 +1,13 @@
import os import os
import tomllib
from flask import Flask 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_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect from flask_wtf.csrf import CSRFProtect
from flask_login import (
LoginManager,
)
APP = Flask(__name__, static_folder="static")
db = SQLAlchemy() db = SQLAlchemy()
migrate = Migrate() migrate = Migrate()
bcrypt = Bcrypt() bcrypt = Bcrypt()
@ -17,16 +15,18 @@ login_manager = LoginManager()
def create_app(): def create_app():
APP.secret_key = os.urandom(24) APP = Flask(__name__, static_folder="static")
APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///distribusiverse.db"
APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True 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_SERVER"] = "mail.autonomic.zone"
APP.config["MAIL_PORT"] = 587 APP.config["MAIL_PORT"] = 587
APP.config["MAIL_USE_SSL"] = False APP.config["MAIL_USE_SSL"] = False
APP.config["MAIL_USE_TLS"] = True APP.config["MAIL_USE_TLS"] = True
APP.config["MAIL_USERNAME"] = "noreply@vvvvvvaria.org" APP.config['MAIL_USERNAME'] = "noreply@vvvvvvaria.org"
login_manager.session_protection = "strong" login_manager.session_protection = "strong"
login_manager.login_view = "index" login_manager.login_view = "index"
@ -38,35 +38,10 @@ def create_app():
APP.config["UPLOAD_FOLDER"] = "tmpupload" APP.config["UPLOAD_FOLDER"] = "tmpupload"
APP.config["PUBLIC_THEMES"] = "themes/publicthemes" APP.config["PUBLIC_THEMES"] = "themes/publicthemes"
# user settings_file
settings()
csrf.init_app(APP) csrf.init_app(APP)
login_manager.init_app(APP) login_manager.init_app(APP)
db.init_app(APP) db.init_app(APP)
migrate.init_app(APP, db, render_as_batch=True) migrate.init_app(APP, db, render_as_batch=True)
bcrypt.init_app(APP) bcrypt.init_app(APP)
@APP.context_processor
def inject_title():
return dict(title=APP.config["title"])
return APP 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
View File

@ -0,0 +1,3 @@
*
*/
!.gitignore

View File

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

View File

@ -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

View File

@ -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', {})})

View File

@ -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!")

View File

@ -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%;
}

View File

@ -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 %}

View File

@ -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>

View File

@ -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)

View File

@ -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()

View File

@ -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")

View File

@ -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;
}

View File

@ -9,11 +9,14 @@ class Distribusis(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
distribusiname = db.Column(db.String(300), nullable=False, unique=True) distribusiname = db.Column(db.String(300), nullable=False, unique=True)
userid = db.Column(db.Integer, db.ForeignKey("users.id")) userid = db.Column(db.Integer, db.ForeignKey("users.id"))
category = db.Column(db.String(500), nullable=True, unique=False) 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) 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) tags = db.Column(db.String(500), nullable=True, unique=False)
publictheme = db.Column(db.String(300), unique=True, nullable=True) publictheme = db.Column(db.String(300), unique=True, nullable=True)
visible = db.Column(db.Boolean, default=False) visible = db.Column(db.Boolean, default=False)
def __repr__(self): def __repr__(self):

View File

@ -1,89 +1,77 @@
import os import os
import shutil import shutil
from flask import flash, render_template
from flask import flash, render_template, redirect, url_for
from flask_login import current_user from flask_login import current_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError,
DataError, DataError,
DatabaseError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from app import db from usermodel import User
from distribusikan.distribusis_info import DistribusisInfo from distribusimodel import Distribusis
from distribusikan.forms.distribusiform import DistribusiForm from distribusisinfo import DistribusisInfo
from distribusikan.forms.publicthemeform import PublicThemeForm
from distribusikan.forms.selectorform import SelectorForm from forms.selectorform import SelectorForm
from distribusikan.forms.themeform import ThemeForm from forms.uploadform import UploadForm
from distribusikan.forms.uploadform import UploadForm from forms.distribusiform import DistribusiForm
from models.distribusi_model import Distribusis from forms.themeform import ThemeForm
from models.user_model import User from forms.publicthemeform import PublicThemeForm
# UserPengguna # UserPengguna
from statuspengguna.helper import UserHelper from statuspengguna.helper import UserHelper
from app import db
def distribusi_selector():
def DistribusiSelector():
uploadform = UploadForm() uploadform = UploadForm()
selectorform = SelectorForm() selectorform = SelectorForm()
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames() selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if selectorform.validate_on_submit(): if selectorform.validate_on_submit():
if selectorform.new.data: if selectorform.new.data:
select_new_distribusi() SelectNewDistribusi()
if selectorform.describe.data:
return select_describe_distribusi(selectorform.distribusis.data)
if selectorform.delete.data: if selectorform.delete.data:
selectorform = delete_distribusi(selectorform.distribusis.data) selectorform = DeleteDistribusi(selectorform.distribusis.data)
selectorform.distribusis.choices = ( selectorform.distribusis.choices = (
DistribusisInfo.user_distribusinames() DistribusisInfo.userdistribusinames()
) )
if selectorform.update.data: if selectorform.update.data:
select_update_distribusi(selectorform.distribusis.data) SelectUpdateDistribusi(selectorform.distribusis.data)
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
uploadform = auto_fill_in_upload_form( uploadform = AutoFillInUploadForm(uploadform, current_distribusi)
uploadform, current_distribusi
)
return render_distribusi_template( return RenderDistribusiTemplate(
selectorform, uploadform, current_distribusi selectorform, uploadform, current_distribusi
) )
def auto_fill_in_upload_form(uploadform, current_distribusi): def AutoFillInUploadForm(uploadform, current_distribusi):
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
uploadform.sitename.data = distribusi.distribusiname uploadform.sitename.data = distribusi.distribusiname
uploadform.sitename.render_kw = {"readonly": True} uploadform.sitename.render_kw = {"readonly": True}
uploadform.description.data = distribusi.description uploadform.term.data = distribusi.term
uploadform.category.data = distribusi.category uploadform.course.data = distribusi.course
uploadform.year.data = distribusi.year uploadform.academicyear.data = distribusi.year
uploadform.tags.data = distribusi.tags uploadform.tags.data = distribusi.tags
return uploadform return uploadform
def select_new_distribusi(): def SelectNewDistribusi():
print("make a new distribusi") print("make a new distribusi")
select_current_distribusi("new") SelectCurrentDistribusi("new")
def select_describe_distribusi(distribusiname): def SelectUpdateDistribusi(distribusiname):
return redirect(
url_for(
"describer.show_distribusi_files",
distribusiname=distribusiname,
)
)
def select_update_distribusi(distribusiname):
print(f"Update this distribusi {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}") print(f"delete this distribusi {distribusiname}")
selectorform = SelectorForm() selectorform = SelectorForm()
try: try:
@ -117,7 +105,7 @@ def delete_distribusi(distribusiname):
return selectorform return selectorform
def select_current_distribusi(distribusiname): def SelectCurrentDistribusi(distribusiname):
if not current_user.is_authenticated: if not current_user.is_authenticated:
return return
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
@ -129,35 +117,35 @@ def select_current_distribusi(distribusiname):
flash("An error occured !", "danger") flash("An error occured !", "danger")
def distribusi_selected(): def DistribusiSelected():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
if user.currentdistribusi is None: if user.currentdistribusi is None:
return False return False
return True return True
def selector_visible(): def SelectorVisible():
has_distribusi = UserHelper.has_distribusi() has_distribusi = UserHelper.has_distribusi()
is_distribusi_selected = distribusi_selected() distribusi_selected = DistribusiSelected()
if is_distribusi_selected: if distribusi_selected:
return False return False
if not has_distribusi: if not has_distribusi:
return False return False
return True return True
def render_distribusi_template(selectorform, uploadform, current_distribusi): def RenderDistribusiTemplate(selectorform, uploadform, current_distribusi):
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
# because the user has chosen to update his distribusi, we assume # because the user has chosen to update his distribusi, we assume
# no selected css. # no selected css.
css_selected = False css_selected = False
selectorvisible = selector_visible() selectorvisible = SelectorVisible()
limit_reached = UserHelper.distribusi_limit_reached() limit_reached = UserHelper.distribusi_limit_reached()
template = render_template( template = render_template(
"distribusi.html", "distribusi.html",

View File

@ -1,18 +1,18 @@
from flask_login import current_user from flask_login import current_user
from models.distribusi_model import Distribusis from usermodel import User
from models.user_model import User from distribusimodel import Distribusis
class DistribusisInfo: class DistribusisInfo:
def user_distribusinames(): def userdistribusinames():
distribusinames = [] distribusinames = []
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
for distribusi in Distribusis.query.filter_by(userid=user.id).all(): for distribusi in Distribusis.query.filter_by(userid=user.id).all():
distribusinames.append(distribusi.distribusiname) distribusinames.append(distribusi.distribusiname)
return distribusinames return distribusinames
def public_themes(): def publicthemes():
publicthemes = [] publicthemes = []
distribusis = Distribusis.query.filter( distribusis = Distribusis.query.filter(
Distribusis.publictheme.isnot(None) Distribusis.publictheme.isnot(None)
@ -27,12 +27,12 @@ made by {user.username}""",
publicthemes.append(publictheme) publicthemes.append(publictheme)
return publicthemes return publicthemes
def visible_distribusis(): def visibledistribusis():
distribusis = Distribusis.query.filter( distribusis = Distribusis.query.filter(
Distribusis.visible.isnot(False) Distribusis.visible.isnot(False)
).all() ).all()
return distribusis return distribusis
def get_user_distribusis(useremail): def getuserdistribusis(useremail):
user = User.query.filter_by(email=useremail).first() user = User.query.filter_by(email=useremail).first()
return Distribusis.query.filter_by(userid=user.id).all() return Distribusis.query.filter_by(userid=user.id).all()

View File

@ -1,38 +1,43 @@
import os import os
import shutil import shutil
import zipfile 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! # Tada!
from distribusi.cli import build_argparser from distribusi.cli import build_argparser
from distribusi.distribusi import distribusify 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() distribusiform = DistribusiForm()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
@ -42,19 +47,18 @@ def distribusi_workflow():
if distribusiform.validate_on_submit(): if distribusiform.validate_on_submit():
userfolder = os.path.join("stash", distribusi.distribusiname) userfolder = os.path.join("stash", distribusi.distribusiname)
cssfile = get_css_file(distribusi) cssfile = GetCssFile(distribusi)
unzip_distribusi_files(distribusi, userfolder) UnzipDistribusiFiles(distribusi, userfolder)
clean_up_distribusi_files(userfolder) CleanUpDistribusiFiles(userfolder)
add_distribusi_files_to_db(distribusi.distribusiname) RunDistribusi(userfolder, cssfile)
run_distribusi(userfolder, cssfile) SetDistribusiToVisible(distribusi, user)
set_distribusi_to_visible(distribusi, user) DeleteCssFile(cssfile)
delete_css_file(cssfile)
return redirect(url_for("index")) 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) zipfilename = "{}.zip".format(distribusi.distribusiname)
unzipfile = os.path.join(userfolder, zipfilename) unzipfile = os.path.join(userfolder, zipfilename)
@ -66,15 +70,15 @@ def unzip_distribusi_files(distribusi, userfolder):
os.remove(os.path.join(userfolder, zipfilename)) os.remove(os.path.join(userfolder, zipfilename))
def clean_up_distribusi_files(userfolder): def CleanUpDistribusiFiles(userfolder):
if os.path.exists(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): for filename in os.listdir(path):
fullpath = os.path.join(path, filename) fullpath = os.path.join(path, filename)
if filename.startswith("."): if filename.startswith('.'):
if os.path.isdir(fullpath): if os.path.isdir(fullpath):
shutil.rmtree(fullpath) shutil.rmtree(fullpath)
else: else:
@ -82,10 +86,10 @@ def remove_mac_folders(path):
if filename == "__MACOSX": if filename == "__MACOSX":
shutil.rmtree(fullpath) shutil.rmtree(fullpath)
if os.path.isdir(fullpath): if os.path.isdir(fullpath):
remove_mac_folders(fullpath) RemoveMacFolders(fullpath)
def get_css_file(distribusi): def GetCssFile(distribusi):
cssfile = "" cssfile = ""
cssfolder = os.path.join("themes/userthemes", distribusi.distribusiname) cssfolder = os.path.join("themes/userthemes", distribusi.distribusiname)
if os.path.exists(cssfolder): if os.path.exists(cssfolder):
@ -95,14 +99,13 @@ def get_css_file(distribusi):
return cssfile return cssfile
def run_distribusi(userfolder, cssfile): def RunDistribusi(userfolder, cssfile):
print(f"Run distribusi on this folder: {userfolder} with css:{cssfile}")
parser = build_argparser() 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) distribusify(args, userfolder)
def set_distribusi_to_visible(distribusi, user): def SetDistribusiToVisible(distribusi, user):
try: try:
distribusi.visible = True distribusi.visible = True
user.currentdistribusi = None user.currentdistribusi = None
@ -112,19 +115,19 @@ def set_distribusi_to_visible(distribusi, user):
flash("Unknown error occured!") flash("Unknown error occured!")
def delete_css_file(cssfile): def DeleteCssFile(cssfile):
if os.path.exists(cssfile): if os.path.exists(cssfile):
os.remove(cssfile) os.remove(cssfile)
def render_distribusi_template(distribusiform, current_distribusi): def RenderDistribusiTemplate(distribusiform, current_distribusi):
uploadform = UploadForm() uploadform = UploadForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
selectorform = SelectorForm() selectorform = SelectorForm()
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames() selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
selectorvisible = selector_visible() selectorvisible = SelectorVisible()
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)

View File

@ -1,40 +1,41 @@
import os import os
import shutil
import bleach import bleach
from bleach_allowlist import all_styles from bleach_allowlist import all_styles
import shutil
from flask import render_template from flask import render_template
from werkzeug.utils import secure_filename
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError,
DataError, DataError,
DatabaseError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from werkzeug.utils import secure_filename
from app import db from app import db
from distribusikan.distribusis_info import DistribusisInfo from distribusimodel import Distribusis
from distribusikan.forms.distribusiform import DistribusiForm
from distribusikan.forms.editorform import EditorForm
from distribusikan.forms.publicthemeform import PublicThemeForm
from distribusikan.forms.selectorform import SelectorForm
from distribusikan.forms.themeform import ThemeForm
from distribusikan.forms.uploadform import UploadForm
from models.distribusi_model import Distribusis
from statuspengguna.helper import UserHelper 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() editorform = EditorForm()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if editorform.validate_on_submit(): if editorform.validate_on_submit():
validate_edit_css_form(editorform, current_distribusi) ValidateEditCssForm(editorform, current_distribusi)
return render_distribusi_template(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) newcssfolder = os.path.join("themes/userthemes", current_distribusi)
if os.path.exists(newcssfolder): if os.path.exists(newcssfolder):
shutil.rmtree(newcssfolder) shutil.rmtree(newcssfolder)
@ -44,22 +45,22 @@ def validate_edit_css_form(editorform, current_distribusi):
shutil.rmtree(publicfolder) shutil.rmtree(publicfolder)
if editorform.public.data: if editorform.public.data:
make_public_theme(editorform, current_distribusi) MakePublicTheme(editorform, current_distribusi)
if editorform.cssfile.data: if editorform.cssfile.data:
save_upload_css_file(editorform, publicfolder) SaveUploadCssFile(editorform, publicfolder)
copy_public_to_user_folder(editorform, publicfolder, newcssfolder) CopyPublicToUserFolder(editorform, publicfolder, newcssfolder)
return return
else: else:
write_css_to_file(editorform, publicfolder) WriteCssToFile(editorform, publicfolder)
if editorform.cssfile.data: if editorform.cssfile.data:
save_upload_css_file(editorform, newcssfolder) SaveUploadCssFile(editorform, newcssfolder)
return return
if editorform.cssname.data: 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): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
cssfile = editorform.cssfile.data cssfile = editorform.cssfile.data
@ -67,37 +68,38 @@ def save_upload_css_file(editorform, newcssfolder):
cssfile.save(os.path.join(newcssfolder, cssfilename)) cssfile.save(os.path.join(newcssfolder, cssfilename))
openfile = open(os.path.join(newcssfolder, cssfilename), "r") openfile = open(os.path.join(newcssfolder, cssfilename), "r")
cleancss = bleach.clean(openfile.read(), all_styles) cleancss = bleach.clean(openfile.read(), all_styles)
cleancss = cleancss.replace("&gt;", ">") cleancss = cleancss.replace('&gt;', '>')
openfile.close() openfile.close()
cleanfile = open(os.path.join(newcssfolder, cssfilename), "w") cleanfile = open(os.path.join(newcssfolder, cssfilename), "w")
cleanfile.write(cleancss) cleanfile.write(cleancss)
cleanfile.close() cleanfile.close()
def write_css_to_file(editorform, newcssfolder): def WriteCssToFile(editorform, newcssfolder):
if not os.path.exists(newcssfolder): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
cssfilename = f"{secure_filename(editorform.cssname.data)}.css" cssfilename = f"{secure_filename(editorform.cssname.data)}.css"
cleancss = bleach.clean(editorform.css.data, all_styles) cleancss = bleach.clean(editorform.css.data, all_styles)
cleancss = cleancss.replace("&gt;", ">") cleancss = cleancss.replace('&gt;', '>')
with open(os.path.join(newcssfolder, cssfilename), "w") as cssfile: with open(os.path.join(newcssfolder, cssfilename), "w") as cssfile:
cssfile.write(cleancss) cssfile.write(cleancss)
cssfile.close cssfile.close
def copy_public_to_user_folder(editorform, publicfolder, newcssfolder): def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder):
if not os.path.exists(newcssfolder): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
copycssfile = os.path.join( copycssfile = os.path.join(
publicfolder, f"{secure_filename(editorform.cssname.data)}.css" publicfolder,
f"{secure_filename(editorform.cssname.data)}.css"
) )
print(f"copying file: {copycssfile}") print(f"copying file: {copycssfile}")
print(f"to folder: {newcssfolder}") print(f"to folder: {newcssfolder}")
shutil.copy(copycssfile, newcssfolder) shutil.copy(copycssfile, newcssfolder)
def make_public_theme(editorform, current_distribusi): def MakePublicTheme(editorform, current_distribusi):
try: try:
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
@ -119,12 +121,12 @@ def make_public_theme(editorform, current_distribusi):
editorform.public.errors.append("Error connecting to the database") editorform.public.errors.append("Error connecting to the database")
def render_distribusi_template(current_distribusi): def RenderDistribusiTemplate(current_distribusi):
uploadform = UploadForm() uploadform = UploadForm()
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
selectorform = SelectorForm() selectorform = SelectorForm()
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
@ -148,11 +150,11 @@ def render_distribusi_template(current_distribusi):
return template return template
def render_editor_template(editorform, current_distribusi): def RenderEditorTemplate(editorform, current_distribusi):
html_placeholder = get_html_placeholder() htmlplaceholder = HtmlPlaceholder()
css_placeholder = get_css_placeholder(current_distribusi) cssplaceholder = CssPlaceholder(current_distribusi)
editorform.css.data = css_placeholder editorform.css.data = cssplaceholder
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi) files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
@ -161,33 +163,33 @@ def render_editor_template(editorform, current_distribusi):
files_uploaded=files_uploaded, files_uploaded=files_uploaded,
distribusi_live=distribusi_live, distribusi_live=distribusi_live,
editorform=editorform, editorform=editorform,
html_placeholder=html_placeholder, htmlplaceholder=htmlplaceholder,
) )
return template return template
def get_css_placeholder(current_distribusi): def CssPlaceholder(current_distribusi):
css_placeholder = "Try out your CSS here" cssplaceholder = "Try out your CSS here"
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
if distribusi is not None and distribusi.publictheme is not None: if distribusi is not None and distribusi.publictheme is not None:
css_placeholder = get_public_css_file(distribusi) cssplaceholder = GetPublicCssFile(distribusi)
else: else:
with open("themes/editor/placeholder.css") as f: with open("themes/editor/placeholder.css") as f:
css_placeholder = f.read() cssplaceholder = f.read()
return css_placeholder return cssplaceholder
def get_html_placeholder(): def HtmlPlaceholder():
html_placeholder = "Write some test HTML here" htmlplaceholder = "Write some test HTML here"
with open("themes/editor/placeholder.html") as f: with open("themes/editor/placeholder.html") as f:
html_placeholder = f.read() htmlplaceholder = f.read()
return html_placeholder return htmlplaceholder
def get_public_css_file(distribusi): def GetPublicCssFile(distribusi):
css_placeholder = "" cssplaceholder = ""
publicthemefolder = os.path.join( publicthemefolder = os.path.join(
"themes/publicthemes", distribusi.distribusiname "themes/publicthemes", distribusi.distribusiname
) )
@ -195,5 +197,5 @@ def get_public_css_file(distribusi):
if filename.endswith(".css"): if filename.endswith(".css"):
cssfile = os.path.join(publicthemefolder, filename) cssfile = os.path.join(publicthemefolder, filename)
with open(cssfile) as f: with open(cssfile) as f:
css_placeholder = f.read() cssplaceholder = f.read()
return css_placeholder return cssplaceholder

View File

@ -1,7 +1,9 @@
"""Form object declaration.""" """Form object declaration."""
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import BooleanField, SubmitField from wtforms import (
BooleanField,
SubmitField,
)
class AdminDistribusiForm(FlaskForm): class AdminDistribusiForm(FlaskForm):
@ -13,7 +15,7 @@ class AdminDistribusiForm(FlaskForm):
class DistribusiListForm(AdminDistribusiForm): class DistribusiListForm(AdminDistribusiForm):
pass pass
for i, distribusi in enumerate(distribusis): for (i, distribusi) in enumerate(distribusis):
setattr( setattr(
DistribusiListForm, DistribusiListForm,
f"distribusi_{i}", f"distribusi_{i}",

View File

@ -1,7 +1,9 @@
"""Form object declaration.""" """Form object declaration."""
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import BooleanField, SubmitField from wtforms import (
SubmitField,
BooleanField,
)
class AdminUserForm(FlaskForm): class AdminUserForm(FlaskForm):
@ -11,7 +13,7 @@ class AdminUserForm(FlaskForm):
class UserListForm(AdminUserForm): class UserListForm(AdminUserForm):
pass pass
for i, user in enumerate(users): for (i, user) in enumerate(users):
setattr( setattr(
UserListForm, UserListForm,
f"user_{i}", f"user_{i}",
@ -20,4 +22,8 @@ class AdminUserForm(FlaskForm):
return UserListForm() return UserListForm()
tutors = SubmitField("Are tutors")
nottutors = SubmitField("Are not tutors")
delete = SubmitField("Delete") delete = SubmitField("Delete")

View File

@ -1,15 +1,15 @@
"""Form to save your CSS editor work.""" """Form to save your CSS editor work."""
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed, FileField, FileSize
from wtforms import ( from wtforms import (
BooleanField,
StringField, StringField,
SubmitField,
TextAreaField, TextAreaField,
validators, BooleanField,
SubmitField,
) )
from wtforms import validators
from wtforms.validators import Length from wtforms.validators import Length
from flask_wtf.file import FileField, FileAllowed, FileSize
from flask_wtf import FlaskForm
class EditorForm(FlaskForm): class EditorForm(FlaskForm):

View File

@ -1,8 +1,12 @@
"""Forgotten password form to help user.""" """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 flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, validators
from wtforms.validators import Email, Length
class ForgotPasswordForm(FlaskForm): class ForgotPasswordForm(FlaskForm):

View File

@ -1,8 +1,13 @@
"""Login form to validate user.""" """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 flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField, validators
from wtforms.validators import Email, Length
class LoginForm(FlaskForm): class LoginForm(FlaskForm):

View File

@ -1,7 +1,9 @@
"""Form object declaration.""" """Form object declaration."""
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import RadioField, SubmitField from wtforms import (
RadioField,
SubmitField,
)
class PublicThemeForm(FlaskForm): class PublicThemeForm(FlaskForm):

View File

@ -1,13 +1,22 @@
"""Register form to make a new user.""" """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 flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField, validators
from wtforms.validators import Email, EqualTo, Length
class RegisterForm(FlaskForm): class RegisterForm(FlaskForm):
"""Register for distribusi-verse form class""" """Register for distribusi-verse form class"""
def hremail(form, field):
if not field.data.endswith("@hr.nl"):
raise ValidationError("Only HRO accounts are allowed.")
username = StringField( username = StringField(
"Username:", "Username:",
validators=[validators.InputRequired(), Length(3, 150)], validators=[validators.InputRequired(), Length(3, 150)],
@ -18,8 +27,9 @@ class RegisterForm(FlaskForm):
validators=[ validators=[
validators.InputRequired(), validators.InputRequired(),
Email(), Email(),
Length(6, 128), Length(6, 64),
], hremail,
]
) )
password = PasswordField( password = PasswordField(

View File

@ -1,8 +1,12 @@
"""Reset Password Form form to reset a users PasswordField.""" """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 flask_wtf import FlaskForm
from wtforms import PasswordField, SubmitField, validators
from wtforms.validators import EqualTo, Length
class ResetPasswordForm(FlaskForm): class ResetPasswordForm(FlaskForm):

View File

@ -1,5 +1,5 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import SelectField, SubmitField from wtforms import SubmitField, SelectField
class SelectorForm(FlaskForm): class SelectorForm(FlaskForm):
@ -9,6 +9,4 @@ class SelectorForm(FlaskForm):
update = SubmitField("update") update = SubmitField("update")
describe = SubmitField("describe")
delete = SubmitField("delete") delete = SubmitField("delete")

View File

@ -1,7 +1,9 @@
"""Form object declaration.""" """Form object declaration."""
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import RadioField, SubmitField from wtforms import (
RadioField,
SubmitField,
)
class ThemeForm(FlaskForm): class ThemeForm(FlaskForm):

88
verse/forms/uploadform.py Normal file
View 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")

View File

@ -14,19 +14,17 @@ config = context.config
# Interpret the config file for Python logging. # Interpret the config file for Python logging.
# This line sets up loggers basically. # This line sets up loggers basically.
fileConfig(config.config_file_name) fileConfig(config.config_file_name)
logger = logging.getLogger("alembic.env") logger = logging.getLogger('alembic.env')
# add your model's MetaData object here # add your model's MetaData object here
# for 'autogenerate' support # for 'autogenerate' support
# from myapp import mymodel # from myapp import mymodel
# target_metadata = mymodel.Base.metadata # target_metadata = mymodel.Base.metadata
config.set_main_option( config.set_main_option(
"sqlalchemy.url", 'sqlalchemy.url',
str(current_app.extensions["migrate"].db.get_engine().url).replace( str(current_app.extensions['migrate'].db.get_engine().url).replace(
"%", "%%" '%', '%%'))
), target_metadata = current_app.extensions['migrate'].db.metadata
)
target_metadata = current_app.extensions["migrate"].db.metadata
# other values from the config, defined by the needs of env.py, # other values from the config, defined by the needs of env.py,
# can be acquired: # can be acquired:
@ -67,20 +65,20 @@ def run_migrations_online():
# when there are no changes to the schema # when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives): def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, "autogenerate", False): if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0] script = directives[0]
if script.upgrade_ops.is_empty(): if script.upgrade_ops.is_empty():
directives[:] = [] directives[:] = []
logger.info("No changes in schema detected.") logger.info('No changes in schema detected.')
connectable = current_app.extensions["migrate"].db.get_engine() connectable = current_app.extensions['migrate'].db.get_engine()
with connectable.connect() as connection: with connectable.connect() as connection:
context.configure( context.configure(
connection=connection, connection=connection,
target_metadata=target_metadata, target_metadata=target_metadata,
process_revision_directives=process_revision_directives, process_revision_directives=process_revision_directives,
**current_app.extensions["migrate"].configure_args, **current_app.extensions['migrate'].configure_args
) )
with context.begin_transaction(): with context.begin_transaction():

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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 %}

View File

@ -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

View File

@ -1,45 +1,50 @@
"""This is the main flask distribusi page""" """This is the main flask distribusi page"""
from datetime import timedelta from datetime import timedelta
from flask import ( from flask import (
Blueprint,
redirect,
render_template, render_template,
send_from_directory, redirect,
session,
url_for, 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 flask_wtf.csrf import CSRFError
from app import create_app, login_manager
from admin import is_adminuser from usermodel import User
from admin_page.admin_page import admin_page from distribusimodel import Distribusis
from app import create_app, login_manager, db
from describer.describe_files import describer # Use upload form to populate filters
from distribusikan.distribusikan import distribusikan from forms.uploadform import UploadForm
from distribusikan.distribusis_info import DistribusisInfo
from distribusikan.forms.uploadform import UploadForm # Interface! these are seperate files in main folder
from models.distribusi_model import Distribusis from adminpage import AdminPage
from models.user_model import User from editor import Editor
from statuspengguna.forgotpassword import forgot_password from themeselector import ThemeSelector
from distribusiworkflow import DistribusiWorkflow
from distribusiselector import DistribusiSelector
from uploadpage import UploadPage
# UserPengguna
from statuspengguna.helper import UserHelper from statuspengguna.helper import UserHelper
from statuspengguna.loginuser import login_section from statuspengguna.loginuser import LoginUser
from statuspengguna.registeruser import register_user from statuspengguna.registeruser import RegisterUser
from search.search import searchpages from statuspengguna.forgotpassword import ForgotPassword
from search.search_index import init_search_index from statuspengguna.resetpassword import ResetPassword
# Distribusi Information
from distribusisinfo import DistribusisInfo
APP = create_app() APP = create_app()
stash_page = Blueprint("stash_page", __name__, static_folder="stash") stash_page = Blueprint("stash_page", __name__, static_folder="stash")
APP.register_blueprint(stash_page) APP.register_blueprint(stash_page)
APP.register_blueprint(describer, url_prefix="/describer") mail = Mail(APP)
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)
@APP.before_request @APP.before_request
@ -51,28 +56,32 @@ def session_handler():
@APP.route("/") @APP.route("/")
def index(): def index():
UserHelper.reset_user_state() UserHelper.reset_user_state()
# http://localhost:5000/themes/publicthemes/RomeroTape/blueskies.css
uploadform = UploadForm() uploadform = UploadForm()
distribusis = DistribusisInfo.visible_distribusis() distribusis = DistribusisInfo.visibledistribusis()
distribusisindex = {} distribusisindex = {}
for distribusi in distribusis: for distribusi in distribusis:
user = User.query.filter_by(id=distribusi.userid).first() user = User.query.filter_by(id=distribusi.userid).first()
singledistribusi = { singledistribusi = {
"username": user.username, "username": user.username,
"publictheme": distribusi.publictheme, "publictheme": distribusi.publictheme,
"category": distribusi.category, "term": distribusi.term,
"course": distribusi.course,
"year": distribusi.year, "year": distribusi.year,
"tags": distribusi.tags.split(","), "tags": distribusi.tags.split(","),
} }
distribusisindex[distribusi.distribusiname] = singledistribusi distribusisindex[distribusi.distribusiname] = singledistribusi
years = uploadform.academicyear.choices
terms = uploadform.term.choices
courses = uploadform.course.choices
years = uploadform.year.choices adminuser = isadminuser()
categories = uploadform.category.choices
adminuser = is_adminuser()
template = render_template( template = render_template(
"base/index.html", "index.html",
distribusisindex=distribusisindex, distribusisindex=distribusisindex,
years=years, years=years,
categories=categories, terms=terms,
courses=courses,
adminuser=adminuser, adminuser=adminuser,
) )
return template return template
@ -80,7 +89,26 @@ def index():
@APP.route("/help") @APP.route("/help")
def 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>") @APP.route("/publicthemes/<path>")
@ -88,14 +116,35 @@ def publicthemes(path):
distribusi = Distribusis.query.filter_by(distribusiname=path).first() distribusi = Distribusis.query.filter_by(distribusiname=path).first()
publicthemefolder = f"publicthemes/{distribusi.distribusiname}/" publicthemefolder = f"publicthemes/{distribusi.distribusiname}/"
cssfile = f"{publicthemefolder}/{distribusi.publictheme}.css" cssfile = f"{publicthemefolder}/{distribusi.publictheme}.css"
print(cssfile)
return send_from_directory("themes", cssfile, as_attachment=True) 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") @APP.route("/stash")
def shortstashurl(): def shortstashurl():
return redirect(url_for("index")) 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") @APP.route("/logout")
@login_required @login_required
def logout(): def logout():
@ -103,6 +152,26 @@ def logout():
return redirect(url_for("index")) 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) @APP.errorhandler(CSRFError)
def handle_csrf_error(e): def handle_csrf_error(e):
return render_template("csrf_error.html", reason=e.description), 400 return render_template("csrf_error.html", reason=e.description), 400
@ -110,7 +179,14 @@ def handle_csrf_error(e):
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): 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__": if __name__ == "__main__":

View File

@ -1,8 +1,8 @@
/* Dropdown Button */ /* Dropdown Button */
/* for sorting on year and category /* for sorting on Academicyear, Term, Course
*/ */
button { button {
background-color: #9de457; background-color: #E0B0FF;
text-decoration: none; text-decoration: none;
border: none; border: none;
} }
@ -26,7 +26,7 @@ button {
.dropdown-content { .dropdown-content {
display: none; display: none;
position: absolute; position: absolute;
background-color: #9de457; background-color: #E0B0FF;
min-width: 120px; min-width: 120px;
border: 2px solid; border: 2px solid;
z-index: 1; z-index: 1;

View File

@ -5,7 +5,7 @@
} }
.editarea { .editarea {
width: 30%; width: 30%;
border: 3px solid #9de457; border: 3px solid #E0B0FF;
border-style: outset; border-style: outset;
margin-right: 1em; margin-right: 1em;
margin-left: 0; margin-left: 0;
@ -31,7 +31,7 @@ textarea {
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
min-height: 250px; min-height: 250px;
background: #9de457; background: #E0B0FF;
outline: none; outline: none;
font-family: Courier, sans-serif; font-family: Courier, sans-serif;
font-size: 16px; font-size: 16px;
@ -45,6 +45,6 @@ iframe {
height: 30em; height: 30em;
} }
#html { #html {
background-color: #9de457; background-color: #60337F;
color: black; color: lightgrey;
} }

View File

@ -4,7 +4,7 @@
max-width: 20em; max-width: 20em;
position: relative; position: relative;
border: none; border: none;
background: #9de457; background: #E0B0FF;
text-decoration: none; text-decoration: none;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -18,7 +18,7 @@
max-width: 20em; max-width: 20em;
border: none; border: none;
box-shadow: none; box-shadow: none;
background-color: #9de457; background-color: #E0B0FF;
background-image: none; background-image: none;
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
@ -41,7 +41,7 @@
} }
select.selector option{ select.selector option{
color: white; color: white;
background-color: #9de457; background-color: #60337F;
padding: 0 10px; padding: 0 10px;
} }
@ -49,5 +49,5 @@ select.selector option{
outline: none; outline: none;
} }
.selector-style select option:hover { .selector-style select option:hover {
background: #9de457; background: #60337F;
} }

View File

@ -2,17 +2,64 @@ body
{ {
font-family: monospace, monospace; font-family: monospace, monospace;
font-size: 15px; font-size: 15px;
background-color: #fdfdfd; background-color: #272a33;
color:#091411; color:#E0B0FF;
word-wrap: break-word; word-wrap: break-word;
line-height: 1.1; 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 #mainworkflow
{ {
width: 40em; width: 30em;
margin:0 auto; margin:0 auto;
} }
@ -22,16 +69,7 @@ body
#distribusi-index { #distribusi-index {
padding-left: 1em; padding-left: 1em;
} }
.description > textarea {
width: 100%;
height: 10em;
resize: none;
}
textarea#description {
width: 100%;
height: 20em;
resize: none;
}
div#buttons{ div#buttons{
position: fixed; position: fixed;
top: 0.5em; top: 0.5em;
@ -44,13 +82,13 @@ div#buttons{
div#buttons .distribusi input{ div#buttons .distribusi input{
border: none; border: none;
background: #9de457; background: #fff600;
text-decoration: none; text-decoration: none;
margin: 0.2em; margin: 0.2em;
} }
div#buttons .distribusi input:hover{ div#buttons .distribusi input:hover{
background: #091411; background: #ffbf00;
color: #6df2cc;
} }
fieldset.required { fieldset.required {
border: none; border: none;
@ -63,15 +101,21 @@ fieldset.required > ul {
fieldset.required > ul > li{ fieldset.required > ul > li{
list-style-type: none; list-style-type: none;
} }
fieldset.tagfield > input { fieldset.tagfield > input {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
} }
#publicthemes > ul {
max-height: 20em;
overflow: auto;
}
#publicthemes > ul > li{
word-break: break-all;
}
input { input {
border: none; border: none;
background: #9de457; background: #E0B0FF;
text-decoration: none; text-decoration: none;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -80,9 +124,7 @@ input {
} }
input:hover { input:hover {
background: #091411; background: #60337F;
color: #6df2cc;
cursor: pointer;
} }
input[type="submit"]:disabled:hover, input[type="submit"]:disabled:hover,
@ -102,11 +144,37 @@ input[type="submit"]:disabled:focus {
background-color: #F92020; background-color: #F92020;
} }
#update, #describe { #update {
color: black; color: black;
background-color: #62b264; 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 */ /* STOLEN GOODS */
#fancyboi::before { #fancyboi::before {
content: "$ "; content: "$ ";
@ -127,7 +195,7 @@ input[type="submit"]:disabled:focus {
white-space: nowrap; white-space: nowrap;
animation: reveal 4s linear; animation: reveal 4s linear;
text-overflow: "█"; text-overflow: "█";
background-color: #9de457; background-color: #2D3039;
} }
#fancyboi::after { #fancyboi::after {
content: "█"; content: "█";
@ -137,7 +205,7 @@ input[type="submit"]:disabled:focus {
div.maincontent{ div.maincontent{
width: 55%; width: 55%;
border: 3px #9de457; border: 3px #E0B0FF;
margin-top: 0.5em; margin-top: 0.5em;
padding: 0.5em; padding: 0.5em;
border-style: outset; border-style: outset;
@ -176,6 +244,8 @@ div.maincontent{
bottom: 100%; bottom: 100%;
left: 50%; left: 50%;
margin-left: -60px; margin-left: -60px;
/* Fade in tooltip - takes 1 second to go from 0% to 100% opac: */
opacity: 0; opacity: 0;
transition: opacity 2s; transition: opacity 2s;
} }
@ -190,7 +260,7 @@ div.maincontent{
color: black; color: black;
padding: 1em; padding: 1em;
box-sizing: border-box; box-sizing: border-box;
background: #9de457; background: #E0B0FF;
outline: none; outline: none;
font-family: Courier, sans-serif; font-family: Courier, sans-serif;
font-size: 16px; font-size: 16px;
@ -198,11 +268,11 @@ div.maincontent{
/* /*
Project colors so far. Project colors so far.
light light
#9de457 #E0B0FF
medium medium
#d28cff #d28cff
dark dark
#9de457 #60337F
background dark background dark
#2D3039 #2D3039

View File

@ -24,8 +24,9 @@ function filterSelection(c, name, id) {
} }
function resetDropDownButtons(){ function resetDropDownButtons(){
document.getElementById("Year").innerText = "Year"; document.getElementById("Academicyear").innerText = "Academic year";
document.getElementById("Category").innerText = "Category"; document.getElementById("Term").innerText = "Term";
document.getElementById("Course").innerText = "Course";
allactivebuttons = document.getElementsByClassName("activebtn"); allactivebuttons = document.getElementsByClassName("activebtn");
for(var i = 0;allactivebuttons.length; i++) { for(var i = 0;allactivebuttons.length; i++) {
removeClass(allactivebuttons[i], "activebtn"); removeClass(allactivebuttons[i], "activebtn");

View File

@ -1,31 +1,17 @@
from datetime import datetime
from uuid import uuid1 from uuid import uuid1
from datetime import datetime
from flask import Blueprint, render_template
from flask_mail import Mail, Message
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError,
DataError, DataError,
DatabaseError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from flask import render_template
from flask_mail import Message
from app import db, get_app from usermodel import User
from statuspengguna.forms.forgotpasswordform import ForgotPasswordForm from forms.forgotpasswordform import ForgotPasswordForm
from models.user_model import User from app import db
mail = Mail(get_app())
forgot_password = Blueprint(
"forgotpassword",
__name__,
template_folder="templates/statuspengguna",
static_folder="static",
)
@forgot_password.route("/", methods=["GET", "POST"])
def forgotpassword():
return ForgotPassword(mail)
def ForgotPassword(mail): def ForgotPassword(mail):

View File

@ -1,18 +1,17 @@
import os import os
from flask import flash
from flask_login import current_user from flask_login import current_user
from flask import flash
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError,
DataError, DataError,
DatabaseError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from usermodel import User
from distribusimodel import Distribusis
from distribusisinfo import DistribusisInfo
from app import db from app import db
from distribusikan.distribusis_info import DistribusisInfo
from models.distribusi_model import Distribusis
from models.user_model import User
class UserHelper: class UserHelper:
@ -76,10 +75,11 @@ class UserHelper:
def distribusi_limit_reached(): def distribusi_limit_reached():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
distribusiamount = len( distribusiamount = len(DistribusisInfo.getuserdistribusis(user.email))
DistribusisInfo.get_user_distribusis(user.email) if user.tutor and distribusiamount > 14:
) print("tutor already has 15 distribusis")
if distribusiamount > 19: return True
print("user already has 20 distribusis") if not user.tutor and distribusiamount > 4:
print("user already has 5 distribusis")
return True return True
return False return False

View File

@ -1,29 +1,15 @@
from flask import ( from flask import (
Blueprint,
abort,
flash,
redirect,
render_template, render_template,
redirect,
request, request,
flash,
url_for, 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 flask_login import login_user
from flask_bcrypt import check_password_hash
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()
def LoginUser(): def LoginUser():
@ -39,9 +25,7 @@ def LoginUser():
flash("Logged in successfully.", "success") flash("Logged in successfully.", "success")
next = request.args.get("next") next = request.args.get("next")
if next is not None and not is_safe_url(next): # noqa: F821 if next is not None and not is_safe_url(next): # noqa: F821
print(next)
return abort(400) return abort(400)
print("index")
return redirect(next or url_for("index")) return redirect(next or url_for("index"))
else: else:
flash("Invalid email or password!", "danger") flash("Invalid email or password!", "danger")

View File

@ -1,30 +1,22 @@
from flask import Blueprint, flash, redirect, render_template, url_for from flask import (
from flask_bcrypt import generate_password_hash render_template,
from flask_login import login_user redirect,
flash,
url_for,
)
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError,
DataError,
IntegrityError, IntegrityError,
DataError,
DatabaseError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from werkzeug.routing import BuildError 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 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(): def RegisterUser():

View File

@ -1,32 +1,23 @@
from datetime import datetime from datetime import datetime
from flask import (
from flask import Blueprint, flash, redirect, render_template, url_for render_template,
from flask_bcrypt import generate_password_hash redirect,
from flask_login import login_user flash,
url_for,
)
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError,
DataError,
IntegrityError, IntegrityError,
DataError,
DatabaseError,
InterfaceError, InterfaceError,
InvalidRequestError, InvalidRequestError,
) )
from werkzeug.routing import BuildError 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 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): def ResetPassword(path):

View File

@ -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;
}

View File

@ -1,4 +1,4 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="buttons"> <div id="buttons">
<div class="overview"> <div class="overview">
@ -14,6 +14,9 @@
</div> </div>
<div class="maincontent"> <div class="maincontent">
<h2>Admin Page</h2> <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"> <div id="distribusiverse" class="maincontent">
<h2>List of distribusis</h2> <h2>List of distribusis</h2>
<form method="POST" enctype="multipart/form-data" action="{{ url_for('admin') }}"> <form method="POST" enctype="multipart/form-data" action="{{ url_for('admin') }}">
@ -50,6 +53,12 @@
</fieldset> </fieldset>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<fieldset class="button required">
{{ adminuserform.tutors }}
</fieldset>
<fieldset class="button required">
{{ adminuserform.nottutors }}
</fieldset>
<fieldset class="button required"> <fieldset class="button required">
{{ adminuserform.delete }} {{ adminuserform.delete }}
</fieldset> </fieldset>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <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/style.css')}}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/selector.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') }}"> <link rel="shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">

View File

@ -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 %}

View File

@ -1,4 +1,4 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="buttons"> <div id="buttons">
<div class="overview"> <div class="overview">
@ -20,28 +20,27 @@
<div id="mainworkflow"> <div id="mainworkflow">
{% if selectorvisible %} {% if selectorvisible %}
{% block selector %} {% block selector %}
{% include "distribusi_workflow/selector.html" %} {% include "distribusiworkflow/selector.html" %}
{% endblock selector%} {% endblock selector%}
{% else %} {% else %}
{% block upload %} {% block upload %}
{% include "distribusi_workflow/upload.html" %} {% include "distribusiworkflow/upload.html" %}
{% endblock upload%} {% endblock upload%}
<img src="{{ url_for('static', filename='svg/arrow_1.svg')}}" /> <img src="{{ url_for('static', filename='svg/arrow_1.svg')}}" />
{% block theme %} {% block theme %}
{% include "distribusi_workflow/theme.html" %} {% include "distribusiworkflow/theme.html" %}
{% endblock theme%} {% endblock theme%}
<img src="{{ url_for('static', filename='svg/arrow_2.svg')}}" /> <img src="{{ url_for('static', filename='svg/arrow_2.svg')}}" />
{% block editcss %} {% block editcss %}
{% include "distribusi_workflow/editcss.html" %} {% include "distribusiworkflow/editcss.html" %}
{% endblock editcss%} {% endblock editcss%}
<img src="{{ url_for('static', filename='svg/arrow_3.svg')}}" /> <img src="{{ url_for('static', filename='svg/arrow_3.svg')}}" />
{% block launch %} {% block launch %}
{% include "distribusi_workflow/launch.html" %} {% include "distribusiworkflow/launch.html" %}
{% endblock launch%} {% endblock launch%}
{%endif%} {%endif%}
</div> </div>
{% if css_selected %} {% if css_selected %}
<p id="cssSelected" hidden>css selected</p> <p id="cssSelected" hidden>css selected</p>
{% endif %} {% endif %}
<link rel="stylesheet" type="text/css" href="{{ url_for('distribusikan.static', filename='css/distribusikan.css')}}">
{% endblock main %} {% endblock main %}

View File

@ -1,10 +1,10 @@
<div id="edit" class="workflow"> <div id="edit" class="workflow">
<h2>Step 3: Edit Custom CSS (Optional)</h2> <h2>Step 3: Edit Custom CSS (Optional)</h2>
{% if files_uploaded or distribusi_live %} {% 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 %} {% else %}
<p> <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. for your files.
</p> </p>
<p><a href="#upload">Go to Step 1</a></p> <p><a href="#upload">Go to Step 1</a></p>

View File

@ -3,7 +3,7 @@
<p class="tooltip">Run distribusi on your files. This will generate your website and make <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! your content public. <span class="tooltiptext">Distribusi will unpack your zip file and turn it into a website!
</span></p> </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 }} {{ distribusiform.csrf_token }}
{% if files_uploaded or distribusi_live %} {% if files_uploaded or distribusi_live %}
<fieldset class="button required"> <fieldset class="button required">

View File

@ -1,7 +1,7 @@
<div id="distribusi" class="workflow"> <div id="distribusi" class="workflow">
<h2>Welcome back to your Distribusi</h2> <h2>Welcome back to your Distribusi</h2>
<p>You have already uploaded a distribusi website:</p> <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 }} {{ selectorform.csrf_token }}
<fieldset class="required"> <fieldset class="required">
{{ selectorform.distribusis.label }} {{ selectorform.distribusis.label }}
@ -18,13 +18,6 @@
{{ selectorform.update }} {{ selectorform.update }}
</fieldset> </fieldset>
<hr> <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> <p>
This will delete your distribusi site. This will delete your distribusi site.
<strong> This action cannot be undone! </strong> <strong> This action cannot be undone! </strong>
@ -36,7 +29,6 @@
{% endfor %} {% endfor %}
</fieldset> </fieldset>
<hr> <hr>
<div class="new_divider"></div>
{% if limit_reached %} {% if limit_reached %}
<p>You have reached your limit of distribusi websites</p> <p>You have reached your limit of distribusi websites</p>
{% else %} {% else %}

View File

@ -4,7 +4,7 @@
step 3.</p> step 3.</p>
<p>Don't forget to press Save</p> <p>Don't forget to press Save</p>
<hr> <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 }} {{ themeform.csrf_token }}
<fieldset class="required"> <fieldset class="required">
{{ themeform.theme.label }} {{ themeform.theme.label }}
@ -16,14 +16,14 @@
</fieldset> </fieldset>
{% else %} {% else %}
<p> <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. for your files.
</p> </p>
<a href="#upload">Go to Step 1</a> <a href="#upload">Go to Step 1</a>
{% endif %} {% endif %}
</form> </form>
<hr> <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 }} {{ publicthemeform.csrf_token }}
<fieldset id="publicthemes" class="required"> <fieldset id="publicthemes" class="required">
{{ publicthemeform.publicthemes.label }} {{ publicthemeform.publicthemes.label }}
@ -35,7 +35,7 @@
</fieldset> </fieldset>
{% else %} {% else %}
<p> <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. for your files.
</p> </p>
<a href="#upload">Go to Step 1</a> <a href="#upload">Go to Step 1</a>

View File

@ -1,7 +1,7 @@
<div id="upload" class="workflow"> <div id="upload" class="workflow">
<h2>Step 1: Upload</h2> <h2>Step 1: Upload</h2>
<p>Upload your files here:</p> <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 }} {{ uploadform.csrf_token }}
<fieldset class="required"> <fieldset class="required">
{{ uploadform.sitename.label }} {{ uploadform.sitename.label }}
@ -11,26 +11,28 @@
{% endfor %} {% endfor %}
</fieldset> </fieldset>
<fieldset class="required"> <fieldset class="required">
{{ uploadform.description.label }} {{ uploadform.academicyear.label }}
{{ uploadform.description }}
{% for message in uploadform.description.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="required">
{{ uploadform.year.label }}
<div class="selector-style"> <div class="selector-style">
{{ uploadform.year }} {{ uploadform.academicyear }}
{% for message in uploadform.year.errors %} {% for message in uploadform.academicyear.errors %}
<div class="error">{{ message }}</div> <div class="error">{{ message }}</div>
{% endfor %} {% endfor %}
</div> </div>
</fieldset> </fieldset>
<fieldset class="required"> <fieldset class="required">
{{ uploadform.category.label }} {{ uploadform.term.label }}
<div class="selector-style"> <div class="selector-style">
{{ uploadform.category }} {{ uploadform.term }}
{% for message in uploadform.category.errors %} {% 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> <div class="error">{{ message }}</div>
{% endfor %} {% endfor %}
</div> </div>

View File

@ -1,11 +1,11 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% 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="editareas">
<div class="editarea editor"> <div class="editarea editor">
<fieldset class="required"> <fieldset class="required">
<textarea id="html" placeholder="Write some test HTML here" readonly> <textarea id="html" placeholder="Write some test HTML here" readonly>
{{html_placeholder}} {{htmlplaceholder}}
</textarea> </textarea>
</fieldset> </fieldset>
</div> </div>
@ -54,6 +54,6 @@
</form> </form>
<iframe id="code"></iframe> <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> <script src="{{ url_for('static', filename='js/editorupdate.js')}}"></script>
{% endblock main %} {% endblock main %}

View 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 %}

View File

@ -1,13 +1,12 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="mainworkflow"> <div id="mainworkflow">
<div class="login"> <div class="workflow">
<h2>Forgot your password?</h2> <h2>Forgot your password?</h2>
<p> <p>
Enter the email address that was used to register with Distribusiverse. Enter the email address that was used to register with Distribusiverse.
</p> </p>
<form class="form" action="{{ url_for('forgotpassword.forgotpassword') }}" <form class="form" action="{{ url_for('forgotpassword') }}" method="post">
method="post">
{{ forgotpasswordform.csrf_token }} {{ forgotpasswordform.csrf_token }}
<fieldset class="required"> <fieldset class="required">
{{ forgotpasswordform.email.label }} {{ forgotpasswordform.email.label }}
@ -26,6 +25,5 @@
</fieldset> </fieldset>
</form> </form>
</div> </div>
</div> </div
<link rel="stylesheet" type="text/css" href="{{ url_for('forgotpassword.static', filename='css/login.css')}}">
{% endblock main %} {% endblock main %}

View File

@ -1,4 +1,4 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="buttons"> <div id="buttons">
<div class="overview"> <div class="overview">
@ -19,7 +19,7 @@
</div> </div>
{% else %} {% else %}
<div class="distribusi"> <div class="distribusi">
<a href="distribusikan/distribusi"> <a href="/distribusi">
<input type="button" name="button" value="Distribusi"></input> <input type="button" name="button" value="Distribusi"></input>
</a> </a>
</div> </div>

View File

@ -1,4 +1,4 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="buttons"> <div id="buttons">
@ -15,7 +15,7 @@
</div> </div>
{% else %} {% else %}
<div class="distribusi"> <div class="distribusi">
<a href="distribusikan/distribusi"> <a href="/distribusi">
<input type="button" name="button" value="Distribusi"></input> <input type="button" name="button" value="Distribusi"></input>
</a> </a>
</div> </div>
@ -46,14 +46,19 @@
<div class="maincontent"> <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>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> </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> </div>
<!-- a div with all the distribusis listed in the distribusiverse --> <!-- a div with all the distribusis listed in the distribusiverse -->
<div id="distribusiverse" class="maincontent"> <div id="distribusiverse" class="maincontent">
<h2>List of distribusis</h2> <h2>List of distribusis</h2>
{% include 'base/filtermenu.html' %} {% include 'filtermenu.html' %}
<ul id="distribusi-index"> <ul id="distribusi-index">
{% for name, distribusi in distribusisindex.items() %} {% 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> <a href='stash/{{name}}/index.html'>{{distribusi["username"]}}:{{name}}</a>
{% for tag in distribusi["tags"] %} {% for tag in distribusi["tags"] %}
<span class="tags">{{tag}}</span> <span class="tags">{{tag}}</span>

View File

@ -1,7 +1,7 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="login"> <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 }} {{ loginform.csrf_token }}
<fieldset class="required"> <fieldset class="required">
{{ loginform.email.label }} {{ loginform.email.label }}
@ -19,9 +19,8 @@
</fieldset> </fieldset>
<fieldset class="button required"> <fieldset class="button required">
{{ loginform.submit }} {{ loginform.submit }}
<a href="forgotpassword">Forgot Password?</a> <a href="/forgotpassword">Forgot Password?</a>
</fieldset> </fieldset>
</form> </form>
</div> </div>
<link rel="stylesheet" type="text/css" href="{{ url_for('login.static', filename='css/login.css')}}">
{% endblock main %} {% endblock main %}

View File

@ -1,7 +1,7 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="login"> <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 }} {{ registerform.csrf_token }}
<fieldset class="required"> <fieldset class="required">
{{ registerform.username.label }} {{ registerform.username.label }}
@ -36,5 +36,4 @@
</fieldset> </fieldset>
</form> </form>
</div> </div>
<link rel="stylesheet" type="text/css" href="{{ url_for('register.static', filename='css/login.css')}}">
{% endblock main %} {% endblock main %}

View File

@ -1,4 +1,4 @@
{% extends "base/base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<div id="login"> <div id="login">
{% if linkvalid%} {% if linkvalid%}
@ -26,5 +26,4 @@
<h3>Password reset link no longer valid.</h3> <h3>Password reset link no longer valid.</h3>
{% endif %} {% endif %}
</div> </div>
<link rel="stylesheet" type="text/css" href="{{ url_for('reset_password.static', filename='css/login.css')}}">
{% endblock main %} {% endblock main %}

View File

@ -6,14 +6,14 @@
<div id="willemdekooning-logo" class="png"> <div id="willemdekooning-logo" class="png">
<figure> <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> <figcaption>logo.png</figcaption>
</figure> </figure>
</div> </div>
<div id="example_video" class="mp4"> <div id="example_video" class="mp4">
<video controls> <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> </video>
<span class="filename">example_video.mp4</span> <span class="filename">example_video.mp4</span>
</div> </div>

View File

@ -1,47 +1,49 @@
import os import os
import shutil import shutil
from flask import render_template 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 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() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if themeform.validate_on_submit(): if themeform.validate_on_submit():
copycssfile = os.path.join( copycssfile = os.path.join(
"themes", "themes",
f"{themeform.theme.data}.css", f"{themeform.theme.data}.css",
) )
move_css_to_user_folder(current_distribusi, copycssfile) MoveCssToUserFolder(current_distribusi, copycssfile)
if publicthemeform.validate_on_submit(): if publicthemeform.validate_on_submit():
copycssfile = os.path.join( copycssfile = os.path.join(
"themes/publicthemes/", "themes/publicthemes/",
f"{publicthemeform.publicthemes.data}.css", f"{publicthemeform.publicthemes.data}.css",
) )
move_css_to_user_folder(current_distribusi, copycssfile) MoveCssToUserFolder(current_distribusi, copycssfile)
return render_distribusi_template( return RenderDistribusiTemplate(
themeform, publicthemeform, current_distribusi 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) newcssfolder = os.path.join("themes/userthemes", current_distribusi)
if not os.path.exists(newcssfolder): if not os.path.exists(newcssfolder):
os.mkdir(newcssfolder) os.mkdir(newcssfolder)
shutil.copy(copycssfile, newcssfolder) shutil.copy(copycssfile, newcssfolder)
def render_distribusi_template(themeform, publicthemeform, current_distribusi): def RenderDistribusiTemplate(themeform, publicthemeform, current_distribusi):
uploadform = UploadForm() uploadform = UploadForm()
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
selectorform = SelectorForm() selectorform = SelectorForm()

View File

@ -1,25 +1,25 @@
import os import os
import shutil import shutil
from flask import flash from flask import flash
from flask_login import current_user from flask_login import current_user
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError,
DataError,
IntegrityError, IntegrityError,
InterfaceError,
InvalidRequestError, InvalidRequestError,
DataError,
InterfaceError,
DatabaseError,
) )
from app import db from app import db
from distribusikan.distribusi_selector import select_current_distribusi
from distribusikan.forms.uploadform import UploadForm from usermodel import User
from models.distribusi_model import Distribusis from distribusimodel import Distribusis
from models.user_model import User
from statuspengguna.helper import UserHelper from statuspengguna.helper import UserHelper
from distribusiselector import SelectCurrentDistribusi
from forms.uploadform import UploadForm
def upload_new_distribusi(uploadfolder): def UploadNewDistribusi(uploadfolder):
uploadform = UploadForm() uploadform = UploadForm()
if uploadform.validate_on_submit(): if uploadform.validate_on_submit():
user = User.query.filter_by(email=current_user.email).first() user = User.query.filter_by(email=current_user.email).first()
@ -27,9 +27,9 @@ def upload_new_distribusi(uploadfolder):
newdistribusi = Distribusis( newdistribusi = Distribusis(
distribusiname=uploadform.sitename.data, distribusiname=uploadform.sitename.data,
userid=user.id, userid=user.id,
category=uploadform.category.data, term=uploadform.term.data,
description=uploadform.description.data, course=uploadform.course.data,
year=uploadform.year.data, year=uploadform.academicyear.data,
tags=uploadform.tags.data, tags=uploadform.tags.data,
) )
user.currentdistribusi = uploadform.sitename.data user.currentdistribusi = uploadform.sitename.data
@ -47,7 +47,7 @@ def upload_new_distribusi(uploadfolder):
uploadform.sitename.errors.append("Something went wrong!") uploadform.sitename.errors.append("Something went wrong!")
flash("Something went wrong!", "danger") flash("Something went wrong!", "danger")
return uploadform return uploadform
select_current_distribusi(newdistribusi.distribusiname) SelectCurrentDistribusi(newdistribusi.distribusiname)
zipfilename = "{}.zip".format(newdistribusi.distribusiname) zipfilename = "{}.zip".format(newdistribusi.distribusiname)
zipfile = uploadform.zipfile.data zipfile = uploadform.zipfile.data
zipfile.save(os.path.join(uploadfolder, zipfilename)) zipfile.save(os.path.join(uploadfolder, zipfilename))
@ -63,7 +63,7 @@ def upload_new_distribusi(uploadfolder):
return uploadform return uploadform
def upload_updates_files(uploadfolder): def UploadUpdatedFiles(uploadfolder):
uploadform = UploadForm() uploadform = UploadForm()
if uploadform.validate_on_submit(): if uploadform.validate_on_submit():
try: try:
@ -71,9 +71,9 @@ def upload_updates_files(uploadfolder):
distribusi = Distribusis.query.filter_by( distribusi = Distribusis.query.filter_by(
distribusiname=current_distribusi distribusiname=current_distribusi
).first() ).first()
distribusi.category = uploadform.category.data distribusi.term = uploadform.term.data
distribusi.description = (uploadform.description.data,) distribusi.course = uploadform.course.data
distribusi.year = uploadform.year.data distribusi.year = uploadform.academicyear.data
distribusi.tags = uploadform.tags.data distribusi.tags = uploadform.tags.data
distribusi.visible = False distribusi.visible = False
db.session.commit() db.session.commit()

View File

@ -1,34 +1,33 @@
from flask import render_template from flask import render_template
from app import APP from forms.distribusiform import DistribusiForm
from distribusikan.distribusi_selector import selector_visible from forms.themeform import ThemeForm
from distribusikan.distribusis_info import DistribusisInfo from forms.publicthemeform import PublicThemeForm
from distribusikan.upload import upload_new_distribusi, upload_updates_files from forms.selectorform import SelectorForm
from distribusikan.forms.distribusiform import DistribusiForm
from distribusikan.forms.publicthemeform import PublicThemeForm
from distribusikan.forms.selectorform import SelectorForm
from distribusikan.forms.themeform import ThemeForm
# UserPengguna # UserPengguna
from statuspengguna.helper import UserHelper 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" "render upload page section of distribusi workflow"
uploadfolder = APP.config["UPLOAD_FOLDER"]
distribusiform = DistribusiForm() distribusiform = DistribusiForm()
themeform = ThemeForm() themeform = ThemeForm()
publicthemeform = PublicThemeForm() publicthemeform = PublicThemeForm()
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
selectorform = SelectorForm() selectorform = SelectorForm()
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames() selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
selectorvisible = selector_visible() selectorvisible = SelectorVisible()
current_distribusi = UserHelper.current_distribusi() current_distribusi = UserHelper.current_distribusi()
if current_distribusi == "new" or UserHelper.has_distribusi() is False: if current_distribusi == "new" or UserHelper.has_distribusi() is False:
uploadform = upload_new_distribusi(uploadfolder) uploadform = UploadNewDistribusi(uploadfolder)
else: else:
uploadform = upload_updates_files(uploadfolder) uploadform = UploadUpdatedFiles(uploadfolder)
files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data) files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data)
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) distribusi_live = UserHelper.is_distribusi_live(current_distribusi)

View File

@ -1,6 +1,5 @@
from flask_login import UserMixin
from app import db from app import db
from flask_login import UserMixin
class User(UserMixin, db.Model): class User(UserMixin, db.Model):
@ -15,6 +14,8 @@ class User(UserMixin, db.Model):
currentdistribusi = db.Column(db.String(300), nullable=True, unique=False) currentdistribusi = db.Column(db.String(300), nullable=True, unique=False)
resethash = db.Column(db.String(300), nullable=True, unique=True) resethash = db.Column(db.String(300), nullable=True, unique=True)
resettime = db.Column(db.DateTime) resettime = db.Column(db.DateTime)
#active = db.Column(db.Boolean, default=False)
tutor = db.Column(db.Boolean, default=False)
admin = db.Column(db.Boolean, default=False) admin = db.Column(db.Boolean, default=False)
def __repr__(self): def __repr__(self):