main #12
2
.gitignore
vendored
@ -3,10 +3,12 @@
|
||||
*.pyc
|
||||
*.egg-info/
|
||||
.eggs/
|
||||
.ruff_cache
|
||||
build/
|
||||
dist/
|
||||
pip-wheel-metadata/
|
||||
|
||||
verse/tmpupload/*
|
||||
verse/stash/*
|
||||
verse/search/searchdata/*
|
||||
*.db
|
||||
|
@ -1,25 +1,49 @@
|
||||
[tool.black]
|
||||
[tool.ruff]
|
||||
line-length = 79
|
||||
target-version = ['py311']
|
||||
include = '\.pyi?$'
|
||||
exclude = '''
|
||||
/(
|
||||
\.eggs
|
||||
| \.git
|
||||
| \.hg
|
||||
| \.mypy_cache
|
||||
| \.tox
|
||||
| \.venv
|
||||
| _build
|
||||
| buck-out
|
||||
| build
|
||||
| dist
|
||||
|
||||
# The following are specific to Black, you probably don't want those.
|
||||
| blib2to3
|
||||
| tests/data
|
||||
| profiling
|
||||
)/
|
||||
'''
|
||||
target-version = "py311"
|
||||
#include = '\.pyi?$'
|
||||
exclude = [
|
||||
".bzr",
|
||||
".direnv",
|
||||
".eggs",
|
||||
".git",
|
||||
".git-rewrite",
|
||||
".hg",
|
||||
".ipynb_checkpoints",
|
||||
".mypy_cache",
|
||||
".nox",
|
||||
".pants.d",
|
||||
".pyenv",
|
||||
".pytest_cache",
|
||||
".pytype",
|
||||
".ruff_cache",
|
||||
".svn",
|
||||
".tox",
|
||||
".venv",
|
||||
".vscode",
|
||||
"__pypackages__",
|
||||
"_build",
|
||||
"buck-out",
|
||||
"build",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"site-packages",
|
||||
"venv",
|
||||
]
|
||||
|
||||
[tool.ruff.lint]
|
||||
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
||||
select = ["E4", "E7", "E9", "F"]
|
||||
ignore = []
|
||||
# Allow fix for all enabled rules (when `--fix`) is provided.
|
||||
fixable = ["ALL"]
|
||||
unfixable = []
|
||||
# Allow unused variables when underscore-prefixed.
|
||||
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "double"
|
||||
indent-style = "space"
|
||||
docstring-code-format = true
|
||||
line-ending = "auto"
|
||||
skip-magic-trailing-comma = false
|
||||
|
@ -6,9 +6,9 @@ black==24.4.0
|
||||
bleach==4.1.0
|
||||
bleach-allowlist==1.0.3
|
||||
blinker==1.7.0
|
||||
cffi==1.15.0
|
||||
cffi
|
||||
click==8.1.7
|
||||
distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@e291e7497e40211c2ebd54ca32a1f4bdaed71230
|
||||
distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@3eefd6e5ca7048555d441df8c6fbf4f2e255acac
|
||||
dnspython==2.1.0
|
||||
email-validator==1.1.3
|
||||
Flask==3.0.3
|
||||
@ -36,7 +36,7 @@ neovim==0.3.1
|
||||
packaging==24.0
|
||||
passlib==1.7.4
|
||||
pathspec==0.9.0
|
||||
Pillow==8.3.2
|
||||
Pillow
|
||||
platformdirs==2.4.0
|
||||
pycparser==2.21
|
||||
pynvim==0.5.0
|
||||
@ -44,7 +44,7 @@ pyparsing==3.0.7
|
||||
python-dateutil==2.9.0.post0
|
||||
python-magic==0.4.24
|
||||
pytz==2021.3
|
||||
regex==2021.11.10
|
||||
regex
|
||||
six==1.16.0
|
||||
speaklater==1.3
|
||||
SQLAlchemy==2.0.29
|
||||
|
3
src/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
*
|
||||
*/
|
||||
!.gitignore
|
9
verse/admin.py
Normal file
@ -0,0 +1,9 @@
|
||||
from flask_login import current_user
|
||||
from models.user_model import User
|
||||
|
||||
|
||||
def is_adminuser():
|
||||
if not current_user.is_authenticated:
|
||||
return False
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
return user.admin
|
@ -1,7 +1,8 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from flask import render_template
|
||||
from flask import render_template, Blueprint
|
||||
from flask_login import current_user, login_required
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
@ -10,22 +11,34 @@ from sqlalchemy.exc import (
|
||||
)
|
||||
|
||||
from app import db
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from forms.admindistribusiform import AdminDistribusiForm
|
||||
from forms.adminuserform import AdminUserForm
|
||||
from admin import is_adminuser
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from admin_page.forms.admindistribusiform import AdminDistribusiForm
|
||||
from admin_page.forms.adminuserform import AdminUserForm
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
|
||||
admin_page = Blueprint(
|
||||
"admin",
|
||||
__name__,
|
||||
template_folder="templates/describe_files",
|
||||
static_folder="static",
|
||||
)
|
||||
|
||||
def AdminPage():
|
||||
adminuserform = AddUsersToForm(AdminUserForm())
|
||||
admindistribusiform = AddDistribusisToForm(AdminDistribusiForm())
|
||||
|
||||
@admin_page.route("/admin", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def admin():
|
||||
if not is_adminuser():
|
||||
return redirect(url_for("index"))
|
||||
adminuserform = add_users_to_form(AdminUserForm())
|
||||
admindistribusiform = add_distribusis_to_form(AdminDistribusiForm())
|
||||
if admindistribusiform.validate_on_submit():
|
||||
DeleteDistribusis(admindistribusiform)
|
||||
delete_distribusis(admindistribusiform)
|
||||
|
||||
if adminuserform.validate_on_submit():
|
||||
if adminuserform.delete.data:
|
||||
DeleteUsers(adminuserform)
|
||||
delete_users(adminuserform)
|
||||
|
||||
template = render_template(
|
||||
"admin.html",
|
||||
@ -35,19 +48,18 @@ def AdminPage():
|
||||
return template
|
||||
|
||||
|
||||
def DeleteUsers(adminuserform):
|
||||
def delete_users(adminuserform):
|
||||
for userform in adminuserform:
|
||||
if "user" in userform.id:
|
||||
if userform.data:
|
||||
useremail = userform.label.text
|
||||
user = User.query.filter_by(email=useremail).first()
|
||||
DeleteUserDistribusis(user)
|
||||
DeleteUserFromDb(user)
|
||||
delete_User_distribusis(user)
|
||||
delete_user_from_db(user)
|
||||
userform.errors.append(f"User {useremail} deleted!")
|
||||
|
||||
|
||||
|
||||
def DeleteUserFromDb(user):
|
||||
def delete_user_from_db(user):
|
||||
try:
|
||||
db.session.delete(user)
|
||||
db.session.commit()
|
||||
@ -55,14 +67,14 @@ def DeleteUserFromDb(user):
|
||||
db.session.rollback()
|
||||
|
||||
|
||||
def DeleteUserDistribusis(user):
|
||||
distribusis = DistribusisInfo.getuserdistribusis(user.email)
|
||||
def delete_User_distribusis(user):
|
||||
distribusis = DistribusisInfo.get_user_distribusis(user.email)
|
||||
for distribusi in distribusis:
|
||||
DeleteDistribusiFiles(distribusi.distribusiname)
|
||||
DeleteDistribusiFromDb(distribusi)
|
||||
delete_distribusi_files(distribusi.distribusiname)
|
||||
delete_distribusi_from_db(distribusi)
|
||||
|
||||
|
||||
def DeleteDistribusis(admindistribusiform):
|
||||
def delete_distribusis(admindistribusiform):
|
||||
for distribusiform in admindistribusiform:
|
||||
if "distribusi" in distribusiform.id:
|
||||
if distribusiform.data:
|
||||
@ -70,12 +82,12 @@ def DeleteDistribusis(admindistribusiform):
|
||||
distribusi = Distribusis.query.filter_by(
|
||||
distribusiname=distribusiname
|
||||
).first()
|
||||
DeleteDistribusiFromDb(distribusi)
|
||||
DeleteDistribusiFiles(distribusiname)
|
||||
delete_distribusi_from_db(distribusi)
|
||||
delete_distribusi_files(distribusiname)
|
||||
distribusiform.errors.append("Deleted distribusi")
|
||||
|
||||
|
||||
def DeleteDistribusiFromDb(distribusi):
|
||||
def delete_distribusi_from_db(distribusi):
|
||||
try:
|
||||
db.session.delete(distribusi)
|
||||
db.session.commit()
|
||||
@ -83,7 +95,7 @@ def DeleteDistribusiFromDb(distribusi):
|
||||
db.session.rollback()
|
||||
|
||||
|
||||
def DeleteDistribusiFiles(distribusiname):
|
||||
def delete_distribusi_files(distribusiname):
|
||||
userfolder = os.path.join("stash", distribusiname)
|
||||
if os.path.exists(userfolder):
|
||||
shutil.rmtree(userfolder)
|
||||
@ -92,15 +104,15 @@ def DeleteDistribusiFiles(distribusiname):
|
||||
shutil.rmtree(cssfolder)
|
||||
|
||||
|
||||
def AddDistribusisToForm(admindistribusiform):
|
||||
distribusis = DistribusisInfo.visibledistribusis()
|
||||
def add_distribusis_to_form(admindistribusiform):
|
||||
distribusis = DistribusisInfo.visible_distribusis()
|
||||
admindistribusiform = AdminDistribusiForm.distribusi_list_form_builder(
|
||||
distribusis
|
||||
)
|
||||
return admindistribusiform
|
||||
|
||||
|
||||
def AddUsersToForm(adminuserform):
|
||||
def add_users_to_form(adminuserform):
|
||||
users = User.query.all()
|
||||
adminuserform = AdminUserForm.user_list_form_builder(users)
|
||||
return adminuserform
|
@ -8,6 +8,7 @@ from flask_migrate import Migrate
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
|
||||
|
||||
APP = Flask(__name__, static_folder="static")
|
||||
db = SQLAlchemy()
|
||||
migrate = Migrate()
|
||||
@ -19,8 +20,8 @@ def create_app():
|
||||
APP.secret_key = os.urandom(24)
|
||||
APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///distribusiverse.db"
|
||||
APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
|
||||
APP.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 1024
|
||||
|
||||
APP.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 1024
|
||||
APP.config["MAIL_SERVER"] = "mail.autonomic.zone"
|
||||
APP.config["MAIL_PORT"] = 587
|
||||
APP.config["MAIL_USE_SSL"] = False
|
||||
@ -64,7 +65,6 @@ def get_app():
|
||||
|
||||
|
||||
def settings_from_file():
|
||||
settings = {}
|
||||
if os.path.isfile("settings_development.toml"):
|
||||
with open("settings_development.toml", "rb") as settings_file:
|
||||
return tomllib.load(settings_file)
|
||||
|
@ -4,6 +4,7 @@ def deploy():
|
||||
|
||||
from app import create_app, db
|
||||
from models.distribusi_model import Distribusis # noqa: F401
|
||||
from models.distribusi_file_model import DistribusiFiles # noqa: F401
|
||||
|
||||
# This model is required for flask_migrate to make the table
|
||||
from models.user_model import User # noqa: F401
|
||||
|
160
verse/describer/describe_files.py
Normal file
@ -0,0 +1,160 @@
|
||||
import os
|
||||
from flask import (
|
||||
Blueprint,
|
||||
render_template,
|
||||
redirect,
|
||||
url_for,
|
||||
send_from_directory,
|
||||
flash,
|
||||
)
|
||||
from flask_login import current_user, login_required
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
IntegrityError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
import piexif
|
||||
from PIL import Image
|
||||
from app import db
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.distribusi_file_model import DistribusiFiles
|
||||
from describer.forms.describe_files_form import DescribeFilesForm
|
||||
from describer.forms.redistribusi_form import ReDistribusiForm
|
||||
from distribusikan.distribusi_workflow import run_distribusi, get_css_file
|
||||
|
||||
describer = Blueprint(
|
||||
"describer",
|
||||
__name__,
|
||||
template_folder="templates/describe_files",
|
||||
static_folder="static",
|
||||
)
|
||||
|
||||
|
||||
@describer.route("/<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
|
48
verse/describer/forms/describe_files_form.py
Normal file
@ -0,0 +1,48 @@
|
||||
"""Describe File Form to describe files in the distribusi archive"""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, validators
|
||||
from wtforms.validators import Length
|
||||
from wtforms.widgets import TextArea
|
||||
|
||||
|
||||
class DescribeFilesForm(FlaskForm):
|
||||
"""DescribeFileForm selection form."""
|
||||
|
||||
alttext = StringField(
|
||||
"Alt-text for this file:",
|
||||
validators=[
|
||||
Length(3, 255),
|
||||
],
|
||||
)
|
||||
searchtags = StringField(
|
||||
"Add search tags, seperated by commas. No need for the '#' sign:",
|
||||
validators=[
|
||||
Length(3, 500),
|
||||
],
|
||||
)
|
||||
description = StringField(
|
||||
"Description of this file:",
|
||||
validators=[
|
||||
Length(3, 4096),
|
||||
],
|
||||
widget=TextArea(),
|
||||
)
|
||||
save = SubmitField("Save")
|
||||
|
||||
def __init__(self, id, file_path=None, type=None):
|
||||
super(DescribeFilesForm, self).__init__()
|
||||
self.id = id
|
||||
self.file_path = file_path
|
||||
self.type = type
|
||||
self.alttext.id = f"alttext-{id}"
|
||||
self.searchtags.id = f"searchtags-{id}"
|
||||
self.description.id = f"description-{id}"
|
||||
self.save.id = f"save-{id}"
|
||||
|
||||
|
||||
# def StringFieldWithId(form_name, **kwargs):
|
||||
# name = kwargs.get('name', 'Bar')
|
||||
# return wtf.StringField(name, render_kw={
|
||||
# 'id': f'{}{}'.format(form_name, name.lower(),
|
||||
# **kwargs.get('render_kw', {})})
|
8
verse/describer/forms/redistribusi_form.py
Normal file
@ -0,0 +1,8 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import SubmitField
|
||||
|
||||
|
||||
class ReDistribusiForm(FlaskForm):
|
||||
"""Re-Distribusi form class to re-distrusi with desribed files"""
|
||||
|
||||
submit = SubmitField("Re-Distribusi!")
|
32
verse/describer/static/css/describer.css
Normal file
@ -0,0 +1,32 @@
|
||||
#describe_workflow {
|
||||
display: flex;
|
||||
width: 60em;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.redistribusi {
|
||||
position: sticky;
|
||||
top: 2em;
|
||||
margin-top: 2em;
|
||||
margin-left: 1em;
|
||||
width: 15em;
|
||||
height: 10em;
|
||||
border-style: outset;
|
||||
float: right;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.distribusi_file {
|
||||
margin-top: 2em;
|
||||
padding: 0.5em;
|
||||
width: 42em;
|
||||
background-color:#fdfdfd;
|
||||
text-decoration: none;
|
||||
scroll-behavior: smooth;
|
||||
border-style: outset;
|
||||
}
|
||||
|
||||
.distribusi_file > img, video {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
78
verse/describer/templates/describe_files/describe.html
Normal file
@ -0,0 +1,78 @@
|
||||
{% 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 %}
|
13
verse/describer/templates/describe_files/redistribusi.html
Normal file
@ -0,0 +1,13 @@
|
||||
<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>
|
82
verse/distribusikan/add_files_to_describer.py
Normal file
@ -0,0 +1,82 @@
|
||||
import os
|
||||
|
||||
import magic
|
||||
from distribusi.mappings import FILE_TYPES
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.distribusi_file_model import DistribusiFiles
|
||||
from app import create_app, get_app, db
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
DataError,
|
||||
IntegrityError,
|
||||
InterfaceError,
|
||||
InvalidRequestError,
|
||||
)
|
||||
|
||||
MIME_TYPE = magic.Magic(mime=True)
|
||||
|
||||
|
||||
def _distribusi_file_with_type(distribusi, full_path):
|
||||
mime = MIME_TYPE.from_file(full_path)
|
||||
type_, subtype = mime.split("/")
|
||||
if type_ in FILE_TYPES:
|
||||
_add_distribusi_file_to_db(distribusi, full_path, type_)
|
||||
|
||||
|
||||
def _get_distribusi_from_path(path):
|
||||
distribusi = Distribusis.query.filter_by(distribusiname=path).first()
|
||||
return distribusi
|
||||
|
||||
|
||||
def _add_distribusi_file_to_db(distribusi, full_path, type):
|
||||
app = get_app()
|
||||
app.logger.info(f"adding file to database: {full_path} type: {type}")
|
||||
distribusi_file = DistribusiFiles.query.filter_by(path=full_path).first()
|
||||
if distribusi_file is not None:
|
||||
app.logger.error(f"File already in database: {full_path}")
|
||||
return
|
||||
try:
|
||||
new_distribusi_file = DistribusiFiles(
|
||||
path=full_path,
|
||||
type=type,
|
||||
distribusi=distribusi.id,
|
||||
)
|
||||
db.session.add(new_distribusi_file)
|
||||
db.session.commit()
|
||||
return
|
||||
except InvalidRequestError:
|
||||
db.session.rollback()
|
||||
app.logger.error("Something went wrong!")
|
||||
except IntegrityError:
|
||||
db.session.rollback()
|
||||
app.logger.error("File %s already exists!", full_path)
|
||||
except DataError:
|
||||
db.session.rollback()
|
||||
app.logger.error("%s Invalid Entry", full_path)
|
||||
except InterfaceError:
|
||||
db.session.rollback()
|
||||
app.logger.error("Error connecting to the database")
|
||||
except DatabaseError:
|
||||
db.session.rollback()
|
||||
app.logger.error("Error connecting to the database")
|
||||
|
||||
|
||||
def add_distribusi_files_to_db(path):
|
||||
distribusi = _get_distribusi_from_path(path)
|
||||
path = os.path.join("stash", path)
|
||||
for root, dirs, files in os.walk(path, topdown=True):
|
||||
files = list(filter(lambda f: not f.startswith("."), files))
|
||||
files = list(filter(lambda f: not f.endswith(".html"), files))
|
||||
files = list(filter(lambda f: not f.endswith("_thumbnail.jpg"), files))
|
||||
files = list(filter(lambda f: not f.endswith("_alttext.txt"), files))
|
||||
files = list(
|
||||
filter(lambda f: not f.endswith("_dv_description.txt"), files)
|
||||
)
|
||||
|
||||
for file in files:
|
||||
full_path = os.path.join(root, file)
|
||||
distribusi_file = DistribusiFiles.query.filter_by(
|
||||
path=full_path
|
||||
).first()
|
||||
if distribusi_file is None:
|
||||
_distribusi_file_with_type(distribusi, full_path)
|
@ -13,28 +13,28 @@ from sqlalchemy.exc import (
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from app import db
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.editorform import EditorForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
from forms.selectorform import SelectorForm
|
||||
from forms.themeform import ThemeForm
|
||||
from forms.uploadform import UploadForm
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from distribusikan.forms.distribusiform import DistribusiForm
|
||||
from distribusikan.forms.editorform import EditorForm
|
||||
from distribusikan.forms.publicthemeform import PublicThemeForm
|
||||
from distribusikan.forms.selectorform import SelectorForm
|
||||
from distribusikan.forms.themeform import ThemeForm
|
||||
from distribusikan.forms.uploadform import UploadForm
|
||||
from models.distribusi_model import Distribusis
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
|
||||
def Editor():
|
||||
def css_editor_page():
|
||||
editorform = EditorForm()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if editorform.validate_on_submit():
|
||||
ValidateEditCssForm(editorform, current_distribusi)
|
||||
return RenderDistribusiTemplate(current_distribusi)
|
||||
validate_edit_css_form(editorform, current_distribusi)
|
||||
return render_distribusi_template(current_distribusi)
|
||||
|
||||
return RenderEditorTemplate(editorform, current_distribusi)
|
||||
return render_editor_template(editorform, current_distribusi)
|
||||
|
||||
|
||||
def ValidateEditCssForm(editorform, current_distribusi):
|
||||
def validate_edit_css_form(editorform, current_distribusi):
|
||||
newcssfolder = os.path.join("themes/userthemes", current_distribusi)
|
||||
if os.path.exists(newcssfolder):
|
||||
shutil.rmtree(newcssfolder)
|
||||
@ -44,22 +44,22 @@ def ValidateEditCssForm(editorform, current_distribusi):
|
||||
shutil.rmtree(publicfolder)
|
||||
|
||||
if editorform.public.data:
|
||||
MakePublicTheme(editorform, current_distribusi)
|
||||
make_public_theme(editorform, current_distribusi)
|
||||
if editorform.cssfile.data:
|
||||
SaveUploadCssFile(editorform, publicfolder)
|
||||
CopyPublicToUserFolder(editorform, publicfolder, newcssfolder)
|
||||
save_upload_css_file(editorform, publicfolder)
|
||||
copy_public_to_user_folder(editorform, publicfolder, newcssfolder)
|
||||
return
|
||||
else:
|
||||
WriteCssToFile(editorform, publicfolder)
|
||||
write_css_to_file(editorform, publicfolder)
|
||||
|
||||
if editorform.cssfile.data:
|
||||
SaveUploadCssFile(editorform, newcssfolder)
|
||||
save_upload_css_file(editorform, newcssfolder)
|
||||
return
|
||||
if editorform.cssname.data:
|
||||
WriteCssToFile(editorform, newcssfolder)
|
||||
write_css_to_file(editorform, newcssfolder)
|
||||
|
||||
|
||||
def SaveUploadCssFile(editorform, newcssfolder):
|
||||
def save_upload_css_file(editorform, newcssfolder):
|
||||
if not os.path.exists(newcssfolder):
|
||||
os.mkdir(newcssfolder)
|
||||
cssfile = editorform.cssfile.data
|
||||
@ -74,7 +74,7 @@ def SaveUploadCssFile(editorform, newcssfolder):
|
||||
cleanfile.close()
|
||||
|
||||
|
||||
def WriteCssToFile(editorform, newcssfolder):
|
||||
def write_css_to_file(editorform, newcssfolder):
|
||||
if not os.path.exists(newcssfolder):
|
||||
os.mkdir(newcssfolder)
|
||||
|
||||
@ -86,7 +86,7 @@ def WriteCssToFile(editorform, newcssfolder):
|
||||
cssfile.close
|
||||
|
||||
|
||||
def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder):
|
||||
def copy_public_to_user_folder(editorform, publicfolder, newcssfolder):
|
||||
if not os.path.exists(newcssfolder):
|
||||
os.mkdir(newcssfolder)
|
||||
copycssfile = os.path.join(
|
||||
@ -97,7 +97,7 @@ def CopyPublicToUserFolder(editorform, publicfolder, newcssfolder):
|
||||
shutil.copy(copycssfile, newcssfolder)
|
||||
|
||||
|
||||
def MakePublicTheme(editorform, current_distribusi):
|
||||
def make_public_theme(editorform, current_distribusi):
|
||||
try:
|
||||
distribusi = Distribusis.query.filter_by(
|
||||
distribusiname=current_distribusi
|
||||
@ -119,12 +119,12 @@ def MakePublicTheme(editorform, current_distribusi):
|
||||
editorform.public.errors.append("Error connecting to the database")
|
||||
|
||||
|
||||
def RenderDistribusiTemplate(current_distribusi):
|
||||
def render_distribusi_template(current_distribusi):
|
||||
uploadform = UploadForm()
|
||||
distribusiform = DistribusiForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
selectorform = SelectorForm()
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
|
||||
@ -148,11 +148,11 @@ def RenderDistribusiTemplate(current_distribusi):
|
||||
return template
|
||||
|
||||
|
||||
def RenderEditorTemplate(editorform, current_distribusi):
|
||||
htmlplaceholder = HtmlPlaceholder()
|
||||
def render_editor_template(editorform, current_distribusi):
|
||||
html_placeholder = get_html_placeholder()
|
||||
|
||||
cssplaceholder = CssPlaceholder(current_distribusi)
|
||||
editorform.css.data = cssplaceholder
|
||||
css_placeholder = get_css_placeholder(current_distribusi)
|
||||
editorform.css.data = css_placeholder
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
|
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
|
||||
@ -161,33 +161,33 @@ def RenderEditorTemplate(editorform, current_distribusi):
|
||||
files_uploaded=files_uploaded,
|
||||
distribusi_live=distribusi_live,
|
||||
editorform=editorform,
|
||||
htmlplaceholder=htmlplaceholder,
|
||||
html_placeholder=html_placeholder,
|
||||
)
|
||||
return template
|
||||
|
||||
|
||||
def CssPlaceholder(current_distribusi):
|
||||
cssplaceholder = "Try out your CSS here"
|
||||
def get_css_placeholder(current_distribusi):
|
||||
css_placeholder = "Try out your CSS here"
|
||||
distribusi = Distribusis.query.filter_by(
|
||||
distribusiname=current_distribusi
|
||||
).first()
|
||||
if distribusi is not None and distribusi.publictheme is not None:
|
||||
cssplaceholder = GetPublicCssFile(distribusi)
|
||||
css_placeholder = get_public_css_file(distribusi)
|
||||
else:
|
||||
with open("themes/editor/placeholder.css") as f:
|
||||
cssplaceholder = f.read()
|
||||
return cssplaceholder
|
||||
css_placeholder = f.read()
|
||||
return css_placeholder
|
||||
|
||||
|
||||
def HtmlPlaceholder():
|
||||
htmlplaceholder = "Write some test HTML here"
|
||||
def get_html_placeholder():
|
||||
html_placeholder = "Write some test HTML here"
|
||||
with open("themes/editor/placeholder.html") as f:
|
||||
htmlplaceholder = f.read()
|
||||
return htmlplaceholder
|
||||
html_placeholder = f.read()
|
||||
return html_placeholder
|
||||
|
||||
|
||||
def GetPublicCssFile(distribusi):
|
||||
cssplaceholder = ""
|
||||
def get_public_css_file(distribusi):
|
||||
css_placeholder = ""
|
||||
publicthemefolder = os.path.join(
|
||||
"themes/publicthemes", distribusi.distribusiname
|
||||
)
|
||||
@ -195,5 +195,5 @@ def GetPublicCssFile(distribusi):
|
||||
if filename.endswith(".css"):
|
||||
cssfile = os.path.join(publicthemefolder, filename)
|
||||
with open(cssfile) as f:
|
||||
cssplaceholder = f.read()
|
||||
return cssplaceholder
|
||||
css_placeholder = f.read()
|
||||
return css_placeholder
|
@ -1,7 +1,7 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from flask import flash, render_template
|
||||
from flask import flash, render_template, redirect, url_for
|
||||
from flask_login import current_user
|
||||
from sqlalchemy.exc import (
|
||||
DatabaseError,
|
||||
@ -11,12 +11,12 @@ from sqlalchemy.exc import (
|
||||
)
|
||||
|
||||
from app import db
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
from forms.selectorform import SelectorForm
|
||||
from forms.themeform import ThemeForm
|
||||
from forms.uploadform import UploadForm
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from distribusikan.forms.distribusiform import DistribusiForm
|
||||
from distribusikan.forms.publicthemeform import PublicThemeForm
|
||||
from distribusikan.forms.selectorform import SelectorForm
|
||||
from distribusikan.forms.themeform import ThemeForm
|
||||
from distribusikan.forms.uploadform import UploadForm
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
|
||||
@ -24,52 +24,66 @@ from models.user_model import User
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
|
||||
def DistribusiSelector():
|
||||
def distribusi_selector():
|
||||
uploadform = UploadForm()
|
||||
selectorform = SelectorForm()
|
||||
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
|
||||
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if selectorform.validate_on_submit():
|
||||
if selectorform.new.data:
|
||||
SelectNewDistribusi()
|
||||
select_new_distribusi()
|
||||
if selectorform.describe.data:
|
||||
return select_describe_distribusi(selectorform.distribusis.data)
|
||||
if selectorform.delete.data:
|
||||
selectorform = DeleteDistribusi(selectorform.distribusis.data)
|
||||
selectorform = delete_distribusi(selectorform.distribusis.data)
|
||||
selectorform.distribusis.choices = (
|
||||
DistribusisInfo.userdistribusinames()
|
||||
DistribusisInfo.user_distribusinames()
|
||||
)
|
||||
if selectorform.update.data:
|
||||
SelectUpdateDistribusi(selectorform.distribusis.data)
|
||||
select_update_distribusi(selectorform.distribusis.data)
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
uploadform = AutoFillInUploadForm(uploadform, current_distribusi)
|
||||
uploadform = auto_fill_in_upload_form(
|
||||
uploadform, current_distribusi
|
||||
)
|
||||
|
||||
return RenderDistribusiTemplate(
|
||||
return render_distribusi_template(
|
||||
selectorform, uploadform, current_distribusi
|
||||
)
|
||||
|
||||
|
||||
def AutoFillInUploadForm(uploadform, current_distribusi):
|
||||
def auto_fill_in_upload_form(uploadform, current_distribusi):
|
||||
distribusi = Distribusis.query.filter_by(
|
||||
distribusiname=current_distribusi
|
||||
).first()
|
||||
uploadform.sitename.data = distribusi.distribusiname
|
||||
uploadform.sitename.render_kw = {"readonly": True}
|
||||
uploadform.description.data = distribusi.description
|
||||
uploadform.category.data = distribusi.category
|
||||
uploadform.year.data = distribusi.year
|
||||
uploadform.tags.data = distribusi.tags
|
||||
return uploadform
|
||||
|
||||
|
||||
def SelectNewDistribusi():
|
||||
def select_new_distribusi():
|
||||
print("make a new distribusi")
|
||||
SelectCurrentDistribusi("new")
|
||||
select_current_distribusi("new")
|
||||
|
||||
|
||||
def SelectUpdateDistribusi(distribusiname):
|
||||
def select_describe_distribusi(distribusiname):
|
||||
return redirect(
|
||||
url_for(
|
||||
"describer.show_distribusi_files",
|
||||
distribusiname=distribusiname,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def select_update_distribusi(distribusiname):
|
||||
print(f"Update this distribusi {distribusiname}")
|
||||
SelectCurrentDistribusi(distribusiname)
|
||||
select_current_distribusi(distribusiname)
|
||||
|
||||
|
||||
def DeleteDistribusi(distribusiname):
|
||||
def delete_distribusi(distribusiname):
|
||||
print(f"delete this distribusi {distribusiname}")
|
||||
selectorform = SelectorForm()
|
||||
try:
|
||||
@ -103,7 +117,7 @@ def DeleteDistribusi(distribusiname):
|
||||
return selectorform
|
||||
|
||||
|
||||
def SelectCurrentDistribusi(distribusiname):
|
||||
def select_current_distribusi(distribusiname):
|
||||
if not current_user.is_authenticated:
|
||||
return
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
@ -115,35 +129,35 @@ def SelectCurrentDistribusi(distribusiname):
|
||||
flash("An error occured !", "danger")
|
||||
|
||||
|
||||
def DistribusiSelected():
|
||||
def distribusi_selected():
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
if user.currentdistribusi is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def SelectorVisible():
|
||||
def selector_visible():
|
||||
has_distribusi = UserHelper.has_distribusi()
|
||||
distribusi_selected = DistribusiSelected()
|
||||
if distribusi_selected:
|
||||
is_distribusi_selected = distribusi_selected()
|
||||
if is_distribusi_selected:
|
||||
return False
|
||||
if not has_distribusi:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def RenderDistribusiTemplate(selectorform, uploadform, current_distribusi):
|
||||
def render_distribusi_template(selectorform, uploadform, current_distribusi):
|
||||
distribusiform = DistribusiForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
|
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
|
||||
|
||||
# because the user has chosen to update his distribusi, we assume
|
||||
# no selected css.
|
||||
css_selected = False
|
||||
selectorvisible = SelectorVisible()
|
||||
selectorvisible = selector_visible()
|
||||
limit_reached = UserHelper.distribusi_limit_reached()
|
||||
template = render_template(
|
||||
"distribusi.html",
|
@ -15,15 +15,16 @@ from sqlalchemy.exc import (
|
||||
)
|
||||
|
||||
from app import db
|
||||
from distribusikan.distribusiselector import SelectorVisible
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
from forms.selectorform import SelectorForm
|
||||
from forms.themeform import ThemeForm
|
||||
from distribusikan.add_files_to_describer import add_distribusi_files_to_db
|
||||
from distribusikan.distribusi_selector import selector_visible
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from distribusikan.forms.distribusiform import DistribusiForm
|
||||
from distribusikan.forms.publicthemeform import PublicThemeForm
|
||||
from distribusikan.forms.selectorform import SelectorForm
|
||||
from distribusikan.forms.themeform import ThemeForm
|
||||
|
||||
# Forms!
|
||||
from forms.uploadform import UploadForm
|
||||
from distribusikan.forms.uploadform import UploadForm
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
|
||||
@ -31,7 +32,7 @@ from models.user_model import User
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
|
||||
def DistribusiWorkflow():
|
||||
def distribusi_workflow():
|
||||
distribusiform = DistribusiForm()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
@ -41,18 +42,19 @@ def DistribusiWorkflow():
|
||||
|
||||
if distribusiform.validate_on_submit():
|
||||
userfolder = os.path.join("stash", distribusi.distribusiname)
|
||||
cssfile = GetCssFile(distribusi)
|
||||
UnzipDistribusiFiles(distribusi, userfolder)
|
||||
CleanUpDistribusiFiles(userfolder)
|
||||
RunDistribusi(userfolder, cssfile)
|
||||
SetDistribusiToVisible(distribusi, user)
|
||||
DeleteCssFile(cssfile)
|
||||
cssfile = get_css_file(distribusi)
|
||||
unzip_distribusi_files(distribusi, userfolder)
|
||||
clean_up_distribusi_files(userfolder)
|
||||
add_distribusi_files_to_db(distribusi.distribusiname)
|
||||
run_distribusi(userfolder, cssfile)
|
||||
set_distribusi_to_visible(distribusi, user)
|
||||
delete_css_file(cssfile)
|
||||
return redirect(url_for("index"))
|
||||
|
||||
return RenderDistribusiTemplate(distribusiform, current_distribusi)
|
||||
return render_distribusi_template(distribusiform, current_distribusi)
|
||||
|
||||
|
||||
def UnzipDistribusiFiles(distribusi, userfolder):
|
||||
def unzip_distribusi_files(distribusi, userfolder):
|
||||
zipfilename = "{}.zip".format(distribusi.distribusiname)
|
||||
unzipfile = os.path.join(userfolder, zipfilename)
|
||||
|
||||
@ -64,12 +66,12 @@ def UnzipDistribusiFiles(distribusi, userfolder):
|
||||
os.remove(os.path.join(userfolder, zipfilename))
|
||||
|
||||
|
||||
def CleanUpDistribusiFiles(userfolder):
|
||||
def clean_up_distribusi_files(userfolder):
|
||||
if os.path.exists(userfolder):
|
||||
RemoveMacFolders(userfolder)
|
||||
remove_mac_folders(userfolder)
|
||||
|
||||
|
||||
def RemoveMacFolders(path):
|
||||
def remove_mac_folders(path):
|
||||
for filename in os.listdir(path):
|
||||
fullpath = os.path.join(path, filename)
|
||||
if filename.startswith("."):
|
||||
@ -80,10 +82,10 @@ def RemoveMacFolders(path):
|
||||
if filename == "__MACOSX":
|
||||
shutil.rmtree(fullpath)
|
||||
if os.path.isdir(fullpath):
|
||||
RemoveMacFolders(fullpath)
|
||||
remove_mac_folders(fullpath)
|
||||
|
||||
|
||||
def GetCssFile(distribusi):
|
||||
def get_css_file(distribusi):
|
||||
cssfile = ""
|
||||
cssfolder = os.path.join("themes/userthemes", distribusi.distribusiname)
|
||||
if os.path.exists(cssfolder):
|
||||
@ -93,13 +95,14 @@ def GetCssFile(distribusi):
|
||||
return cssfile
|
||||
|
||||
|
||||
def RunDistribusi(userfolder, cssfile):
|
||||
def run_distribusi(userfolder, cssfile):
|
||||
print(f"Run distribusi on this folder: {userfolder} with css:{cssfile}")
|
||||
parser = build_argparser()
|
||||
args = parser.parse_args(["-t", "--menu-with-index", "-s", cssfile])
|
||||
args = parser.parse_args(["-t", "-a", "--menu-with-index", "-s", cssfile])
|
||||
distribusify(args, userfolder)
|
||||
|
||||
|
||||
def SetDistribusiToVisible(distribusi, user):
|
||||
def set_distribusi_to_visible(distribusi, user):
|
||||
try:
|
||||
distribusi.visible = True
|
||||
user.currentdistribusi = None
|
||||
@ -109,19 +112,19 @@ def SetDistribusiToVisible(distribusi, user):
|
||||
flash("Unknown error occured!")
|
||||
|
||||
|
||||
def DeleteCssFile(cssfile):
|
||||
def delete_css_file(cssfile):
|
||||
if os.path.exists(cssfile):
|
||||
os.remove(cssfile)
|
||||
|
||||
|
||||
def RenderDistribusiTemplate(distribusiform, current_distribusi):
|
||||
def render_distribusi_template(distribusiform, current_distribusi):
|
||||
uploadform = UploadForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
selectorform = SelectorForm()
|
||||
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
|
||||
selectorvisible = SelectorVisible()
|
||||
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames()
|
||||
selectorvisible = selector_visible()
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(current_distribusi)
|
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
|
@ -1,14 +1,13 @@
|
||||
from flask import Blueprint
|
||||
from flask_login import login_required
|
||||
|
||||
from distribusikan.distribusiselector import DistribusiSelector
|
||||
from distribusikan.distribusi_selector import distribusi_selector
|
||||
|
||||
# Distribusi Information
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from distribusikan.distribusiworkflow import DistribusiWorkflow
|
||||
from distribusikan.editor import Editor
|
||||
from distribusikan.themeselector import ThemeSelector
|
||||
from distribusikan.uploadpage import UploadPage
|
||||
from distribusikan.distribusi_workflow import distribusi_workflow
|
||||
from distribusikan.css_editor_page import css_editor_page
|
||||
from distribusikan.theme_selector import theme_selector
|
||||
from distribusikan.upload_page import upload_page
|
||||
|
||||
distribusikan = Blueprint(
|
||||
"distribusikan",
|
||||
@ -21,28 +20,28 @@ distribusikan = Blueprint(
|
||||
@distribusikan.route("/distribusi", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def distribusi():
|
||||
return DistribusiWorkflow()
|
||||
return distribusi_workflow()
|
||||
|
||||
|
||||
@distribusikan.route("/upload", methods=["POST"])
|
||||
@login_required
|
||||
def upload():
|
||||
return UploadPage()
|
||||
return upload_page()
|
||||
|
||||
|
||||
@distribusikan.route("/theme", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def theme():
|
||||
return ThemeSelector()
|
||||
return theme_selector()
|
||||
|
||||
|
||||
@distribusikan.route("/editor", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def editor():
|
||||
return Editor()
|
||||
return css_editor_page()
|
||||
|
||||
|
||||
@distribusikan.route("/selector", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def selector():
|
||||
return DistribusiSelector()
|
||||
return distribusi_selector()
|
||||
|
@ -5,14 +5,14 @@ from models.user_model import User
|
||||
|
||||
|
||||
class DistribusisInfo:
|
||||
def userdistribusinames():
|
||||
def user_distribusinames():
|
||||
distribusinames = []
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
for distribusi in Distribusis.query.filter_by(userid=user.id).all():
|
||||
distribusinames.append(distribusi.distribusiname)
|
||||
return distribusinames
|
||||
|
||||
def publicthemes():
|
||||
def public_themes():
|
||||
publicthemes = []
|
||||
distribusis = Distribusis.query.filter(
|
||||
Distribusis.publictheme.isnot(None)
|
||||
@ -27,12 +27,12 @@ made by {user.username}""",
|
||||
publicthemes.append(publictheme)
|
||||
return publicthemes
|
||||
|
||||
def visibledistribusis():
|
||||
def visible_distribusis():
|
||||
distribusis = Distribusis.query.filter(
|
||||
Distribusis.visible.isnot(False)
|
||||
).all()
|
||||
return distribusis
|
||||
|
||||
def getuserdistribusis(useremail):
|
||||
def get_user_distribusis(useremail):
|
||||
user = User.query.filter_by(email=useremail).first()
|
||||
return Distribusis.query.filter_by(userid=user.id).all()
|
@ -9,4 +9,6 @@ class SelectorForm(FlaskForm):
|
||||
|
||||
update = SubmitField("update")
|
||||
|
||||
describe = SubmitField("describe")
|
||||
|
||||
delete = SubmitField("delete")
|
@ -1,18 +1,18 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileAllowed, FileField, FileRequired, FileSize
|
||||
from wtforms import (
|
||||
IntegerField,
|
||||
SelectField,
|
||||
StringField,
|
||||
SubmitField,
|
||||
TextAreaField,
|
||||
validators,
|
||||
)
|
||||
from wtforms.validators import (
|
||||
DataRequired,
|
||||
Length,
|
||||
NumberRange,
|
||||
ValidationError,
|
||||
)
|
||||
from wtforms.widgets import TextArea
|
||||
|
||||
from app import settings
|
||||
|
||||
@ -50,6 +50,13 @@ class UploadForm(FlaskForm):
|
||||
distribusiname,
|
||||
],
|
||||
)
|
||||
description = StringField(
|
||||
"Description of this distribusi:",
|
||||
validators=[
|
||||
Length(10, 32000),
|
||||
],
|
||||
widget=TextArea(),
|
||||
)
|
||||
year = SelectField(
|
||||
"Year:",
|
||||
validate_choice=True,
|
||||
@ -68,8 +75,8 @@ class UploadForm(FlaskForm):
|
||||
)
|
||||
|
||||
tags = StringField(
|
||||
"Add tags, seperated by commas. No need for the '#' sign:",
|
||||
validators=[validators.InputRequired(), Length(2, 500)],
|
||||
"Add search tags, seperated by commas. No need for the '#' sign:",
|
||||
validators=[validators.InputRequired(), Length(3, 500)],
|
||||
)
|
||||
|
||||
zipfile = FileField(
|
||||
@ -79,7 +86,7 @@ class UploadForm(FlaskForm):
|
||||
FileRequired(),
|
||||
FileSize(
|
||||
max_size=1073741824,
|
||||
message="Zipfile size must be smaller than 100MB",
|
||||
message="Zipfile size must be smaller than 1024MB",
|
||||
),
|
||||
],
|
||||
)
|
32
verse/distribusikan/static/css/distribusikan.css
Normal file
@ -0,0 +1,32 @@
|
||||
#publicthemes > ul {
|
||||
max-height: 20em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#publicthemes > ul > li{
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.workflow{
|
||||
margin-top: 1em;
|
||||
padding: 0.5em;
|
||||
background-color:#fdfdfd;
|
||||
text-decoration: none;
|
||||
scroll-behavior: smooth;
|
||||
border-style: outset;
|
||||
}
|
||||
|
||||
.workflow > p {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.workflow > h2 {
|
||||
padding-left: 0.4em;;
|
||||
}
|
||||
|
||||
.workflow input{
|
||||
max-width: 20em;
|
||||
}
|
||||
.new_divider {
|
||||
height: 5em;
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
}
|
||||
.editarea {
|
||||
width: 30%;
|
||||
border: 3px solid #E0B0FF;
|
||||
border: 3px solid #9de457;
|
||||
border-style: outset;
|
||||
margin-right: 1em;
|
||||
margin-left: 0;
|
||||
@ -31,7 +31,7 @@ textarea {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 250px;
|
||||
background: #E0B0FF;
|
||||
background: #9de457;
|
||||
outline: none;
|
||||
font-family: Courier, sans-serif;
|
||||
font-size: 16px;
|
||||
@ -45,6 +45,6 @@ iframe {
|
||||
height: 30em;
|
||||
}
|
||||
#html {
|
||||
background-color: #60337F;
|
||||
color: lightgrey;
|
||||
background-color: #9de457;
|
||||
color: black;
|
||||
}
|
@ -20,27 +20,28 @@
|
||||
<div id="mainworkflow">
|
||||
{% if selectorvisible %}
|
||||
{% block selector %}
|
||||
{% include "distribusiworkflow/selector.html" %}
|
||||
{% include "distribusi_workflow/selector.html" %}
|
||||
{% endblock selector%}
|
||||
{% else %}
|
||||
{% block upload %}
|
||||
{% include "distribusiworkflow/upload.html" %}
|
||||
{% include "distribusi_workflow/upload.html" %}
|
||||
{% endblock upload%}
|
||||
<img src="{{ url_for('static', filename='svg/arrow_1.svg')}}" />
|
||||
{% block theme %}
|
||||
{% include "distribusiworkflow/theme.html" %}
|
||||
{% include "distribusi_workflow/theme.html" %}
|
||||
{% endblock theme%}
|
||||
<img src="{{ url_for('static', filename='svg/arrow_2.svg')}}" />
|
||||
{% block editcss %}
|
||||
{% include "distribusiworkflow/editcss.html" %}
|
||||
{% include "distribusi_workflow/editcss.html" %}
|
||||
{% endblock editcss%}
|
||||
<img src="{{ url_for('static', filename='svg/arrow_3.svg')}}" />
|
||||
{% block launch %}
|
||||
{% include "distribusiworkflow/launch.html" %}
|
||||
{% include "distribusi_workflow/launch.html" %}
|
||||
{% endblock launch%}
|
||||
{%endif%}
|
||||
</div>
|
||||
{% if css_selected %}
|
||||
<p id="cssSelected" hidden>css selected</p>
|
||||
{% endif %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('distribusikan.static', filename='css/distribusikan.css')}}">
|
||||
{% endblock main %}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div id="edit" class="workflow">
|
||||
<h2>Step 3: Edit Custom CSS (Optional)</h2>
|
||||
{% if files_uploaded or distribusi_live %}
|
||||
<p><a href="/editor">Go to CSS editor</a></p>
|
||||
<p><a href="/distribusikan/editor">Go to CSS editor</a></p>
|
||||
{% else %}
|
||||
<p>
|
||||
You need to upload your files first before you can select a css theme
|
@ -18,6 +18,13 @@
|
||||
{{ selectorform.update }}
|
||||
</fieldset>
|
||||
<hr>
|
||||
<p>
|
||||
Describe your distribusi files. Add description texts, tags for search
|
||||
or add alt-text for images</p>
|
||||
<fieldset class="button required multiselect">
|
||||
{{ selectorform.describe }}
|
||||
</fieldset>
|
||||
<hr>
|
||||
<p>
|
||||
This will delete your distribusi site.
|
||||
<strong> This action cannot be undone! </strong>
|
||||
@ -29,6 +36,7 @@
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<hr>
|
||||
<div class="new_divider"></div>
|
||||
{% if limit_reached %}
|
||||
<p>You have reached your limit of distribusi websites</p>
|
||||
{% else %}
|
@ -10,6 +10,13 @@
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="required">
|
||||
{{ uploadform.description.label }}
|
||||
{{ uploadform.description }}
|
||||
{% for message in uploadform.description.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="required">
|
||||
{{ uploadform.year.label }}
|
||||
<div class="selector-style">
|
@ -5,7 +5,7 @@
|
||||
<div class="editarea editor">
|
||||
<fieldset class="required">
|
||||
<textarea id="html" placeholder="Write some test HTML here" readonly>
|
||||
{{htmlplaceholder}}
|
||||
{{html_placeholder}}
|
||||
</textarea>
|
||||
</fieldset>
|
||||
</div>
|
||||
@ -54,6 +54,6 @@
|
||||
</form>
|
||||
<iframe id="code"></iframe>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/editor.css')}}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('distribusikan.static', filename='css/editor.css')}}">
|
||||
<script src="{{ url_for('static', filename='js/editorupdate.js')}}"></script>
|
||||
{% endblock main %}
|
||||
|
@ -3,45 +3,45 @@ import shutil
|
||||
|
||||
from flask import render_template
|
||||
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
from forms.selectorform import SelectorForm
|
||||
from forms.themeform import ThemeForm
|
||||
from forms.uploadform import UploadForm
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from distribusikan.forms.distribusiform import DistribusiForm
|
||||
from distribusikan.forms.publicthemeform import PublicThemeForm
|
||||
from distribusikan.forms.selectorform import SelectorForm
|
||||
from distribusikan.forms.themeform import ThemeForm
|
||||
from distribusikan.forms.uploadform import UploadForm
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
|
||||
def ThemeSelector():
|
||||
def theme_selector():
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if themeform.validate_on_submit():
|
||||
copycssfile = os.path.join(
|
||||
"themes",
|
||||
f"{themeform.theme.data}.css",
|
||||
)
|
||||
MoveCssToUserFolder(current_distribusi, copycssfile)
|
||||
move_css_to_user_folder(current_distribusi, copycssfile)
|
||||
if publicthemeform.validate_on_submit():
|
||||
copycssfile = os.path.join(
|
||||
"themes/publicthemes/",
|
||||
f"{publicthemeform.publicthemes.data}.css",
|
||||
)
|
||||
MoveCssToUserFolder(current_distribusi, copycssfile)
|
||||
return RenderDistribusiTemplate(
|
||||
move_css_to_user_folder(current_distribusi, copycssfile)
|
||||
return render_distribusi_template(
|
||||
themeform, publicthemeform, current_distribusi
|
||||
)
|
||||
|
||||
|
||||
def MoveCssToUserFolder(current_distribusi, copycssfile):
|
||||
def move_css_to_user_folder(current_distribusi, copycssfile):
|
||||
newcssfolder = os.path.join("themes/userthemes", current_distribusi)
|
||||
if not os.path.exists(newcssfolder):
|
||||
os.mkdir(newcssfolder)
|
||||
shutil.copy(copycssfile, newcssfolder)
|
||||
|
||||
|
||||
def RenderDistribusiTemplate(themeform, publicthemeform, current_distribusi):
|
||||
def render_distribusi_template(themeform, publicthemeform, current_distribusi):
|
||||
uploadform = UploadForm()
|
||||
distribusiform = DistribusiForm()
|
||||
selectorform = SelectorForm()
|
@ -12,14 +12,14 @@ from sqlalchemy.exc import (
|
||||
)
|
||||
|
||||
from app import db
|
||||
from distribusikan.distribusiselector import SelectCurrentDistribusi
|
||||
from forms.uploadform import UploadForm
|
||||
from distribusikan.distribusi_selector import select_current_distribusi
|
||||
from distribusikan.forms.uploadform import UploadForm
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
|
||||
def UploadNewDistribusi(uploadfolder):
|
||||
def upload_new_distribusi(uploadfolder):
|
||||
uploadform = UploadForm()
|
||||
if uploadform.validate_on_submit():
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
@ -28,6 +28,7 @@ def UploadNewDistribusi(uploadfolder):
|
||||
distribusiname=uploadform.sitename.data,
|
||||
userid=user.id,
|
||||
category=uploadform.category.data,
|
||||
description=uploadform.description.data,
|
||||
year=uploadform.year.data,
|
||||
tags=uploadform.tags.data,
|
||||
)
|
||||
@ -46,7 +47,7 @@ def UploadNewDistribusi(uploadfolder):
|
||||
uploadform.sitename.errors.append("Something went wrong!")
|
||||
flash("Something went wrong!", "danger")
|
||||
return uploadform
|
||||
SelectCurrentDistribusi(newdistribusi.distribusiname)
|
||||
select_current_distribusi(newdistribusi.distribusiname)
|
||||
zipfilename = "{}.zip".format(newdistribusi.distribusiname)
|
||||
zipfile = uploadform.zipfile.data
|
||||
zipfile.save(os.path.join(uploadfolder, zipfilename))
|
||||
@ -62,7 +63,7 @@ def UploadNewDistribusi(uploadfolder):
|
||||
return uploadform
|
||||
|
||||
|
||||
def UploadUpdatedFiles(uploadfolder):
|
||||
def upload_updates_files(uploadfolder):
|
||||
uploadform = UploadForm()
|
||||
if uploadform.validate_on_submit():
|
||||
try:
|
||||
@ -71,6 +72,7 @@ def UploadUpdatedFiles(uploadfolder):
|
||||
distribusiname=current_distribusi
|
||||
).first()
|
||||
distribusi.category = uploadform.category.data
|
||||
distribusi.description = (uploadform.description.data,)
|
||||
distribusi.year = uploadform.year.data
|
||||
distribusi.tags = uploadform.tags.data
|
||||
distribusi.visible = False
|
||||
|
@ -1,34 +1,34 @@
|
||||
from flask import render_template
|
||||
|
||||
from app import APP
|
||||
from distribusikan.distribusiselector import SelectorVisible
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from distribusikan.upload import UploadNewDistribusi, UploadUpdatedFiles
|
||||
from forms.distribusiform import DistribusiForm
|
||||
from forms.publicthemeform import PublicThemeForm
|
||||
from forms.selectorform import SelectorForm
|
||||
from forms.themeform import ThemeForm
|
||||
from distribusikan.distribusi_selector import selector_visible
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from distribusikan.upload import upload_new_distribusi, upload_updates_files
|
||||
from distribusikan.forms.distribusiform import DistribusiForm
|
||||
from distribusikan.forms.publicthemeform import PublicThemeForm
|
||||
from distribusikan.forms.selectorform import SelectorForm
|
||||
from distribusikan.forms.themeform import ThemeForm
|
||||
|
||||
# UserPengguna
|
||||
from statuspengguna.helper import UserHelper
|
||||
|
||||
|
||||
def UploadPage():
|
||||
def upload_page():
|
||||
"render upload page section of distribusi workflow"
|
||||
uploadfolder = APP.config["UPLOAD_FOLDER"]
|
||||
distribusiform = DistribusiForm()
|
||||
themeform = ThemeForm()
|
||||
publicthemeform = PublicThemeForm()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes()
|
||||
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes()
|
||||
selectorform = SelectorForm()
|
||||
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames()
|
||||
selectorvisible = SelectorVisible()
|
||||
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames()
|
||||
selectorvisible = selector_visible()
|
||||
|
||||
current_distribusi = UserHelper.current_distribusi()
|
||||
if current_distribusi == "new" or UserHelper.has_distribusi() is False:
|
||||
uploadform = UploadNewDistribusi(uploadfolder)
|
||||
uploadform = upload_new_distribusi(uploadfolder)
|
||||
else:
|
||||
uploadform = UploadUpdatedFiles(uploadfolder)
|
||||
uploadform = upload_updates_files(uploadfolder)
|
||||
|
||||
files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data)
|
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi)
|
@ -3,9 +3,10 @@ from __future__ import with_statement
|
||||
import logging
|
||||
from logging.config import fileConfig
|
||||
|
||||
from alembic import context
|
||||
from flask import current_app
|
||||
|
||||
from alembic import context
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
@ -7,11 +7,12 @@ class DistribusiFiles(db.Model):
|
||||
__tablename__ = "distribusi_files"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
type = db.Column(db.String(300), nullable=False, unique=True)
|
||||
type = db.Column(db.String(100), nullable=True, unique=False)
|
||||
distribusi = db.Column(db.Integer, db.ForeignKey("distribusis.id"))
|
||||
path = db.Column(db.String(4096), nullable=True, unique=False)
|
||||
description = db.Column(db.String(9), nullable=True, unique=False)
|
||||
path = db.Column(db.String(4096), nullable=True, unique=True)
|
||||
alttext = db.Column(db.String(255), nullable=True, unique=False)
|
||||
tags = db.Column(db.String(500), nullable=True, unique=False)
|
||||
description = db.Column(db.String(4096), nullable=True, unique=False)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Distribusi_File %r>" % self.distribusiname
|
||||
return "<Distribusi_File %r>" % self.path
|
||||
|
@ -11,6 +11,7 @@ class Distribusis(db.Model):
|
||||
userid = db.Column(db.Integer, db.ForeignKey("users.id"))
|
||||
category = db.Column(db.String(500), nullable=True, unique=False)
|
||||
year = db.Column(db.String(9), nullable=True, unique=False)
|
||||
description = db.Column(db.String(32000), nullable=True, unique=False)
|
||||
tags = db.Column(db.String(500), nullable=True, unique=False)
|
||||
publictheme = db.Column(db.String(300), unique=True, nullable=True)
|
||||
visible = db.Column(db.Boolean, default=False)
|
||||
|
11
verse/search/forms/searchform.py
Normal file
@ -0,0 +1,11 @@
|
||||
"""SearchForm to search files and distribusis in the distribusi archive"""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, validators
|
||||
from wtforms.validators import Length
|
||||
from wtforms.widgets import TextArea
|
||||
|
||||
|
||||
class SearchForm(FlaskForm):
|
||||
searchfield = StringField("Search distribusi-verse archive")
|
||||
submit = SubmitField("Search")
|
42
verse/search/search.py
Normal file
@ -0,0 +1,42 @@
|
||||
import os
|
||||
from flask import Blueprint, render_template
|
||||
from whoosh.fields import *
|
||||
from whoosh.index import open_dir
|
||||
from whoosh.qparser import QueryParser
|
||||
from search.forms.searchform import SearchForm
|
||||
|
||||
searchpages = Blueprint(
|
||||
"search",
|
||||
__name__,
|
||||
template_folder="templates/search",
|
||||
static_folder="static",
|
||||
)
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(__file__)
|
||||
SEARCH_DATA_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "searchdata"))
|
||||
|
||||
|
||||
@searchpages.route("/", methods=["GET", "POST"])
|
||||
def searchpage():
|
||||
searchform = SearchForm()
|
||||
found_distribusis = []
|
||||
if searchform.validate_on_submit():
|
||||
found_distribusis = search(searchform.searchfield.data)
|
||||
template = render_template(
|
||||
"search.html",
|
||||
searchform=searchform,
|
||||
found_distribusis=found_distribusis,
|
||||
)
|
||||
return template
|
||||
|
||||
|
||||
def search(searchinput):
|
||||
"""search and get search result titles and return them as distribusi ids"""
|
||||
ix = open_dir(SEARCH_DATA_DIR)
|
||||
with ix.searcher() as searcher:
|
||||
query = QueryParser("content", ix.schema).parse(searchinput)
|
||||
search_results = searcher.search(query)
|
||||
found_distribusis = []
|
||||
for result in search_results:
|
||||
found_distribusis.append(result["title"])
|
||||
return found_distribusis
|
52
verse/search/search_index.py
Normal file
@ -0,0 +1,52 @@
|
||||
import os
|
||||
from whoosh.fields import *
|
||||
from whoosh.index import create_in
|
||||
from whoosh.qparser import QueryParser
|
||||
from models.distribusi_model import Distribusis
|
||||
import flask_apscheduler
|
||||
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(__file__)
|
||||
SEARCH_DATA_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "searchdata"))
|
||||
|
||||
|
||||
def init_search_index(APP):
|
||||
scheduler = flask_apscheduler.APScheduler()
|
||||
scheduler.api_enabled = False
|
||||
scheduler.init_app(APP)
|
||||
scheduler.start()
|
||||
index_distribusis(APP)
|
||||
index_distribusi_files(APP)
|
||||
|
||||
@scheduler.task("interval", id="update", minutes=60)
|
||||
def update_search_index():
|
||||
index_distribusis(APP)
|
||||
index_distribusi_files(APP)
|
||||
|
||||
|
||||
def index_distribusis(APP):
|
||||
schema = Schema(
|
||||
title=TEXT(stored=True), path=ID(stored=True), content=TEXT
|
||||
)
|
||||
ix = create_in(SEARCH_DATA_DIR, schema)
|
||||
writer = ix.writer()
|
||||
distribusis = _visible_distribusis(APP)
|
||||
for distribusi in distribusis:
|
||||
writer.add_document(
|
||||
title=distribusi.distribusiname,
|
||||
path="/a",
|
||||
content=distribusi.description,
|
||||
)
|
||||
writer.commit()
|
||||
|
||||
|
||||
def index_distribusi_files(APP):
|
||||
APP.logger.info("searching distribusi files not implemented yet.")
|
||||
|
||||
|
||||
def _visible_distribusis(APP):
|
||||
with APP.app_context():
|
||||
distribusis = Distribusis.query.filter(
|
||||
Distribusis.visible.isnot(False)
|
||||
).all()
|
||||
return distribusis
|
23
verse/search/templates/search/search.html
Normal file
@ -0,0 +1,23 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% block main %}
|
||||
<div id="distribusiverse" class="maincontent">
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ url_for('search.searchpage') }}">
|
||||
{{ searchform.csrf_token }}
|
||||
<fieldset class="required">
|
||||
{{ searchform.searchfield.label }}
|
||||
{{ searchform.searchfield }}
|
||||
{% for message in searchform.searchfield.errors %}
|
||||
<div class="error">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset class="button required">
|
||||
{{ searchform.submit }}
|
||||
</fieldset>
|
||||
</form>
|
||||
<div class="searchresults">
|
||||
{% for found_distribusi in found_distribusis %}
|
||||
<a href='{{ url_for('shortstashurl')}}/{{found_distribusi}}/index.html'>{{found_distribusi}}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,4 +1,7 @@
|
||||
title = "Varia Archive X Distribusi-Verse"
|
||||
categories = ["event","gathering","work session","workgroup","performance","music event"]
|
||||
categories = [ "article", "booklaunch", "broadcast", "curriculum", "game",
|
||||
"gathering", "lecture", "opencall", "party", "performance", "presentation",
|
||||
"publication", "report", "screening", "statement", "workgroup", "worksession",
|
||||
"workshop"]
|
||||
start_time = 2017-11-03
|
||||
end_time = 2025-12-31
|
||||
|
@ -11,31 +11,35 @@ from flask import (
|
||||
url_for,
|
||||
)
|
||||
from flask_login import current_user, login_required, logout_user
|
||||
from flask_mail import Mail
|
||||
from flask_wtf.csrf import CSRFError
|
||||
|
||||
# Interface! these are seperate files in main folder
|
||||
from adminpage import AdminPage
|
||||
from app import create_app, login_manager
|
||||
from admin import is_adminuser
|
||||
from admin_page.admin_page import admin_page
|
||||
from app import create_app, login_manager, db
|
||||
from describer.describe_files import describer
|
||||
from distribusikan.distribusikan import distribusikan
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
|
||||
# Use upload form to populate filters
|
||||
from forms.uploadform import UploadForm
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from distribusikan.forms.uploadform import UploadForm
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
from statuspengguna.forgotpassword import forgot_password
|
||||
from statuspengguna.helper import UserHelper
|
||||
from statuspengguna.loginuser import login_section
|
||||
from statuspengguna.registeruser import register_user
|
||||
from search.search import searchpages
|
||||
from search.search_index import init_search_index
|
||||
|
||||
APP = create_app()
|
||||
stash_page = Blueprint("stash_page", __name__, static_folder="stash")
|
||||
APP.register_blueprint(stash_page)
|
||||
APP.register_blueprint(describer, url_prefix="/describer")
|
||||
APP.register_blueprint(login_section, url_prefix="/login")
|
||||
APP.register_blueprint(register_user, url_prefix="/register")
|
||||
APP.register_blueprint(forgot_password, url_prefix="/login/forgotpassword")
|
||||
APP.register_blueprint(distribusikan)
|
||||
APP.register_blueprint(stash_page)
|
||||
APP.register_blueprint(admin_page, url_prefix="/admin")
|
||||
APP.register_blueprint(distribusikan, url_prefix="/distribusikan")
|
||||
APP.register_blueprint(searchpages, url_prefix="/search")
|
||||
init_search_index(APP)
|
||||
|
||||
|
||||
@APP.before_request
|
||||
@ -48,7 +52,7 @@ def session_handler():
|
||||
def index():
|
||||
UserHelper.reset_user_state()
|
||||
uploadform = UploadForm()
|
||||
distribusis = DistribusisInfo.visibledistribusis()
|
||||
distribusis = DistribusisInfo.visible_distribusis()
|
||||
distribusisindex = {}
|
||||
for distribusi in distribusis:
|
||||
user = User.query.filter_by(id=distribusi.userid).first()
|
||||
@ -60,9 +64,10 @@ def index():
|
||||
"tags": distribusi.tags.split(","),
|
||||
}
|
||||
distribusisindex[distribusi.distribusiname] = singledistribusi
|
||||
|
||||
years = uploadform.year.choices
|
||||
categories = uploadform.category.choices
|
||||
adminuser = isadminuser()
|
||||
adminuser = is_adminuser()
|
||||
template = render_template(
|
||||
"base/index.html",
|
||||
distribusisindex=distribusisindex,
|
||||
@ -91,14 +96,6 @@ def shortstashurl():
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@APP.route("/admin", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def admin():
|
||||
if not isadminuser():
|
||||
return redirect(url_for("index"))
|
||||
return AdminPage()
|
||||
|
||||
|
||||
@APP.route("/logout")
|
||||
@login_required
|
||||
def logout():
|
||||
@ -113,14 +110,7 @@ def handle_csrf_error(e):
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return User.query.get(int(user_id))
|
||||
|
||||
|
||||
def isadminuser():
|
||||
if not current_user.is_authenticated:
|
||||
return False
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
return user.admin
|
||||
return db.session.get(User, int(user_id))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -2,7 +2,7 @@
|
||||
/* for sorting on year and category
|
||||
*/
|
||||
button {
|
||||
background-color: #E0B0FF;
|
||||
background-color: #9de457;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
}
|
||||
@ -26,7 +26,7 @@ button {
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #E0B0FF;
|
||||
background-color: #9de457;
|
||||
min-width: 120px;
|
||||
border: 2px solid;
|
||||
z-index: 1;
|
||||
|
@ -4,7 +4,7 @@
|
||||
max-width: 20em;
|
||||
position: relative;
|
||||
border: none;
|
||||
background: #E0B0FF;
|
||||
background: #9de457;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@ -18,7 +18,7 @@
|
||||
max-width: 20em;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: #E0B0FF;
|
||||
background-color: #9de457;
|
||||
background-image: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
@ -41,7 +41,7 @@
|
||||
}
|
||||
select.selector option{
|
||||
color: white;
|
||||
background-color: #60337F;
|
||||
background-color: #9de457;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
@ -49,5 +49,5 @@ select.selector option{
|
||||
outline: none;
|
||||
}
|
||||
.selector-style select option:hover {
|
||||
background: #60337F;
|
||||
background: #9de457;
|
||||
}
|
||||
|
@ -3,63 +3,16 @@ body
|
||||
font-family: monospace, monospace;
|
||||
font-size: 15px;
|
||||
background-color: #fdfdfd;
|
||||
color:#29d148;
|
||||
color:#091411;
|
||||
word-wrap: break-word;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
div#login{
|
||||
width: 30%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-color:#fdfdfd;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div#login form {
|
||||
width: 24em;
|
||||
margin: 0 auto;
|
||||
padding-left: 15%;
|
||||
padding-right: 15%;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password], input[type=file] {
|
||||
color: #C397DF;
|
||||
width: 18em;
|
||||
max-width: 18em;
|
||||
background-color: #fdfdfd;
|
||||
border: 1px solid #E0B0FF;
|
||||
}
|
||||
|
||||
div#upload form {
|
||||
padding-right: 15%;
|
||||
}
|
||||
|
||||
.workflow{
|
||||
margin-top: 1em;
|
||||
padding: 0.5em;
|
||||
padding-left: auto;
|
||||
padding-right: auto;
|
||||
width: 31em;
|
||||
background-color:#fdfdfd;
|
||||
text-decoration: none;
|
||||
scroll-behavior: smooth;
|
||||
border-style: outset;
|
||||
}
|
||||
.workflow > p {
|
||||
padding-left: 1em;
|
||||
}
|
||||
.workflow > h2 {
|
||||
padding-left: 0.4em;;
|
||||
}
|
||||
|
||||
.workflow input{
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
#mainworkflow
|
||||
{
|
||||
width: 30em;
|
||||
width: 40em;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
@ -69,7 +22,16 @@ div#upload form {
|
||||
#distribusi-index {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.description > textarea {
|
||||
width: 100%;
|
||||
height: 10em;
|
||||
resize: none;
|
||||
}
|
||||
textarea#description {
|
||||
width: 100%;
|
||||
height: 20em;
|
||||
resize: none;
|
||||
}
|
||||
div#buttons{
|
||||
position: fixed;
|
||||
top: 0.5em;
|
||||
@ -82,13 +44,13 @@ div#buttons{
|
||||
|
||||
div#buttons .distribusi input{
|
||||
border: none;
|
||||
background: #fff600;
|
||||
background: #9de457;
|
||||
text-decoration: none;
|
||||
margin: 0.2em;
|
||||
}
|
||||
div#buttons .distribusi input:hover{
|
||||
background: #ffbf00;
|
||||
|
||||
background: #091411;
|
||||
color: #6df2cc;
|
||||
}
|
||||
fieldset.required {
|
||||
border: none;
|
||||
@ -101,21 +63,15 @@ fieldset.required > ul {
|
||||
fieldset.required > ul > li{
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
fieldset.tagfield > input {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
#publicthemes > ul {
|
||||
max-height: 20em;
|
||||
overflow: auto;
|
||||
}
|
||||
#publicthemes > ul > li{
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
input {
|
||||
border: none;
|
||||
background: #E0B0FF;
|
||||
background: #9de457;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@ -124,7 +80,9 @@ input {
|
||||
}
|
||||
|
||||
input:hover {
|
||||
background: #60337F;
|
||||
background: #091411;
|
||||
color: #6df2cc;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="submit"]:disabled:hover,
|
||||
@ -144,31 +102,11 @@ input[type="submit"]:disabled:focus {
|
||||
background-color: #F92020;
|
||||
}
|
||||
|
||||
#update {
|
||||
#update, #describe {
|
||||
color: black;
|
||||
background-color: #62b264;
|
||||
}
|
||||
|
||||
/* unvisited link */
|
||||
a:link {
|
||||
color: #fff600;
|
||||
}
|
||||
|
||||
/* visited link */
|
||||
a:visited {
|
||||
color: #d28cff;
|
||||
}
|
||||
|
||||
/* mouse over link */
|
||||
a:hover {
|
||||
color: #60337F;
|
||||
}
|
||||
|
||||
/* selected link */
|
||||
a:active {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* STOLEN GOODS */
|
||||
#fancyboi::before {
|
||||
content: "$ ";
|
||||
@ -189,7 +127,7 @@ a:active {
|
||||
white-space: nowrap;
|
||||
animation: reveal 4s linear;
|
||||
text-overflow: "█";
|
||||
background-color: #2D3039;
|
||||
background-color: #9de457;
|
||||
}
|
||||
#fancyboi::after {
|
||||
content: "█";
|
||||
@ -199,7 +137,7 @@ a:active {
|
||||
|
||||
div.maincontent{
|
||||
width: 55%;
|
||||
border: 3px #E0B0FF;
|
||||
border: 3px #9de457;
|
||||
margin-top: 0.5em;
|
||||
padding: 0.5em;
|
||||
border-style: outset;
|
||||
@ -238,8 +176,6 @@ div.maincontent{
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
margin-left: -60px;
|
||||
|
||||
/* Fade in tooltip - takes 1 second to go from 0% to 100% opac: */
|
||||
opacity: 0;
|
||||
transition: opacity 2s;
|
||||
}
|
||||
@ -254,7 +190,7 @@ div.maincontent{
|
||||
color: black;
|
||||
padding: 1em;
|
||||
box-sizing: border-box;
|
||||
background: #E0B0FF;
|
||||
background: #9de457;
|
||||
outline: none;
|
||||
font-family: Courier, sans-serif;
|
||||
font-size: 16px;
|
||||
@ -262,11 +198,11 @@ div.maincontent{
|
||||
/*
|
||||
Project colors so far.
|
||||
light
|
||||
#E0B0FF
|
||||
#9de457
|
||||
medium
|
||||
#d28cff
|
||||
dark
|
||||
#60337F
|
||||
#9de457
|
||||
|
||||
background dark
|
||||
#2D3039
|
||||
|
@ -11,7 +11,7 @@ from sqlalchemy.exc import (
|
||||
)
|
||||
|
||||
from app import db, get_app
|
||||
from forms.forgotpasswordform import ForgotPasswordForm
|
||||
from statuspengguna.forms.forgotpasswordform import ForgotPasswordForm
|
||||
from models.user_model import User
|
||||
|
||||
mail = Mail(get_app())
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import PasswordField, StringField, SubmitField, validators
|
||||
from wtforms.validators import Email, EqualTo, Length, ValidationError
|
||||
from wtforms.validators import Email, EqualTo, Length
|
||||
|
||||
|
||||
class RegisterForm(FlaskForm):
|
@ -10,7 +10,7 @@ from sqlalchemy.exc import (
|
||||
)
|
||||
|
||||
from app import db
|
||||
from distribusikan.distribusisinfo import DistribusisInfo
|
||||
from distribusikan.distribusis_info import DistribusisInfo
|
||||
from models.distribusi_model import Distribusis
|
||||
from models.user_model import User
|
||||
|
||||
@ -76,7 +76,9 @@ class UserHelper:
|
||||
|
||||
def distribusi_limit_reached():
|
||||
user = User.query.filter_by(email=current_user.email).first()
|
||||
distribusiamount = len(DistribusisInfo.getuserdistribusis(user.email))
|
||||
distribusiamount = len(
|
||||
DistribusisInfo.get_user_distribusis(user.email)
|
||||
)
|
||||
if distribusiamount > 19:
|
||||
print("user already has 20 distribusis")
|
||||
return True
|
||||
|
@ -5,14 +5,12 @@ from flask import (
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
send_from_directory,
|
||||
session,
|
||||
url_for,
|
||||
)
|
||||
from flask_bcrypt import check_password_hash
|
||||
from flask_login import login_user
|
||||
|
||||
from forms.loginform import LoginForm
|
||||
from statuspengguna.forms.loginform import LoginForm
|
||||
from models.user_model import User
|
||||
|
||||
login_section = Blueprint(
|
||||
@ -37,7 +35,6 @@ def LoginUser():
|
||||
loginform.password.errors.append("Invalid email or password!")
|
||||
return render_template("login.html", loginform=loginform)
|
||||
if check_password_hash(user.password, loginform.password.data):
|
||||
print(type(user))
|
||||
login_user(user)
|
||||
flash("Logged in successfully.", "success")
|
||||
next = request.args.get("next")
|
||||
|
@ -11,7 +11,7 @@ from sqlalchemy.exc import (
|
||||
from werkzeug.routing import BuildError
|
||||
|
||||
from app import db
|
||||
from forms.registerform import RegisterForm
|
||||
from statuspengguna.forms.registerform import RegisterForm
|
||||
from models.user_model import User
|
||||
|
||||
register_user = Blueprint(
|
||||
|
@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
|
||||
from flask import flash, redirect, render_template, url_for
|
||||
from flask import Blueprint, flash, redirect, render_template, url_for
|
||||
from flask_bcrypt import generate_password_hash
|
||||
from flask_login import login_user
|
||||
from sqlalchemy.exc import (
|
||||
@ -13,9 +13,8 @@ from sqlalchemy.exc import (
|
||||
from werkzeug.routing import BuildError
|
||||
|
||||
from app import db
|
||||
from forms.resetpasswordform import ResetPasswordForm
|
||||
from statuspengguna.forms.resetpasswordform import ResetPasswordForm
|
||||
from models.user_model import User
|
||||
from statuspengguna import statuspengguna
|
||||
|
||||
reset_password = Blueprint(
|
||||
"reset_password",
|
||||
|
@ -1,69 +0,0 @@
|
||||
/* Dropdown Button */
|
||||
/* for sorting on year and category
|
||||
*/
|
||||
button {
|
||||
background-color: #E0B0FF;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
}
|
||||
.filter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.activebtn {
|
||||
background-color: #62b264;
|
||||
}
|
||||
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Dropdown Content (Hidden by Default) */
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #E0B0FF;
|
||||
min-width: 120px;
|
||||
border: 2px solid;
|
||||
z-index: 1;
|
||||
border-style: outset;
|
||||
}
|
||||
|
||||
/* Links inside the dropdown */
|
||||
.dropdown-content button {
|
||||
color: black;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
min-width: inherit;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
.dropbtn {
|
||||
margin-top: 1em;
|
||||
}
|
||||
/* Change color of dropdown links on hover */
|
||||
.dropdown-content button:hover {background-color: #62b264;}
|
||||
|
||||
|
||||
/* Show the dropdown menu on hover */
|
||||
.dropdown:hover .dropdown-content {display: block;}
|
||||
|
||||
/* Change the background color of the dropdown button when the dropdown content is shown */
|
||||
.dropdown:hover .dropbtn {background-color: #62b264;}
|
||||
|
||||
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
|
||||
.dropdown-content button {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
.container > button {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
.dropdown > button {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
.editareas {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.editarea {
|
||||
width: 30%;
|
||||
border: 3px solid #E0B0FF;
|
||||
border-style: outset;
|
||||
margin-right: 1em;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.editor {
|
||||
min-width: 35%;
|
||||
}
|
||||
.editform {
|
||||
width: 100%%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#editorsubmitform {
|
||||
padding-top: 1em;
|
||||
}
|
||||
.required label {
|
||||
display: block;
|
||||
padding-bottom: 2px;
|
||||
width: 100%
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 250px;
|
||||
background: #E0B0FF;
|
||||
outline: none;
|
||||
font-family: Courier, sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
iframe {
|
||||
bottom: 0;
|
||||
position: relative;
|
||||
margin-top: 1em;
|
||||
width: 100%;
|
||||
height: 30em;
|
||||
}
|
||||
#html {
|
||||
background-color: #60337F;
|
||||
color: lightgrey;
|
||||
}
|
22
verse/statuspengguna/static/css/login.css
Normal file
@ -0,0 +1,22 @@
|
||||
div#login{
|
||||
width: 30%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-color:#fdfdfd;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div#login form {
|
||||
width: 24em;
|
||||
margin: 0 auto;
|
||||
padding-left: 15%;
|
||||
padding-right: 15%;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password], input[type=file] {
|
||||
color: #091411;
|
||||
width: 18em;
|
||||
max-width: 18em;
|
||||
background-color: #fdfdfd;
|
||||
border: 1px solid #9de457;
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
.selector-style {
|
||||
padding: 0;
|
||||
width: 20em;
|
||||
max-width: 20em;
|
||||
position: relative;
|
||||
border: none;
|
||||
background: #E0B0FF;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
.selector-style select {
|
||||
padding: 0.2em 0.2em;
|
||||
width: 20em;
|
||||
max-width: 20em;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: #E0B0FF;
|
||||
background-image: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.selector-style:after {
|
||||
top: 50%;
|
||||
left: 95%;
|
||||
border: solid;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
border-top-color: #000000;
|
||||
margin-top: -2px;
|
||||
z-index: 100;
|
||||
}
|
||||
select.selector option{
|
||||
color: white;
|
||||
background-color: #60337F;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.selector-style select:focus {
|
||||
outline: none;
|
||||
}
|
||||
.selector-style select option:hover {
|
||||
background: #60337F;
|
||||
}
|
@ -1,281 +0,0 @@
|
||||
body
|
||||
{
|
||||
font-family: monospace, monospace;
|
||||
font-size: 15px;
|
||||
background-color: #fdfdfd;
|
||||
color:#29d148;
|
||||
word-wrap: break-word;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
div#login{
|
||||
width: 30%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-color:#fdfdfd;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div#login form {
|
||||
width: 24em;
|
||||
margin: 0 auto;
|
||||
padding-left: 15%;
|
||||
padding-right: 15%;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password], input[type=file] {
|
||||
color: #C397DF;
|
||||
width: 18em;
|
||||
max-width: 18em;
|
||||
background-color: #fdfdfd;
|
||||
border: 1px solid #E0B0FF;
|
||||
}
|
||||
|
||||
div#upload form {
|
||||
padding-right: 15%;
|
||||
}
|
||||
|
||||
.workflow{
|
||||
margin-top: 1em;
|
||||
padding: 0.5em;
|
||||
padding-left: auto;
|
||||
padding-right: auto;
|
||||
width: 31em;
|
||||
background-color:#fdfdfd;
|
||||
text-decoration: none;
|
||||
scroll-behavior: smooth;
|
||||
border-style: outset;
|
||||
}
|
||||
.workflow > p {
|
||||
padding-left: 1em;
|
||||
}
|
||||
.workflow > h2 {
|
||||
padding-left: 0.4em;;
|
||||
}
|
||||
|
||||
.workflow input{
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
#mainworkflow
|
||||
{
|
||||
width: 30em;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
#distribusiverse {
|
||||
margin-bottom: 11em;
|
||||
}
|
||||
#distribusi-index {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
div#buttons{
|
||||
position: fixed;
|
||||
top: 0.5em;
|
||||
right: 0.5em;
|
||||
display:flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div#buttons .distribusi input{
|
||||
border: none;
|
||||
background: #fff600;
|
||||
text-decoration: none;
|
||||
margin: 0.2em;
|
||||
}
|
||||
div#buttons .distribusi input:hover{
|
||||
background: #ffbf00;
|
||||
|
||||
}
|
||||
fieldset.required {
|
||||
border: none;
|
||||
}
|
||||
|
||||
fieldset.required > ul {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
fieldset.required > ul > li{
|
||||
list-style-type: none;
|
||||
}
|
||||
fieldset.tagfield > input {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
#publicthemes > ul {
|
||||
max-height: 20em;
|
||||
overflow: auto;
|
||||
}
|
||||
#publicthemes > ul > li{
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
input {
|
||||
border: none;
|
||||
background: #E0B0FF;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
margin: 0.2em;
|
||||
}
|
||||
|
||||
input:hover {
|
||||
background: #60337F;
|
||||
}
|
||||
|
||||
input[type="submit"]:disabled:hover,
|
||||
input[type="submit"]:disabled,
|
||||
input[type="submit"]:disabled:focus {
|
||||
background-color: #2D3039;
|
||||
color: #d28cff;
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: 110%;
|
||||
color: #F92020;
|
||||
}
|
||||
|
||||
#delete {
|
||||
color: black;
|
||||
background-color: #F92020;
|
||||
}
|
||||
|
||||
#update {
|
||||
color: black;
|
||||
background-color: #62b264;
|
||||
}
|
||||
|
||||
|
||||
/* unvisited link */
|
||||
a:link {
|
||||
color: #fff600;
|
||||
}
|
||||
|
||||
/* visited link */
|
||||
a:visited {
|
||||
color: #d28cff;
|
||||
}
|
||||
|
||||
/* mouse over link */
|
||||
a:hover {
|
||||
color: #60337F;
|
||||
}
|
||||
|
||||
/* selected link */
|
||||
a:active {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* STOLEN GOODS */
|
||||
#fancyboi::before {
|
||||
content: "$ ";
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
@keyframes flash {
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
@keyframes reveal {
|
||||
from { width: 2em; } /* Width of ::before */
|
||||
to { width: 55%; }
|
||||
}
|
||||
#fancyboi {
|
||||
width: 55%;
|
||||
padding: 0.5em;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
animation: reveal 4s linear;
|
||||
text-overflow: "█";
|
||||
background-color: #2D3039;
|
||||
}
|
||||
#fancyboi::after {
|
||||
content: "█";
|
||||
animation: flash 0.5s step-end infinite;
|
||||
}
|
||||
}
|
||||
|
||||
div.maincontent{
|
||||
width: 55%;
|
||||
border: 3px #E0B0FF;
|
||||
margin-top: 0.5em;
|
||||
padding: 0.5em;
|
||||
border-style: outset;
|
||||
}
|
||||
|
||||
.tags{
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
text-align: center;
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
.searched {
|
||||
background: #fff600 !important;
|
||||
color: black !important;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border-bottom: 1px dotted black;
|
||||
}
|
||||
|
||||
.tooltip .tooltiptext {
|
||||
visibility: hidden;
|
||||
width: 120px;
|
||||
background-color: black;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
margin-left: -60px;
|
||||
|
||||
/* Fade in tooltip - takes 1 second to go from 0% to 100% opac: */
|
||||
opacity: 0;
|
||||
transition: opacity 2s;
|
||||
}
|
||||
|
||||
.tooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.code-example {
|
||||
width: 100%;
|
||||
color: black;
|
||||
padding: 1em;
|
||||
box-sizing: border-box;
|
||||
background: #E0B0FF;
|
||||
outline: none;
|
||||
font-family: Courier, sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
/*
|
||||
Project colors so far.
|
||||
light
|
||||
#E0B0FF
|
||||
medium
|
||||
#d28cff
|
||||
dark
|
||||
#60337F
|
||||
|
||||
background dark
|
||||
#2D3039
|
||||
|
||||
yellow important
|
||||
#fff600
|
||||
|
||||
red: danger
|
||||
ff5a5a
|
||||
backgrounds
|
||||
*/
|
@ -1,6 +0,0 @@
|
||||
This favicon was generated using the following font:
|
||||
|
||||
- Font Title: Klee One
|
||||
- Font Author: Copyright 2020 The Klee Project Authors (https://github.com/fontworks-fonts/Klee)
|
||||
- Font Source: http://fonts.gstatic.com/s/kleeone/v5/LDIxapCLNRc6A8oT4q4AOeekWPrP.ttf
|
||||
- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL))
|
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 322 B |
Before Width: | Height: | Size: 666 B |
Before Width: | Height: | Size: 15 KiB |
@ -1 +0,0 @@
|
||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
@ -1,92 +0,0 @@
|
||||
filterSelection("all", "None");
|
||||
function filterSelection(c, name, id) {
|
||||
resetDropDownButtons();
|
||||
var i;
|
||||
var button = document.getElementById(id);
|
||||
if(button){
|
||||
button.innerText = name;
|
||||
addClass(button, "activebtn");
|
||||
}
|
||||
var alldistribusis = document.getElementsByClassName("filter");
|
||||
if (c == "all") {
|
||||
for (i = 0; i < alldistribusis.length; i++) {
|
||||
addClass(alldistribusis[i], "show");
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < alldistribusis.length; i++) {
|
||||
removeClass(alldistribusis[i], "show");
|
||||
if (alldistribusis[i].className.indexOf(c) > -1) {
|
||||
addClass(alldistribusis[i], "show");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetDropDownButtons(){
|
||||
document.getElementById("Year").innerText = "Year";
|
||||
document.getElementById("Category").innerText = "Category";
|
||||
allactivebuttons = document.getElementsByClassName("activebtn");
|
||||
for(var i = 0;allactivebuttons.length; i++) {
|
||||
removeClass(allactivebuttons[i], "activebtn");
|
||||
}
|
||||
}
|
||||
function addClass(element, name) {
|
||||
var i, arr1, arr2;
|
||||
arr1 = element.className.split(" ");
|
||||
arr2 = name.split(" ");
|
||||
for (i = 0; i < arr2.length; i++) {
|
||||
if (arr1.indexOf(arr2[i]) == -1) {element.className += " " + arr2[i];}
|
||||
}
|
||||
}
|
||||
|
||||
function removeClass(element, name) {
|
||||
var i, arr1, arr2;
|
||||
arr1 = element.className.split(" ");
|
||||
arr2 = name.split(" ");
|
||||
for (i = 0; i < arr2.length; i++) {
|
||||
while (arr1.indexOf(arr2[i]) > -1) {
|
||||
arr1.splice(arr1.indexOf(arr2[i]), 1);
|
||||
}
|
||||
}
|
||||
element.className = arr1.join(" ");
|
||||
}
|
||||
|
||||
|
||||
let searchInput = document.getElementById('tagsearch');
|
||||
let timeout = null;
|
||||
// Listen for keystroke events
|
||||
searchInput.addEventListener('keyup', function (e) {
|
||||
// Clear the timeout if it has already been set.
|
||||
clearTimeout(timeout);
|
||||
// Make a new timeout set to go off in 1000ms (1 second)
|
||||
timeout = setTimeout(function () {
|
||||
console.log('Input Value:', searchInput.value);
|
||||
if (searchInput.value.length > 2) {
|
||||
searchTags(searchInput.value);
|
||||
} else {
|
||||
clearSearchTags();
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
function searchTags(searchInput) {
|
||||
let tag_ele = document.getElementsByClassName('tags');
|
||||
for (var i = 0; i < tag_ele.length; ++i) {
|
||||
let searchText = searchInput.toLowerCase().trim();
|
||||
let tagtext = tag_ele[i].innerText.toLowerCase();
|
||||
if(searchText.includes(tagtext) || tagtext.includes(searchText)) {
|
||||
addClass(tag_ele[i], "searched");
|
||||
}
|
||||
else {
|
||||
removeClass(tag_ele[i], "searched");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearSearchTags() {
|
||||
let tag_ele = document.getElementsByClassName('tags');
|
||||
for (var i = 0; i < tag_ele.length; ++i) {
|
||||
removeClass(tag_ele[i], "searched");
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
function update() {
|
||||
|
||||
var html = document.getElementById("html");
|
||||
var css = document.getElementById("css");
|
||||
var code = document.getElementById("code").contentWindow.document;
|
||||
|
||||
document.body.onkeyup = function(){
|
||||
code.open();
|
||||
code.writeln(html.value+"<style>"+css.value+"</style>");
|
||||
code.close();
|
||||
};
|
||||
document.addEventListener("DOMContentLoaded", function(){
|
||||
code.open();
|
||||
code.writeln(html.value+"<style>"+css.value+"</style>");
|
||||
code.close();
|
||||
});
|
||||
};
|
||||
|
||||
update();
|
@ -1,25 +0,0 @@
|
||||
console.log("everything is still smooth")
|
||||
|
||||
function scrollToTheme() {
|
||||
var uploadsuccessful = document.getElementById("uploadsuccessful");
|
||||
if(uploadsuccessful){
|
||||
const theme = document.getElementById('theme')
|
||||
theme.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToLaunch() {
|
||||
var cssSelected = document.getElementById("cssSelected");
|
||||
if(cssSelected){
|
||||
const launch = document.getElementById('launch')
|
||||
launch.scrollIntoView({ behavior: 'smooth', block: 'end' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", scrollToTheme);
|
||||
document.addEventListener("DOMContentLoaded", scrollToLaunch);
|
||||
|
||||
// function(e) {
|
||||
// (e.keyCode === 13 || e.keyCode === 32) && $(this).trigger("click")
|
||||
// }
|
@ -1,75 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="240"
|
||||
height="320"
|
||||
viewBox="0 0 63.5 84.666667"
|
||||
version="1.1"
|
||||
id="svgArrowOne"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||
sodipodi:docname="arrow_1.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="236"
|
||||
inkscape:cy="70"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="1366"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<circle
|
||||
id="path865"
|
||||
style="fill:#060000;stroke:#fcfffe;stroke-width:0.264583"
|
||||
cx="167.50412"
|
||||
cy="23.866825"
|
||||
r="0.211455" />
|
||||
<circle
|
||||
id="path867"
|
||||
style="fill:#e0b0ff;stroke:#fcfffe;stroke-width:0.264583;fill-opacity:1"
|
||||
cx="167.50412"
|
||||
cy="23.866825"
|
||||
r="0.211455" />
|
||||
<circle
|
||||
id="path2716"
|
||||
style="fill:#d28cff;stroke:#fcfffe;stroke-width:0.264583"
|
||||
cx="31.623327"
|
||||
cy="-54.739456"
|
||||
r="0.1057275" />
|
||||
<circle
|
||||
id="path2718"
|
||||
style="fill:#d28cff;stroke:#fcfffe;stroke-width:0.264583"
|
||||
cx="31.623327"
|
||||
cy="-54.739456"
|
||||
r="0.1057275" />
|
||||
<path
|
||||
style="fill:#d28cff;fill-opacity:1;stroke:none;stroke-width:0.799999"
|
||||
id="path2732"
|
||||
d="m 19.948434,3.1817159 c 1.290131,0.6550689 2.512225,1.4411814 3.755485,2.1807733 1.793529,1.0335667 3.565214,2.1021852 5.308482,3.2186226 0.483624,0.3097273 0.976024,0.6070071 1.443413,0.9407313 0.457224,0.3264641 0.885243,0.6920049 1.327862,1.0380079 2.123546,1.795334 3.693565,4.041838 4.640125,6.658655 0.242448,0.67026 0.417224,1.3631 0.625834,2.04465 0.468096,1.928539 0.850726,3.889399 1.025174,5.869019 0.146409,1.661472 0.09044,3.337613 0.06891,5.002416 -0.136327,2.53704 -0.886677,4.958631 -1.507659,7.401952 -0.562415,2.08257 -2.195008,3.525988 -3.642546,5.02172 -1.668862,1.796187 -3.430227,3.511629 -4.96204,5.428684 -1.232474,1.501685 -2.187443,3.200289 -3.147382,4.881737 -1.04435,1.719871 -1.86704,3.57665 -2.548164,5.467477 -0.710967,2.173634 -0.907385,4.460639 -1.024063,6.730664 0.02091,1.346742 0.05687,2.707192 0.493364,3.995719 0.26353,0.777933 0.396191,0.938664 0.795115,1.653278 0.654367,1.054661 1.365786,2.066507 2.102377,3.064017 0,0 3.841737,-0.248322 3.841737,-0.248322 v 0 c -0.75511,-0.983935 -1.542788,-1.939549 -2.17802,-3.011543 -0.382704,-0.652497 -0.537692,-0.849823 -0.799641,-1.562883 -0.455204,-1.239128 -0.493109,-2.567154 -0.52219,-3.871724 0.107265,-2.234121 0.278343,-4.485997 1.012129,-6.617327 0.708365,-1.865136 1.556754,-3.687384 2.575162,-5.404406 0.953056,-1.662009 1.928715,-3.32604 3.127534,-4.825259 1.51579,-1.902804 3.233504,-3.631578 4.905512,-5.395754 1.510255,-1.536197 3.212571,-3.04624 3.747334,-5.218498 0.540033,-2.47709 1.199993,-4.93743 1.330515,-7.483557 0.02558,-1.263529 0.06192,-2.073423 0.0096,-3.332359 C 41.644752,24.222411 41.147902,21.675409 40.546318,19.16389 40.076453,17.470971 39.976922,16.848842 39.271149,15.277213 38.380408,13.293695 37.001362,11.650365 35.365848,10.236089 34.920391,9.8793346 34.491789,9.5004423 34.02947,9.1658256 33.563896,8.8288536 33.065526,8.5396762 32.585453,8.223701 30.879732,7.1010218 29.144655,6.0327407 27.391958,4.9847267 26.212505,4.238663 25.04853,3.4635151 23.848505,2.7523961 c 0,0 -3.900058,0.4293198 -3.900058,0.4293198 z" />
|
||||
<path
|
||||
style="fill:#d28cff;fill-opacity:1;stroke:none;stroke-width:0.799999"
|
||||
id="path2736"
|
||||
d="m 17.143337,69.050471 c 1.633713,0.894598 3.185906,1.900385 4.678149,3.014075 1.115423,0.934426 2.160169,1.94547 3.113059,3.044203 1.826876,2.397014 -1.146831,1.665475 4.779041,1.263248 0.383141,-1.686153 0.758291,-3.374861 1.165924,-5.055598 0.206131,-0.876517 0.390895,-1.75066 0.653066,-2.611993 0,0 -3.799028,-0.103103 -3.799028,-0.103103 v 0 c -0.220279,0.87104 -0.384717,1.750875 -0.582906,2.627255 -0.396558,1.670132 -0.773763,3.348908 -1.349638,4.968864 1.273906,0.05246 2.548034,0.09977 3.821714,0.157393 0.02885,0.0013 -0.07003,0.03579 -0.08584,0.01161 -0.06107,-0.09337 -0.07566,-0.209923 -0.112684,-0.315174 -0.133537,-0.379648 -0.146335,-0.493044 -0.361696,-0.837912 -0.08452,-0.135356 -0.188793,-0.257328 -0.283188,-0.385993 -1.017286,-1.099923 -2.077482,-2.15043 -3.232635,-3.10924 -1.452916,-1.095015 -2.937697,-2.134709 -4.528692,-3.02179 0,0 -3.87465,0.354142 -3.87465,0.354142 z" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.9 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="240" height="320" version="1.1" viewBox="0 0 63.5 84.667" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="167.5" cy="23.867" r=".21146" fill="#060000" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<circle cx="167.5" cy="23.867" r=".21146" fill="#e0b0ff" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<g fill="#d28cff">
|
||||
<circle cx="31.623" cy="-54.739" r=".10573" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<circle cx="31.623" cy="-54.739" r=".10573" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<path d="m29.598 1.3629c0.29231 0.93057 0.37445 1.9094 0.44145 2.8774 0.01955 0.99076 0.29893 1.9483 0.43855 2.9253 0.04901 1.1628 0.31687 2.2714 0.7734 3.3386 0.60807 1.244 1.6241 2.1846 2.6231 3.1104 0.76132 0.7147 1.5224 1.4053 2.414 1.9528 0.85013 0.49091 1.8227 0.71794 2.7627 0.97569 1.4036 0.22312 2.1015 0.68412 3.1203 1.648 1.1101 1.0733 1.7779 2.4463 2.4311 3.8184 0.5827 1.142 0.76303 2.3828 0.73638 3.6503-0.08765 1.5129-0.67764 2.6923-1.5432 3.8976-0.84272 1.225-2.1589 1.8621-3.4214 2.5577-1.3039 0.74177-2.5458 1.586-3.8965 2.2408-1.5184 0.78493-3.077 1.4779-4.6378 2.1709-1.2968 0.70155-2.6371 1.3714-3.7845 2.3055-1.5755 1.3431-2.9301 2.8922-4.2407 4.4866-1.0773 1.3646-2.2517 2.7443-2.9262 4.3683-0.12219 0.2942-0.20988 0.60157-0.31482 0.90236-0.3176 1.1367-0.50828 2.2967-0.36852 3.4764 0.04693 0.39614 0.19687 1.057 0.27962 1.4461 0.30758 1.2289 0.84547 2.3725 1.4798 3.4625 0.70009 1.3121 1.6509 2.4545 2.6734 3.5243 1.0661 1.0736 2.1636 2.1225 3.154 3.2675 0.78168 0.87789 1.0179 1.9433 1.1372 3.0756 0.03544 0.92388 0.11577 1.8587 0.07073 2.7841-0.01773 0.36408-0.1093 0.87867-0.16701 1.2409-0.09034 1.015-0.40258 1.9744-0.65202 2.9542-0.22907 0.93923-0.24592 1.9133-0.26994 2.875 0.01627 0.16165 0.03253 0.3233 0.04879 0.48495 0 0 3.8677-0.04599 3.8677-0.04599l-0.06033-0.42856c0.0271-0.93446 0.05799-1.8763 0.28398-2.7884 0.25461-0.98959 0.52171-1.9723 0.61567-2.9949 0.18691-1.3678 0.16751-2.7404 0.09837-4.1178-0.10464-1.2084-0.33697-2.37-1.1681-3.3092-0.98696-1.161-2.0984-2.2119-3.1752-3.2885-1.0093-1.0344-1.9609-2.1448-2.6312-3.4346-0.61359-1.0586-1.166-2.1573-1.4984-3.3403-0.02657-0.1263-0.26629-1.2542-0.28656-1.3963-0.16054-1.1256 0.0079-2.2354 0.32978-3.3186 0.10325-0.28669 0.1907-0.57958 0.30976-0.86007 0.67556-1.5915 1.8191-2.9377 2.8755-4.2834 1.3254-1.6128 2.6979-3.0863 4.332-4.3948 1.1702-0.86077 2.4531-1.5682 3.751-2.2163 1.5673-0.6912 3.1104-1.4304 4.6479-2.1857 1.3437-0.6747 2.5823-1.5317 3.8988-2.2576 1.3084-0.71914 2.6043-1.447 3.4487-2.7293 0.89598-1.305 1.4437-2.5132 1.5458-4.1199 0.04656-1.326-0.09489-2.646-0.72638-3.8363-0.70909-1.3836-1.3422-2.8175-2.4524-3.9439-0.95909-0.99062-1.6743-1.6678-3.0935-1.8533-0.92413-0.22693-1.8609-0.47835-2.7296-0.86415-0.37733-0.23195-0.7701-0.43303-1.1225-0.70362-0.56026-0.43018-0.30161-0.27292-0.85155-0.76539-0.15495-0.13876-0.31951-0.26638-0.47927-0.39957-0.94654-0.91944-2.0219-1.7437-2.6195-2.9576-0.46026-1.0278-0.6805-2.1099-0.72907-3.2345-0.13163-0.97099-0.41801-1.9171-0.4545-2.8972-0.062288-0.99479-0.16352-1.9871-0.37122-2.9636l-3.9178 0.11147z"/>
|
||||
<path d="m22.025 71.064c1.1076 0.81571 1.8963 1.9751 2.6453 3.1096 0.63322 0.93788 1.2476 1.8855 1.6118 2.9617 0.28693 0.82149 0.62284 1.6252 1.0669 2.3743 1.0301 1.4304 1.5291 0.58576 4.4538 0.16545 0.14811-0.02127 0.42422-1.2095 0.46069-1.36 0.25411-0.96357 0.61812-1.6049 1.3587-2.2583 0.75053-0.69358 1.7635-0.9666 2.6863-1.3526 1.0408-0.39579 2.1353-0.68763 3.1287-1.1962 0.12805-0.06035 0.2561-0.12069 0.38414-0.18103 0 0-3.8517-0.43584-3.8517-0.43584-0.12618 0.06059-0.25236 0.12119-0.37854 0.18179-1.0095 0.4429-2.0552 0.79223-3.0867 1.1786-0.97696 0.38612-1.9942 0.73078-2.7537 1.4922-0.6784 0.69992-1.1041 1.5244-1.3418 2.4736-0.08563 0.30808-0.14275 0.60119-0.30832 0.87972-0.05051 0.08497-0.29376 0.21564-0.1952 0.22324 1.2279 0.09468 2.4644-0.01566 3.6945 0.04656 0.07116 0.0036-0.09855 0.1467-0.16824 0.13185-0.0954-0.02032-0.13522-0.1406-0.20282-0.2109-0.48406-0.68952-0.78002-1.4975-1.0935-2.2751-0.36094-1.1214-0.97173-2.1151-1.6698-3.0606-0.6571-0.99538-1.3971-2.1349-2.2397-2.9817-0.09081-0.09127-0.19994-0.16228-0.29991-0.24342l-3.9009 0.33725z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.1 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="240" height="320" version="1.1" viewBox="0 0 63.5 84.667" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="167.5" cy="23.867" r=".21146" fill="#060000" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<circle cx="167.5" cy="23.867" r=".21146" fill="#e0b0ff" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<g fill="#d28cff">
|
||||
<circle cx="31.623" cy="-54.739" r=".10573" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<circle cx="31.623" cy="-54.739" r=".10573" stroke="#fcfffe" stroke-width=".26458"/>
|
||||
<path d="m56.965 3.4219c0.12058 1.1521-0.2318 2.054-0.81004 3.0337-1.0875 1.5907-2.5336 2.8659-4.0843 3.9867-2.1505 1.3863-4.4585 2.4853-6.8625 3.3491-2.7815 0.78715-5.6335 1.3087-8.4879 1.7525-3.134 0.44066-6.2863 0.71397-9.4313 1.0632-3.4224 0.40837-6.8733 1.0287-10.07 2.3675-0.54185 0.22694-1.0603 0.5062-1.5904 0.75929-0.89954 0.54647-1.6469 0.92677-2.4068 1.6606-1.3388 1.2929-2.0863 2.9786-2.778 4.6654-0.87449 2.3542-1.198 4.6214-1.1672 7.1174 0.18717 1.5284 0.31332 3.0753 0.6288 4.5852 0.091869 0.43967 0.3934 1.5785 0.51155 2.0327 0.39771 1.1363 0.63254 2.4445 1.5286 3.3253 0.14764 0.14511 0.3231 0.25888 0.48465 0.38832 0.20368 0.10006 0.39798 0.22205 0.61104 0.30019 0.42615 0.15629 1.2969 0.32297 1.7205 0.41193 1.1822 0.24832 2.3631 0.46842 3.5556 0.66151 1.9566 0.35044 3.9445 0.66205 5.8228 1.331 1.3844 0.50374 2.5213 1.4098 3.6121 2.3711 1.0386 0.99728 2.1001 1.9882 2.7426 3.3026 0.16634 0.3403 0.28751 0.70088 0.43126 1.0513 0.86215 2.4558 1.0225 5.0522 0.9327 7.631-0.07031 1.5349-0.29391 3.1185-1.156 4.4316-0.12638 0.19249-0.28466 0.36202-0.42699 0.54304-0.81011 0.9275-1.7382 1.735-2.5931 2.6178-0.73658 0.82062-1.6053 0.85394-2.5586 1.1927-0.94832 0.22808-1.8262 0.65178-2.7421 0.97327-1.1741 0.61913-2.4826 0.76669-3.7501 1.0714-1.2105 0.21338-2.3976 0.48893-3.5183 1.0015-0.67364 0.34917-1.2076 0.81882-1.6407 1.4361l3.8658 0.2497c0.43909-0.54046 0.98065-0.94428 1.6142-1.2389 1.1138-0.46371 2.2851-0.70648 3.4664-0.93518 1.2893-0.27722 2.5716-0.54674 3.7736-1.1162 0.91684-0.34231 1.829-0.69308 2.7728-0.9567 1.0196-0.30093 1.8099-0.54985 2.5486-1.3801 0.87014-0.87766 1.7909-1.7075 2.5674-2.6739 0.13769-0.20005 0.28985-0.39088 0.41308-0.60015 0.82211-1.3961 1.0263-3.0131 1.0537-4.6056 0.05629-2.6169-0.0783-5.2743-0.90909-7.7781-0.13345-0.36853-0.2428-0.74671-0.40035-1.1056-0.60136-1.3698-1.6464-2.4153-2.7131-3.4287-1.0905-1.0008-2.2045-1.983-3.6142-2.5099-0.24452-0.10125-0.48125-0.22386-0.73356-0.30376-0.26822-0.08493-0.54885-0.12408-0.82261-0.18901-1.4524-0.34445-2.9022-0.68462-4.3809-0.90277-1.1723-0.18185-2.3227-0.40058-3.4815-0.65277-0.54954-0.11959-1.1101-0.19272-1.6518-0.34365-0.20174-0.05621-0.39234-0.14664-0.58852-0.21996-0.15779-0.10023-0.32954-0.18128-0.47337-0.30068-0.94359-0.78332-1.2089-2.059-1.6142-3.1487-0.16754-0.59766-0.40066-1.3998-0.53448-2.0013-0.33082-1.487-0.45328-3.013-0.62991-4.523-0.03942-2.3761 0.26799-4.7319 1.1144-6.9675 0.36685-0.8728 0.62759-1.5813 1.1166-2.3961 0.98125-1.6348 2.2842-2.7836 3.9639-3.6713 0.51139-0.24392 1.0106-0.5151 1.5342-0.73175 3.1926-1.3212 6.6474-1.892 10.059-2.2825 3.192-0.33755 6.3934-0.58867 9.5696-1.062 2.856-0.4763 5.7214-0.9862 8.4967-1.8227 2.4241-0.91126 4.7643-2.0293 6.9388-3.445 1.5814-1.1701 3.0403-2.506 4.1596-4.1381 0.60624-1.0679 0.95747-1.9925 0.94037-3.2331h-3.9289z"/>
|
||||
<path d="m12.023 67.543c0.49829 0.89935 0.97249 1.783 1.2618 2.7744 0.05193 0.50463 0.27477 0.97017 0.38441 1.4597 0.09562 0.42695 0.06722 0.87236 0.05564 1.3052-0.02684 0.65007-0.04547 1.3125-0.23635 1.9412-0.02066 0.06805-0.31569 0.75033-0.34246 0.81269-1.0192 2.7097-0.33194 1.7204 3.7574 1.4613 0.62653-0.65486 1.2245-1.3292 1.8921-1.9454 0.77212-0.76506 1.7378-1.0867 2.7527-1.378 1.0883-0.39202 2.2359-0.50662 3.3814-0.5819 0.64057-0.03615 1.2822-0.04273 1.9235-0.05158 0 0-3.7766-0.59155-3.7766-0.59155-0.64632 0.01315-1.2932 0.02268-1.9381 0.07203-1.1598 0.09954-2.3084 0.26952-3.4108 0.66115-1.0413 0.32357-1.9937 0.77464-2.7811 1.553-0.66771 0.6262-1.2491 1.3374-1.9404 1.9381 1.2373 0.03262 2.4793-0.01378 3.712 0.09787 0.08161 0.0074-0.02469 0.17515-0.08494 0.23068-0.03731 0.03439-0.0096-0.10235-1.85e-4 -0.15222 0.07511-0.39908 0.24315-0.78076 0.38022-1.1601 0.37962-0.92942 0.58939-1.8859 0.57777-2.896 0.01506-0.47523 0.04582-0.96424-0.0577-1.4334-0.10794-0.48914-0.37419-0.93937-0.40173-1.4497-0.15402-0.55207-0.32508-1.0754-0.57723-1.592-0.14541-0.29797-0.33208-0.5746-0.4773-0.87265-0.05226-0.10725-0.08657-0.22235-0.12986-0.33352l-3.9242 0.13069z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.5 KiB |
@ -1,7 +1,7 @@
|
||||
{% extends "base/base.html" %}
|
||||
{% block main %}
|
||||
<div id="mainworkflow">
|
||||
<div class="workflow">
|
||||
<div class="login">
|
||||
<h2>Forgot your password?</h2>
|
||||
<p>
|
||||
Enter the email address that was used to register with Distribusiverse.
|
||||
@ -26,5 +26,6 @@
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('forgotpassword.static', filename='css/login.css')}}">
|
||||
{% endblock main %}
|
||||
|
@ -23,4 +23,5 @@
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('login.static', filename='css/login.css')}}">
|
||||
{% endblock main %}
|
||||
|
@ -36,4 +36,5 @@
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('register.static', filename='css/login.css')}}">
|
||||
{% endblock main %}
|
||||
|
@ -26,4 +26,5 @@
|
||||
<h3>Password reset link no longer valid.</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('reset_password.static', filename='css/login.css')}}">
|
||||
{% endblock main %}
|
||||
|
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="distribusi">
|
||||
<a href="/distribusi">
|
||||
<a href="distribusikan/distribusi">
|
||||
<input type="button" name="button" value="Distribusi"></input>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="distribusi">
|
||||
<a href="/distribusi">
|
||||
<a href="distribusikan/distribusi">
|
||||
<input type="button" name="button" value="Distribusi"></input>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -6,14 +6,14 @@
|
||||
|
||||
<div id="willemdekooning-logo" class="png">
|
||||
<figure>
|
||||
<img class="image" src="https://www.wdka.nl/build/img/willemdekooning-logo.png">
|
||||
<img class="image" src="https://varia.zone/archive/00-varia-server/welcome.png">
|
||||
<figcaption>logo.png</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div id="example_video" class="mp4">
|
||||
<video controls>
|
||||
<source src="example_video.mp4">
|
||||
<source src="https://vvvvvvaria.org/~crunk/box/tomb_of_doom-2021-02-13_21.41.03.mp4">
|
||||
</video>
|
||||
<span class="filename">example_video.mp4</span>
|
||||
</div>
|
||||
|