Added predavanja, restructure, progress on solar.

This commit is contained in:
msinkec 2021-05-17 14:33:53 +02:00
parent 51b1237b5f
commit 9acce4a8e9
17 changed files with 1058 additions and 329 deletions

View File

@ -13,6 +13,6 @@ WORKDIR /usr/src/portal-webapp
RUN apt-get update && apt-get -y install wkhtmltopdf && \ RUN apt-get update && apt-get -y install wkhtmltopdf && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
RUN pip3 install --no-cache-dir pdfkit flask flask-dropzone flask-log-request-id flask-login Flask-SQLAlchemy alembic flask-migrate Flask-script psycopg2 gunicorn pdfkit Werkzeug RUN pip3 install --no-cache-dir pdfkit flask==1.1.4 flask-dropzone flask-log-request-id flask-login Flask-SQLAlchemy alembic flask-migrate Flask-script psycopg2 gunicorn pdfkit Werkzeug==1.0.1
ENTRYPOINT ["./entrypoint.sh"] ENTRYPOINT ["./entrypoint.sh"]

83
app.py
View File

@ -1,7 +1,6 @@
import logging import logging
import os import os
import configparser import configparser
import re
from pathlib import Path from pathlib import Path
from werkzeug.security import check_password_hash from werkzeug.security import check_password_hash
@ -14,6 +13,8 @@ from portal.model import db, RegisteredUser
import portal.base import portal.base
import portal.solar import portal.solar
import portal.regular
import portal.predavanja
# TODO: Implement user registration. # TODO: Implement user registration.
@ -45,6 +46,7 @@ MAIL_BODY = config['MAIL_BODY']
SQL_CONN_STR = config['SQL_CONN_STR'] SQL_CONN_STR = config['SQL_CONN_STR']
DESC_PREVODI = config['DESC_PREVODI'] DESC_PREVODI = config['DESC_PREVODI']
DESC_GIGAFIDA = config['DESC_GIGAFIDA'] DESC_GIGAFIDA = config['DESC_GIGAFIDA']
DESC_PREDAVANJA = config['DESC_PREDAVANJA']
if 'UPLOADS_DIR' in config: if 'UPLOADS_DIR' in config:
UPLOADS_DIR = Path(config['UPLOADS_DIR']) UPLOADS_DIR = Path(config['UPLOADS_DIR'])
@ -85,7 +87,8 @@ if 'PORTALDS4DS1_DESC_PREVODI' in os.environ:
if 'PORTALDS4DS1_DESC_GIGAFIDA' in os.environ: if 'PORTALDS4DS1_DESC_GIGAFIDA' in os.environ:
DESC_GIGAFIDA = os.environ['PORTALDS4DS1_DESC_GIGAFIDA'] DESC_GIGAFIDA = os.environ['PORTALDS4DS1_DESC_GIGAFIDA']
VALID_CORPUS_NAMES = ['prevodi', 'gigafida', 'solar'] ENABLED_CORPUSES = ['prevodi', 'gigafida', 'solar', 'predavanja']
CORPUSES_LOGIN_REQUIRED = ['solar']
###################### ######################
@ -110,7 +113,33 @@ manager.add_command('db', MigrateCommand)
# Set up dropzone.js to serve all the stuff for "file dropping" on the web interface. # Set up dropzone.js to serve all the stuff for "file dropping" on the web interface.
dropzone = Dropzone(app) dropzone = Dropzone(app)
upload_handler = portal.base.UploadHandler( upload_handler_regular = portal.regular.UploadHandlerRegular(
UPLOADS_DIR=UPLOADS_DIR,
MAIL_HOST=MAIL_HOST,
MAIL_LOGIN=MAIL_LOGIN,
MAIL_PASS=MAIL_PASS,
SMTP_PORT=SMTP_PORT,
IMAP_PORT=IMAP_PORT,
MAIL_SUBJECT=MAIL_SUBJECT,
MAIL_BODY=MAIL_BODY,
CONTRACT_CLIENT_CONTACT=CONTRACT_CLIENT_CONTACT,
MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD
)
upload_handler_solar = portal.solar.UploadHandlerSolar(
UPLOADS_DIR=UPLOADS_DIR,
MAIL_HOST=MAIL_HOST,
MAIL_LOGIN=MAIL_LOGIN,
MAIL_PASS=MAIL_PASS,
SMTP_PORT=SMTP_PORT,
IMAP_PORT=IMAP_PORT,
MAIL_SUBJECT=MAIL_SUBJECT,
MAIL_BODY=MAIL_BODY,
CONTRACT_CLIENT_CONTACT=CONTRACT_CLIENT_CONTACT,
MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD
)
upload_handler_predavanja = portal.predavanja.UploadHandlerPredavanja(
UPLOADS_DIR=UPLOADS_DIR, UPLOADS_DIR=UPLOADS_DIR,
MAIL_HOST=MAIL_HOST, MAIL_HOST=MAIL_HOST,
MAIL_LOGIN=MAIL_LOGIN, MAIL_LOGIN=MAIL_LOGIN,
@ -141,13 +170,15 @@ def index():
@app.route('/<corpus_name>') @app.route('/<corpus_name>')
def index_corpus(corpus_name): def index_corpus(corpus_name):
if corpus_name not in VALID_CORPUS_NAMES: if corpus_name not in ENABLED_CORPUSES:
return 'Korpus "{}" ne obstaja.'.format(corpus_name), 404 return 'Korpus "{}" ne obstaja.'.format(corpus_name), 404
if corpus_name == 'prevodi': if corpus_name == 'prevodi':
description = DESC_PREVODI description = DESC_PREVODI
elif corpus_name == 'gigafida': elif corpus_name == 'gigafida':
description = DESC_GIGAFIDA description = DESC_GIGAFIDA
elif corpus_name == 'predavanja':
return render_template('basic-predavanja.html', description=DESC_PREDAVANJA, max_files=MAX_FILES_PER_UPLOAD)
elif corpus_name == 'solar': elif corpus_name == 'solar':
if current_user.is_authenticated: if current_user.is_authenticated:
return redirect('/solar/oddaja') return redirect('/solar/oddaja')
@ -164,11 +195,16 @@ def load_user(user_id):
@app.route('/<corpus_name>/login') @app.route('/<corpus_name>/login')
def login_get(corpus_name): def login_get(corpus_name):
return render_template('login.html', corpus_name=corpus_name) if corpus_name == 'solar':
return render_template('login.html', corpus_name=corpus_name, title='ŠOLAR')
return 404
@app.route('/<corpus_name>/login', methods=['POST']) @app.route('/<corpus_name>/login', methods=['POST'])
def login_post(corpus_name): def login_post(corpus_name):
if corpus_name not in ENABLED_CORPUSES or corpus_name not in CORPUSES_LOGIN_REQUIRED:
return 404
email = request.form.get('email') email = request.form.get('email')
password = request.form.get('password') password = request.form.get('password')
remember = True if request.form.get('remember') else False remember = True if request.form.get('remember') else False
@ -189,35 +225,48 @@ def login_post(corpus_name):
if corpus_name == 'solar': if corpus_name == 'solar':
return redirect('/solar/oddaja') return redirect('/solar/oddaja')
return redirect('/{}/home'.format(corpus_name)) return 404
@app.route('/<corpus_name>/home')
@login_required
def profile(corpus_name):
return render_template('login.html', corpus_name=corpus_name)
# TODO: Move solar stuff to seperate file using Flask blueprints. # TODO: Move solar stuff to seperate file using Flask blueprints.
@app.route('/solar/oddaja') @app.route('/solar/oddaja')
@login_required @login_required
def solar_oddaja(): def solar_oddaja():
return render_template('solar-oddaja.html') return render_template('solar-oddaja.html')
@app.route('/solar/zgodvina')
@login_required
def solar_zgodovina():
return render_template('solar-zgodovina.html')
@app.route('/solar/pogodbe')
@login_required
def solar_pogodbe():
return render_template('solar-pogodbe.html')
@app.route('/solar/admin')
@login_required
def solar_admin():
# TODO: check if user is admin
return render_template('solar-admin.html')
@app.route('/<corpus_name>/upload', methods=['POST']) @app.route('/<corpus_name>/upload', methods=['POST'])
def handle_upload(corpus_name): def handle_upload(corpus_name):
if corpus_name not in VALID_CORPUS_NAMES: if corpus_name not in ENABLED_CORPUSES:
return 404 return 404
if corpus_name == 'solar': if corpus_name == 'solar':
if current_user.is_authenticated: if current_user.is_authenticated:
return portal.solar.handle_upload(request, upload_handler) return upload_handler_solar.handle_upload(request, current_user.get_id())
return 404 return 404
elif corpus_name == 'predavanja':
return upload_handler_predavanja.handle_upload(request)
else: else:
return portal.base.handle_upload_unauthenticated(request, corpus_name) return upload_handler_regular.handle_upload(request, corpus_name)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -12,6 +12,7 @@ UPLOADS_DIR=./uploads
CONTRACT_CLIENT_CONTACT=Testko Tester CONTRACT_CLIENT_CONTACT=Testko Tester
DESC_PREVODI=<h2 id="subtitle">Prevodi</h2><p>Strojno prevajanje je ena od uporabnih jezikovnih tehnologij, saj omogoča hitro sporazumevanje med ljudmi iz različnih kultur in jezikovnih okolij. Več o razvoju slovenskega strojnega prevajalnika lahko preberete na tej <a href="https://slovenscina.eu/strojno-prevajanje">povezavi</a>. Za kakovosten strojni prevajalnik so ključnega pomena prevodi, iz kateri se algoritmi umetne inteligence naučijo prevajati. S prispevanjem besedil v korpus prevodov boste pomembno prispevali k razvoju slovenskega strojnega prevajalnika med angleščino in slovenščino. Več informacij o prispevanju besedil najdete <a href="https://slovenscina.eu/zbiranje-besedil">tukaj</a>.</p> DESC_PREVODI=<h2 id="subtitle">Prevodi</h2><p>Strojno prevajanje je ena od uporabnih jezikovnih tehnologij, saj omogoča hitro sporazumevanje med ljudmi iz različnih kultur in jezikovnih okolij. Več o razvoju slovenskega strojnega prevajalnika lahko preberete na tej <a href="https://slovenscina.eu/strojno-prevajanje">povezavi</a>. Za kakovosten strojni prevajalnik so ključnega pomena prevodi, iz kateri se algoritmi umetne inteligence naučijo prevajati. S prispevanjem besedil v korpus prevodov boste pomembno prispevali k razvoju slovenskega strojnega prevajalnika med angleščino in slovenščino. Več informacij o prispevanju besedil najdete <a href="https://slovenscina.eu/zbiranje-besedil">tukaj</a>.</p>
DESC_GIGAFIDA=<h2 id="subtitle">Gigafida</h2><p><a href="https://viri.cjvt.si/gigafida/">Gigafida</a> je referenčni korpus pisne slovenščine. Besedila so izbrana in strojno obdelana z namenom, da bi korpus kot vzorec sodobne standardne slovenščine lahko služil za jezikoslovne in druge humanistične raziskave, izdelavo sodobnih slovarjev, slovnic, učnih gradiv in razvoj jezikovnih tehnologij za slovenščino. S prispevanjem besedil v korpus Gigafida pomembno prispevate k razvoju sodobnih jezikovnih tehnologij za slovenski jezik.</p> DESC_GIGAFIDA=<h2 id="subtitle">Gigafida</h2><p><a href="https://viri.cjvt.si/gigafida/">Gigafida</a> je referenčni korpus pisne slovenščine. Besedila so izbrana in strojno obdelana z namenom, da bi korpus kot vzorec sodobne standardne slovenščine lahko služil za jezikoslovne in druge humanistične raziskave, izdelavo sodobnih slovarjev, slovnic, učnih gradiv in razvoj jezikovnih tehnologij za slovenščino. S prispevanjem besedil v korpus Gigafida pomembno prispevate k razvoju sodobnih jezikovnih tehnologij za slovenski jezik.</p>
DESC_PREDAVANJA=<h2 id="subtitle">Predavanja</h2>
MAIL_SUBJECT=RSDO: pogodba za oddana besedila ({upload_id}) MAIL_SUBJECT=RSDO: pogodba za oddana besedila ({upload_id})
MAIL_BODY=Hvala, ker ste prispevali besedila in na ta način pomagali pri razvoju slovenskega jezika v digitalnem okolju. V prilogi vam pošiljamo pogodbo s seznamom naloženih datotek. MAIL_BODY=Hvala, ker ste prispevali besedila in na ta način pomagali pri razvoju slovenskega jezika v digitalnem okolju. V prilogi vam pošiljamo pogodbo s seznamom naloženih datotek.

30
contract/predavanja.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
table {
width: 80%;
margin: 0 auto;
}
</style>
</head>
<body>
{{ime_priimek}}
</body>
<p style="text-align: center;"><b>Priloga k pogodbi o prenosu avtorskih pravic: seznam avtorskih del, ki so predmet pogodbe</b></p>
<div style="width: 100%;">
<table>
<tr>
<td style="text-align: center;"><b>Ime, naslov ali oznaka dela</b></td>
</tr>
{{files_table_str}}
</table>
</div>
</html>

View File

@ -18,15 +18,15 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('upload_unauthenticated', op.create_table('upload_regular',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('upload_hash', sa.String(), nullable=True), sa.Column('upload_hash', sa.String(), nullable=False),
sa.Column('timestamp', sa.DateTime(), nullable=True), sa.Column('timestamp', sa.DateTime(), nullable=False),
sa.Column('form_name', sa.String(), nullable=True), sa.Column('name', sa.String(), nullable=False),
sa.Column('form_org', sa.String(), nullable=True), sa.Column('org', sa.String(), nullable=True),
sa.Column('form_address', sa.String(), nullable=True), sa.Column('address', sa.String(), nullable=True),
sa.Column('form_zipcode', sa.String(), nullable=True), sa.Column('zipcode', sa.String(), nullable=True),
sa.Column('form_email', sa.String(), nullable=True), sa.Column('email', sa.String(), nullable=False),
sa.Column('file_contract', sa.String(), nullable=True), sa.Column('file_contract', sa.String(), nullable=True),
sa.Column('upload_file_hashes', sa.ARRAY(sa.String()), nullable=True), sa.Column('upload_file_hashes', sa.ARRAY(sa.String()), nullable=True),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
@ -36,5 +36,5 @@ def upgrade():
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('upload_unauthenticated') op.drop_table('upload_regular')
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -22,13 +22,13 @@ def downgrade():
op.drop_table('institution') op.drop_table('institution')
op.drop_table('stamps') op.drop_table('stamps')
op.drop_table('registered_user') op.drop_table('registered_user')
op.drop_column('upload_unauthenticated', 'corpus_name') op.drop_column('upload_regular', 'corpus_name')
# ### end Alembic commands ### # ### end Alembic commands ###
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('upload_unauthenticated', sa.Column('corpus_name', sa.TEXT(), autoincrement=False, nullable=False)) op.add_column('upload_regular', sa.Column('corpus_name', sa.TEXT(), autoincrement=False, nullable=False))
op.create_table('institution', op.create_table('institution',
sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('institution_id_seq'::regclass)"), autoincrement=True, nullable=False), sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('institution_id_seq'::regclass)"), autoincrement=True, nullable=False),
sa.Column('name', sa.TEXT(), autoincrement=False, nullable=False), sa.Column('name', sa.TEXT(), autoincrement=False, nullable=False),
@ -66,12 +66,14 @@ def upgrade():
sa.Column('upload_hash', sa.TEXT(), autoincrement=False, nullable=False), sa.Column('upload_hash', sa.TEXT(), autoincrement=False, nullable=False),
sa.Column('timestamp', postgresql.TIMESTAMP(), autoincrement=False, nullable=False), sa.Column('timestamp', postgresql.TIMESTAMP(), autoincrement=False, nullable=False),
sa.Column('corpus_name', sa.TEXT(), autoincrement=False, nullable=False), sa.Column('corpus_name', sa.TEXT(), autoincrement=False, nullable=False),
sa.Column('form_program', sa.TEXT(), autoincrement=False, nullable=True), sa.Column('program', sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('form_subject', sa.TEXT(), autoincrement=False, nullable=True), sa.Column('subject', sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('form_grade', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column('subject_custom', sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('form_text_type', sa.TEXT(), autoincrement=False, nullable=True), sa.Column('grade', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('form_school_year', sa.TEXT(), autoincrement=False, nullable=True), sa.Column('text_type', sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('form_grammar_corrections', sa.TEXT(), autoincrement=False, nullable=True), sa.Column('text_type_custom', sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('school_year', sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('grammar_corrections', sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('upload_file_hashes', sa.ARRAY(sa.String()), nullable=True), sa.Column('upload_file_hashes', sa.ARRAY(sa.String()), nullable=True),
sa.ForeignKeyConstraint(['upload_user'], ['registered_user.id'], name='upload_upload_user_fkey'), sa.ForeignKeyConstraint(['upload_user'], ['registered_user.id'], name='upload_upload_user_fkey'),
sa.ForeignKeyConstraint(['institution'], ['institution.id'], name='upload_institution_fkey'), sa.ForeignKeyConstraint(['institution'], ['institution.id'], name='upload_institution_fkey'),
@ -80,4 +82,22 @@ def upgrade():
# Insert default admin user with username "admin" and pass "portal-admin". # Insert default admin user with username "admin" and pass "portal-admin".
op.execute('INSERT INTO registered_user(name, email, role, pass_hash, active) VALUES (\'admin\', \'admin@cjvt.si\', \'admin\', \'pbkdf2:sha256:150000$aPRDrEqF$f27256d6d57001770feb9e7012ea27252f4a3e5ea9989931368e466d798679ff\', TRUE);') op.execute('INSERT INTO registered_user(name, email, role, pass_hash, active) VALUES (\'admin\', \'admin@cjvt.si\', \'admin\', \'pbkdf2:sha256:150000$aPRDrEqF$f27256d6d57001770feb9e7012ea27252f4a3e5ea9989931368e466d798679ff\', TRUE);')
op.create_table('upload_predavanja',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('upload_hash', sa.String(), nullable=False),
sa.Column('timestamp', sa.DateTime(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('address', sa.String(), nullable=False),
sa.Column('subject', sa.String(), nullable=False),
sa.Column('faculty', sa.String(), nullable=False),
sa.Column('email', sa.String(), nullable=False),
sa.Column('phone', sa.String(), nullable=True),
sa.Column('keywords', sa.String(), nullable=False),
sa.Column('agree_publish', sa.Boolean(), nullable=False),
sa.Column('file_contract', sa.String(), nullable=True),
sa.Column('upload_file_hashes', sa.ARRAY(sa.String()), nullable=True),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -2,6 +2,7 @@ import hashlib
import time import time
import ssl import ssl
import traceback import traceback
import re
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
@ -18,19 +19,22 @@ from email.mime.application import MIMEApplication
import pdfkit import pdfkit
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
from . model import db, UploadUnauthenticated, UploadSolar from . model import db, UploadRegular, UploadSolar, RegisteredUser
ENABLED_FILETYPES = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'xml', 'mxliff', 'tmx'] ENABLED_FILETYPES = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'xml', 'mxliff', 'tmx']
REGEX_EMAIL = re.compile('^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$') REGEX_EMAIL = re.compile('^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$')
MAX_FNAME_LEN = 100
class ContractCreator: class ContractCreator:
def __init__(self): def __init__(self, base_path, template_path):
self.base = base_path
template_loader = FileSystemLoader(searchpath="./") template_loader = FileSystemLoader(searchpath="./")
template_env = Environment(loader=template_loader) template_env = Environment(loader=template_loader)
self.template = template_env.get_template('contract/template.html') self.template = template_env.get_template(template_path)
self.pdfkit_options = { self.pdfkit_options = {
'page-size': 'A4', 'page-size': 'A4',
@ -47,7 +51,11 @@ class ContractCreator:
def fill_template(self, **kwargs): def fill_template(self, **kwargs):
return self.template.render(**kwargs) return self.template.render(**kwargs)
def create_pdf(self, out_f, fields_dict): def create_pdf(self, f_name, fields_dict):
sub_dir = self.base / Path(f_name[:2])
if not sub_dir.exists():
sub_dir.mkdir()
out_f = sub_dir / Path(f_name[2:])
html_str = self.fill_template(**fields_dict) html_str = self.fill_template(**fields_dict)
pdfkit.from_string(html_str, out_f, options=self.pdfkit_options) pdfkit.from_string(html_str, out_f, options=self.pdfkit_options)
@ -56,17 +64,26 @@ class UploadHandler:
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.config = kwargs self.config = kwargs
def set_contract_creator(self, contract_creator):
assert isinstance(contract_creator, ContractCreator)
self._contract_creator = contract_creator
self.contract_creator = ContractCreator() def get_uploads_subdir(self, dir_name):
subdir = Path(self.config['UPLOADS_DIR']) / dir_name
if not subdir.exists():
subdir.mkdir(parents=True)
return subdir
def extract_upload_metadata(self, corpus_name, request): @staticmethod
def extract_upload_metadata(corpus_name, request):
upload_metadata = dict() upload_metadata = dict()
file_hashes = self.create_file_hashes(request.files) file_hashes = UploadHandler.create_file_hashes(request.files)
file_names = file_hashes.keys() file_names = file_hashes.keys()
form_data = request.form.copy() form_data = request.form.copy()
upload_timestamp = int(time.time()) upload_timestamp = int(time.time())
upload_id = self.create_upload_id(corpus_name, form_data, upload_timestamp, file_hashes) upload_id = UploadHandler.create_upload_id(corpus_name, form_data, upload_timestamp, file_hashes)
upload_metadata['corpus_name'] = corpus_name upload_metadata['corpus_name'] = corpus_name
upload_metadata['form_data'] = form_data upload_metadata['form_data'] = form_data
@ -78,14 +95,8 @@ class UploadHandler:
return upload_metadata return upload_metadata
def get_uploads_subdir(self, dir_name): @staticmethod
subdir = Path(self.config['UPLOADS_DIR']) / dir_name def create_upload_id(corpus_name, form_data, upload_timestamp, file_hashes):
if not subdir.exists():
subdir.mkdir(parents=True)
return subdir
def create_upload_id(self, corpus_name, form_data, upload_timestamp, file_hashes):
# Order is important while hashing, hence the sorting. # Order is important while hashing, hence the sorting.
val_buff = [str(upload_timestamp)] val_buff = [str(upload_timestamp)]
for key in sorted(form_data): for key in sorted(form_data):
@ -102,7 +113,8 @@ class UploadHandler:
return metahash return metahash
def create_file_hashes(self, files): @staticmethod
def create_file_hashes(files):
res = dict() res = dict()
for key, f in files.items(): for key, f in files.items():
if key.startswith('file'): if key.startswith('file'):
@ -112,57 +124,14 @@ class UploadHandler:
f.seek(0) f.seek(0)
return res return res
def store_metadata_unauthenticated(self, upload_metadata): @staticmethod
timestamp = datetime.fromtimestamp(upload_metadata['timestamp']) def store_model(self, model_obj):
form_data = upload_metadata['form_data']
file_hashes = upload_metadata['file_hashes_dict']
sorted_f_hashes = list(file_hashes.values())
sorted_f_hashes.sort()
try: try:
upload_unauthenticated = UploadUnauthenticated( db.session.add(model_obj)
upload_hash=upload_metadata['upload_id'],
timestamp=timestamp,
form_name=form_data['ime'],
form_org=form_data['podjetje'],
form_address=form_data['naslov'],
form_zipcode=form_data['posta'],
form_email=form_data['email'],
file_contract=upload_metadata['contract_file'],
upload_file_hashes=sorted_f_hashes,
corpus_name=todo
)
db.session.add(upload_unauthenticated)
db.session.commit()
except Exception:
traceback.print_exc()
def store_metadata_solar(self, upload_metadata):
timestamp = datetime.fromtimestamp(upload_metadata['timestamp'])
form_data = upload_metadata['form_data']
file_hashes = upload_metadata['file_hashes_dict']
sorted_f_hashes = list(file_hashes.values())
sorted_f_hashes.sort()
try:
upload_solar = UploadSolar(
upload_user = todo,
institution = todo,
upload_hash=upload_metadata['upload_id'],
timestamp=timestamp,
form_program=form_data['program'],
form_subject=form_data['subject'],
form_grade=form_data['grade'],
form_text_type=form_data['text_type'],
form_school_year=form_data['school_year'],
form_grammar_corrections=form_data['grammar_corrections'],
upload_file_hashes=sorted_f_hashes
)
db.session.add(upload_unauthenticated)
db.session.commit() db.session.commit()
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
def store_datafiles(self, files, upload_metadata): def store_datafiles(self, files, upload_metadata):
base = self.get_uploads_subdir('files') base = self.get_uploads_subdir('files')
@ -170,32 +139,18 @@ class UploadHandler:
for key, f in files.items(): for key, f in files.items():
if key.startswith('file'): if key.startswith('file'):
path = base / file_hashes[f.filename] f_hash = file_hashes[f.filename]
# First byte used for indexing, similarly like git does for example.
sub_dir = base / f_hash[:2]
if not sub_dir.exists():
sub_dir.mkdir()
path = sub_dir / f_hash[2:]
if not path.exists(): if not path.exists():
path.mkdir() path.mkdir()
f.save(path / f.filename) f.save(path / f.filename)
def generate_upload_contract_pdf(self, upload_metadata):
base = self.get_uploads_subdir('contracts')
form_data = upload_metadata['form_data']
files_table_str = []
for file_name in upload_metadata['file_names']:
files_table_str.append('<tr><td style="text-align: center;">')
files_table_str.append(file_name)
files_table_str.append('</td></tr>')
files_table_str = ''.join(files_table_str)
data = {
'ime_priimek': form_data['ime'],
'naslov': form_data['naslov'],
'posta': form_data['posta'],
'kontakt_narocnik': self.config['CONTRACT_CLIENT_CONTACT'],
'kontakt_imetnikpravic': form_data['ime'],
'files_table_str': files_table_str
}
self.contract_creator.create_pdf(base / upload_metadata['contract_file'], data)
def send_confirm_mail(self, upload_metadata): def send_confirm_mail(self, upload_metadata):
upload_id = upload_metadata['upload_id'] upload_id = upload_metadata['upload_id']
@ -207,15 +162,16 @@ class UploadHandler:
body = self.config['MAIL_BODY'].format(upload_id=upload_id) body = self.config['MAIL_BODY'].format(upload_id=upload_id)
message.attach(MIMEText(body, "plain")) message.attach(MIMEText(body, "plain"))
contracts_dir = self.get_uploads_subdir('contracts') contracts_dir = self.contract_creator.base
base_name = upload_metadata['contract_file'] f_name = upload_metadata['contract_file']
contract_file = contracts_dir / base_name sub_dir = contracts_dir / Path(f_name[:2])
contract_file = sub_dir / Path(f_name[2:])
with open(contract_file, "rb") as f: with open(contract_file, "rb") as f:
part = MIMEApplication( part = MIMEApplication(
f.read(), f.read(),
Name = base_name Name = f_name
) )
part['Content-Disposition'] = 'attachment; filename="%s"' % base_name part['Content-Disposition'] = 'attachment; filename="%s"' % f_name
message.attach(part) message.attach(part)
text = message.as_string() text = message.as_string()
@ -223,89 +179,57 @@ class UploadHandler:
# Create a secure SSL context # Create a secure SSL context
context = ssl.create_default_context() context = ssl.create_default_context()
with SMTP_SSL(self.config['MAIL_HOST'], self.config['SMTP_PORT'], context=context) as server: try:
server.login(self.config['MAIL_LOGIN'], self.config['MAIL_PASS']) with SMTP_SSL(self.config['MAIL_HOST'], self.config['SMTP_PORT'], context=context) as server:
server.sendmail(message['From'], message['To'], text) server.login(self.config['MAIL_LOGIN'], self.config['MAIL_PASS'])
server.sendmail(message['From'], message['To'], text)
# Save copy of sent mail in Sent mailbox # Save copy of sent mail in Sent mailbox
imap = imaplib.IMAP4_SSL(self.config['MAIL_HOST'], self.config['IMAP_PORT']) imap = imaplib.IMAP4_SSL(self.config['MAIL_HOST'], self.config['IMAP_PORT'])
imap.login(self.config['MAIL_LOGIN'], self.config['MAIL_PASS']) imap.login(self.config['MAIL_LOGIN'], self.config['MAIL_PASS'])
imap.append('Sent', '\\Seen', imaplib.Time2Internaldate(time.time()), text.encode('utf8')) imap.append('Sent', '\\Seen', imaplib.Time2Internaldate(time.time()), text.encode('utf8'))
imap.logout() imap.logout()
except Exception:
traceback.print_exc()
def handle_upload_unauthenticated(request, corpus_name, upload_handler): @staticmethod
files = request.files def check_suffixes(files):
if len(files) > upload_handler.MAX_FILES_PER_UPLOAD: for key, f in files.items():
return 'Naložite lahko do {} datotek hkrati.'.format(upload_handler.MAX_FILES_PER_UPLOAD), 400 if key.startswith('file'):
elif len(files) < 1: suffix = f.filename.split('.')[-1]
return 'Priložena ni bila nobena datoteka.', 400 if suffix not in ENABLED_FILETYPES:
return 'Datoteka "{}" ni pravilnega formata.'.format(f.filename)
return None
err = check_suffixes(files) @staticmethod
if err: def check_fname_lengths(files):
return err, 400 for key, f in files.items():
if key.startswith('file'):
if len(f.filename) > MAX_FNAME_LEN:
return 'Ime datoteke presega dolžino {} znakov.'.format(MAX_FNAME_LEN)
return None
err = check_form(request.form) def check_upload_request(self, request):
if err: files = request.files
return err, 400 max_files = self.config['MAX_FILES_PER_UPLOAD']
if len(files) > max_files:
return 'Naložite lahko do {} datotek hkrati.'.format(max_files), 400
elif len(files) < 1:
return 'Priložena ni bila nobena datoteka.', 400
# Parse request. err = UploadHandler.check_suffixes(files)
upload_metadata = upload_handler.extract_upload_metadata(corpus_name, request) if err:
return err, 400
logging.info('Upload with id "{}" supplied form data: {}'.format(upload_metadata['upload_id'], err = UploadHandler.check_fname_lengths(files)
str(upload_metadata['form_data']))) if err:
return err, 400
# Generate contract PDF file based on the uploads metadata. return None
upload_handler.generate_upload_contract_pdf(upload_metadata)
# Store uploaded files to disk. @staticmethod
upload_handler.store_datafiles(files, upload_metadata) def get_user_institution(user_id):
match = db.session.query(RegisteredUser).filter(RegisteredUser.id == user_id).one()
# Store metadata to database. return match.institution
upload_handler.store_metadata_unauthenticated(upload_metadata)
# Send confirmation mail along with the contract to the submitted email address.
upload_handler.send_confirm_mail(upload_metadata)
return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(files))
def check_suffixes(files):
for key, f in files.items():
if key.startswith('file'):
suffix = f.filename.split('.')[-1]
if suffix not in ENABLED_FILETYPES:
return 'Datoteka "{}" ni pravilnega formata.'.format(f.filename)
return None
def check_form(form):
ime = form.get('ime')
podjetje = form.get('podjetje')
naslov = form.get('naslov')
posta = form.get('posta')
email = form.get('email')
telefon = form.get('telefon')
if len(ime) > 100:
return 'Predolgo ime.'
if len(podjetje) > 100:
return 'Predolgo ime institucije.'
if len(email) > 100:
return 'Predolgi email naslov'
elif not re.search(REGEX_EMAIL, email):
return 'Email napačnega formata.'
if len(telefon) > 100:
return 'Predolga telefonska št.'
if len(naslov) > 100:
return 'Predolg naslov.'
if len(posta) > 100:
return 'Predolga pošta'
return None

View File

@ -12,22 +12,39 @@ from flask_login import UserMixin
db = SQLAlchemy() db = SQLAlchemy()
# Entries for uploads to corpora, that have no authentication. E.g. "prevodi" or "gigafida". # "prevodi" or "gigafida".
class UploadUnauthenticated(db.Model): class UploadRegular(db.Model):
__tablename__ = 'upload_unauthenticated' __tablename__ = 'upload_regular'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
upload_hash = db.Column(db.String) upload_hash = db.Column(db.String)
timestamp = db.Column(db.DateTime, default=datetime.utcnow) timestamp = db.Column(db.DateTime, default=datetime.utcnow)
form_name = db.Column(db.String) name = db.Column(db.String)
form_org = db.Column(db.String) org = db.Column(db.String)
form_address = db.Column(db.String) address = db.Column(db.String)
form_zipcode = db.Column(db.String) zipcode = db.Column(db.String)
form_email = db.Column(db.String) email = db.Column(db.String)
file_contract = db.Column(db.String) file_contract = db.Column(db.String)
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String)) upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String))
corpus_name = db.Column(db.String) corpus_name = db.Column(db.String)
class UploadPredavanja(db.Model):
__tablename__ = 'upload_predavanja'
id = db.Column(db.Integer, primary_key=True)
upload_hash = db.Column(db.String)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
name = db.Column(db.String)
address = db.Column(db.String)
subject = db.Column(db.String)
faculty = db.Column(db.String)
email = db.Column(db.String)
phone = db.Column(db.String)
keywords = db.Column(db.String)
agree_publish = db.Column(db.Boolean)
file_contract = db.Column(db.String)
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String))
class UploadSolar(db.Model): class UploadSolar(db.Model):
__tablename__ = 'upload_solar' __tablename__ = 'upload_solar'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -35,13 +52,14 @@ class UploadSolar(db.Model):
institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id')) institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'))
upload_hash = db.Column(db.String) upload_hash = db.Column(db.String)
timestamp = db.Column(db.DateTime, default=datetime.utcnow) timestamp = db.Column(db.DateTime, default=datetime.utcnow)
corpus_name = db.Column(db.String) program = db.Column(db.String)
form_program = db.Column(db.String) subject = db.Column(db.String)
form_subject = db.Column(db.String) subject_custom = db.Column(db.String)
form_grade = db.Column(db.Integer) grade = db.Column(db.Integer)
form_text_type = db.Column(db.String) text_type = db.Column(db.String)
form_school_year = db.Column(db.String) text_type_custom = db.Column(db.String)
form_grammar_corrections = db.Column(db.String) school_year = db.Column(db.String)
grammar_corrections = db.Column(db.String)
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String)) upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String))

123
portal/predavanja.py Normal file
View File

@ -0,0 +1,123 @@
import logging
import traceback
import re
from datetime import datetime
import portal.base
from portal.base import UploadHandler, ContractCreator, REGEX_EMAIL
from portal.model import db, UploadPredavanja
MAXLEN_FORM = 150
class UploadHandlerPredavanja(UploadHandler):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.contract_creator = ContractCreator(base_path=self.get_uploads_subdir('contracts'),
template_path='contract/predavanja.html')
def generate_upload_contract_pdf(self, upload_metadata):
form_data = upload_metadata['form_data']
files_table_str = []
for file_name in upload_metadata['file_names']:
files_table_str.append('<tr><td style="text-align: center;">')
files_table_str.append(file_name)
files_table_str.append('</td></tr>')
files_table_str = ''.join(files_table_str)
data = {
'ime_priimek': form_data['ime'],
'files_table_str': files_table_str
}
self.contract_creator.create_pdf(upload_metadata['contract_file'], data)
@staticmethod
def store_metadata(upload_metadata):
timestamp = datetime.fromtimestamp(upload_metadata['timestamp'])
form_data = upload_metadata['form_data']
file_hashes = upload_metadata['file_hashes_dict']
sorted_f_hashes = list(file_hashes.values())
sorted_f_hashes.sort()
try:
model_obj = UploadPredavanja(
upload_hash=upload_metadata['upload_id'],
timestamp=timestamp,
name=form_data['ime'],
address=form_data['naslov-predavanja'],
subject=form_data['predmet'],
faculty=form_data['fakulteta'],
email=form_data['email'],
phone=form_data.get('phone'),
keywords=form_data['kljucne-besede'],
agree_publish=True if 'kljucne-besde' in form_data else False,
file_contract=upload_metadata['contract_file'],
upload_file_hashes=sorted_f_hashes,
)
db.session.add(model_obj)
db.session.commit()
except Exception:
traceback.print_exc()
def handle_upload(self, request):
err = self.check_upload_request(request)
if err:
return err, 400
err = self.check_form(request.form)
if err:
return err, 400
# Parse request.
upload_metadata = self.extract_upload_metadata('predavanja', request)
logging.info('Upload for "predavanja" with id "{}" supplied form data: {}'.format(
upload_metadata['upload_id'], str(upload_metadata['form_data'])))
# Generate contract PDF file based on the uploads metadata.
self.generate_upload_contract_pdf(upload_metadata)
# Store uploaded files to disk.
self.store_datafiles(request.files, upload_metadata)
# Store metadata to database.
self.store_metadata(upload_metadata)
# Send confirmation mail along with the contract to the submitted email address.
self.send_confirm_mail(upload_metadata)
return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(request.files))
@staticmethod
def check_form(form):
name = form.get('ime')
address = form.get('naslov-predavanja')
subject = form.get('predmet')
faculty = form.get('fakulteta')
email = form.get('email')
phone = form.get('telefon')
keywords = form.get('kljucne-besede')
if not name \
or not address \
or not subject \
or not faculty \
or not email \
or not keywords:
return 'Izpolnite vsa obvezna polja.'
for keyword in keywords.split():
if not keyword.isalpha():
return 'Ključna beseda "{}" ni pravilnega formata.'.format(keyword)
if not re.search(REGEX_EMAIL, email):
return 'Email napačnega formata.'
for key, val in form.items():
if len(val) > MAXLEN_FORM:
return 'Polje "{}" presega dolžino {} znakov.'.format(key, MAXLEN_FORM)

130
portal/regular.py Normal file
View File

@ -0,0 +1,130 @@
import logging
import re
import traceback
from datetime import datetime
from portal.base import UploadHandler, ContractCreator, REGEX_EMAIL
from portal.model import db, UploadRegular
class UploadHandlerRegular(UploadHandler):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.contract_creator = ContractCreator(base_path=self.get_uploads_subdir('contracts'),
template_path='contract/regular.html')
def generate_upload_contract_pdf(self, upload_metadata):
base = self.get_uploads_subdir('contracts')
form_data = upload_metadata['form_data']
files_table_str = []
for file_name in upload_metadata['file_names']:
files_table_str.append('<tr><td style="text-align: center;">')
files_table_str.append(file_name)
files_table_str.append('</td></tr>')
files_table_str = ''.join(files_table_str)
data = {
'ime_priimek': form_data['ime'],
'naslov': form_data.get('naslov', ''),
'posta': form_data.get('posta', ''),
'kontakt_narocnik': self.config['CONTRACT_CLIENT_CONTACT'],
'kontakt_imetnikpravic': form_data['ime'],
'files_table_str': files_table_str
}
self.contract_creator.create_pdf(upload_metadata['contract_file'], data)
@staticmethod
def store_metadata(upload_metadata, corpus_name):
timestamp = datetime.fromtimestamp(upload_metadata['timestamp'])
form_data = upload_metadata['form_data']
file_hashes = upload_metadata['file_hashes_dict']
sorted_f_hashes = list(file_hashes.values())
sorted_f_hashes.sort()
try:
model_obj = UploadRegular(
upload_hash=upload_metadata['upload_id'],
timestamp=timestamp,
name=form_data['ime'],
org=form_data.get('podjetje'),
address=form_data.get('naslov'),
zipcode=form_data.get('posta'),
email=form_data['email'],
file_contract=upload_metadata['contract_file'],
upload_file_hashes=sorted_f_hashes,
corpus_name=corpus_name
)
db.session.add(model_obj)
db.session.commit()
except Exception:
traceback.print_exc()
def handle_upload(self, request, corpus_name):
err = self.check_upload_request(request)
if err:
return err, 400
err = self.check_form(request.form)
if err:
return err, 400
# Parse request.
upload_metadata = self.extract_upload_metadata(corpus_name, request)
logging.info('Upload with id "{}" supplied form data: {}'.format(upload_metadata['upload_id'],
str(upload_metadata['form_data'])))
# Generate contract PDF file based on the uploads metadata.
self.generate_upload_contract_pdf(upload_metadata)
# Store uploaded files to disk.
self.store_datafiles(request.files, upload_metadata)
# Store metadata to database.
self.store_metadata(upload_metadata, corpus_name)
# Send confirmation mail along with the contract to the submitted email address.
self.send_confirm_mail(upload_metadata)
return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(request.files))
@staticmethod
def check_form(form):
ime = form.get('ime')
podjetje = form.get('podjetje')
naslov = form.get('naslov')
posta = form.get('posta')
email = form.get('email')
telefon = form.get('telefon')
if not ime:
return 'Prazno polje za ime.'
if len(ime) > 100:
return 'Predolgo ime.'
if podjetje and len(podjetje) > 100:
return 'Predolgo ime institucije.'
if not email:
return 'Prazno polje za elektronsko pošto.'
if len(email) > 100:
return 'Predolgi email naslov'
elif not re.search(REGEX_EMAIL, email):
return 'Email napačnega formata.'
if telefon and len(telefon) > 100:
return 'Predolga telefonska št.'
if naslov and len(naslov) > 100:
return 'Predolg naslov.'
if posta and len(posta) > 100:
return 'Predolga pošta'
return None

View File

@ -1,41 +1,101 @@
import logging
import re
from datetime import datetime
import portal.base import portal.base
from portal.base import UploadHandler
from portal.model import UploadSolar
def handle_upload(request, upload_handler): VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'}
files = request.files VALID_SUBJECTS = {'slo', 'drug-jez', 'drug-druz', 'drug-narav', 'drug-strok', 'drug-izb'}
if len(files) > upload_handler.MAX_FILES_PER_UPLOAD: VALID_TEXT_TYPES = {'esej-spis', 'prakticno', 'solski-test', 'delo-v-razredu'}
return 'Naložite lahko do {} datotek hkrati.'.format(upload_handler.MAX_FILES_PER_UPLOAD), 400 VALID_GRAMMAR_CORRECTIONS = {'popr-ne', 'brez-popr', 'popr-da'}
elif len(files) < 1:
return 'Priložena ni bila nobena datoteka.', 400
err = portal.base.check_suffixes(files) MAXLEN_FORM = 150
if err:
return err, 400
err = check_form(request.form)
if err:
return err, 400
# Parse request.
upload_metadata = upload_handler.extract_upload_metadata(corpus_name, request)
logging.info('Upload from user "{}" with upload id "{}" supplied form data: {}'.format(
request.user,
upload_metadata['upload_id'],
str(upload_metadata['form_data']
)))
# Store uploaded files to disk.
upload_handler.store_datafiles(files, upload_metadata)
# Store metadata to database.
upload_handler.store_metadata_solar(upload_metadata)
# Send confirmation mail along with the contract to the submitted email address.
upload_handler.send_confirm_mail(upload_metadata)
return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(files))
def check_form(form): class UploadHandlerSolar(UploadHandler):
pass
@staticmethod
def store_metadata(upload_metadata, user_id):
timestamp = datetime.fromtimestamp(upload_metadata['timestamp'])
form_data = upload_metadata['form_data']
file_hashes = upload_metadata['file_hashes_dict']
sorted_f_hashes = list(file_hashes.values())
sorted_f_hashes.sort()
institution_id = UploadHandler.get_user_institution(user_id)
try:
model_obj = UploadSolar(
upload_user = user_id,
institution = institution_id,
upload_hash=upload_metadata['upload_id'],
timestamp=timestamp,
program=form_data['program'],
subject=form_data['predmet'],
subject_custom=form_data['predmet-custom'],
grade=form_data['letnik'],
text_type=form_data['vrsta'],
text_type_custom=form_data['vrsta-custom'],
school_year=form_data['solsko-leto'],
grammar_corrections=form_data['jezikovni-popravki'],
upload_file_hashes=sorted_f_hashes
)
db.session.add(model_obj)
db.session.commit()
except Exception:
traceback.print_exc()
def handle_upload(self, request, user_id):
err = portal.base.check_upload_request(request, self)
if err:
return err, 400
err = self.check_form(request.form)
if err:
return err, 400
# Parse request.
upload_metadata = self.extract_upload_metadata('solar', request)
logging.info('Upload from user "{}" with upload id "{}" supplied form data: {}'.format(
user_id,
upload_metadata['upload_id'],
str(upload_metadata['form_data']
)))
# Store uploaded files to disk.
self.store_datafiles(request.files, upload_metadata)
# Store to database.
self.store_metadata(upload_metadata, user_id)
return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(request.files))
@staticmethod
def check_form(form):
program = form['program']
predmet = form['predmet']
letnik = int(form['letnik'])
vrsta = form['vrsta']
solsko_leto = form['solsko-leto']
jezikovni_popravki = form['jezikovni-popravki']
if program not in VALID_PROGRAMS:
return 'Invalid program "{}"'.format(program)
if predmet not in VALID_SUBJECTS:
return 'Invalid subject "{}"'.format(premdet)
if letnik < 1 or letnik > 9:
return 'Invalid grade: {}'.format(letnik)
if vrsta not in VALID_TEXT_TYPES:
return 'Invalid text type "{}"'.format(vrsta)
if not re.match('^\d{0,2}-\d{0,2}$', solsko_leto):
return 'Invalid school year "{}"'.format(solsko_leto)
if jezikovni_popravki not in VALID_GRAMMAR_CORRECTIONS:
return 'Invalid text type "{}"'.format(jezikovni_popravki)
for key, val in form.items():
if len(val) > MAXLEN_FORM:
return 'Value in form field "{}" exceeds max len of {}'.format(key, MAXLEN_FORM)

View File

@ -338,13 +338,12 @@ var _createClass = function() {
// TODO: find scrollbox eleemnt, if not exist, create one // TODO: find scrollbox eleemnt, if not exist, create one
var scrollbox = this.previewsContainer.querySelector(".scrollbox"); var scrollbox = this.previewsContainer.querySelector("#dropzone-scrollbox");
if (scrollbox == null) { if (scrollbox == null) {
scrollbox = document.createElement("div"); scrollbox = document.createElement("div");
scrollbox.setAttribute("class", "scrollbox"); scrollbox.setAttribute("id", "dropzone-scrollbox");
this.previewsContainer.appendChild(scrollbox); this.previewsContainer.appendChild(scrollbox);
} }
console.log(scrollbox)
a.previewElement = a.previewElement =
b.createElement(this.options.previewTemplate.trim()), b.createElement(this.options.previewTemplate.trim()),

View File

@ -22,7 +22,7 @@ html {
} }
html { html {
background: url(image/bg.jpeg) no-repeat center center fixed; background: url(image/bg.jpeg) no-repeat center center fixed;
-webkit-background-size: cover; -webkit-background-size: cover;
-moz-background-size: cover; -moz-background-size: cover;
-o-background-size: cover; -o-background-size: cover;
@ -30,7 +30,6 @@ html {
overflow-y: scroll; overflow-y: scroll;
} }
#main-window { #main-window {
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -43,7 +42,7 @@ html {
position: absolute; position: absolute;
top: -9%; top: -9%;
left: 35%; left: 35%;
background: #F5F5F5; background: #f5f5f5;
border-radius: 50%; border-radius: 50%;
padding-top: 5%; padding-top: 5%;
padding-bottom: 5%; padding-bottom: 5%;
@ -133,6 +132,30 @@ label {
margin: 0px 10px; margin: 0px 10px;
} }
.button-general {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 10px 40px;
width: 138px;
height: 41px;
background: #006cb7;
border-radius: 29px;
border: 0px;
font-family: Roboto;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #ffffff;
flex: none;
order: 0;
flex-grow: 0;
}
.button-terms:enabled { .button-terms:enabled {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -179,7 +202,6 @@ label {
margin-top: 15px; margin-top: 15px;
} }
input { input {
font-family: Roboto; font-family: Roboto;
font-style: normal; font-style: normal;
@ -193,19 +215,50 @@ input {
width: 100%; width: 100%;
} }
.mock-side {
position: absolute;
top: -0.5px;
width: 388px;
height: 732px;
left: 385px;
background: linear-gradient(
198.62deg,
rgba(255, 255, 255, 0.49) -1.62%,
rgba(255, 255, 255, 0.73) -1.61%,
rgba(255, 255, 255, 0.41) 79.34%
);
box-shadow: 20px 4px 40px rgba(0, 0, 0, 0.25);
backdrop-filter: blur(20px);
border: 0px;
border-radius: 0px 20px 20px 0px;
}
select {
font-family: Roboto;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 19px;
color: #46535b;
background: #f5f5f5;
border: 0px;
border-bottom: 2px solid #c4c4c4;
width: 100%;
}
#izjava { #izjava {
width: auto; width: auto;
} }
.scrollbox { #dropzone-scrollbox {
position: relative; position: absolute;
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
margin-top: 26px; margin-top: 26px;
margin-bottom: 26px; margin-bottom: 26px;
min-height: 100px; min-height: 100px;
max-height: 670px; max-height: 670px;
top: -600px; top: 0px;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
} }
@ -336,7 +389,7 @@ input {
display: none; display: none;
} }
.corpus-type-selector { .selection-tabs {
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
@ -345,7 +398,7 @@ input {
margin-bottom: 20px; margin-bottom: 20px;
} }
.corpus-type-button { .selection-tab-button {
width: 100%; width: 100%;
border: 0px; border: 0px;
outline: 0px; outline: 0px;
@ -359,7 +412,7 @@ input {
color: #848c91; color: #848c91;
} }
.corpus-type-button.selected { .selection-tab-button.selected {
width: 100%; width: 100%;
border: 0px; border: 0px;
outline: 0px; outline: 0px;
@ -398,3 +451,8 @@ input {
line-height: 19px; line-height: 19px;
color: #46535b; color: #46535b;
} }
.dz-error-message {
top: 100% !important;
left: 25% !important;
}

View File

@ -0,0 +1,294 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Portal za oddajanje besedil</title>
<!--{{ dropzone.load_css() }}-->
<link rel="stylesheet" href="static/dropzone.css" type="text/css">
{{ dropzone.style('position: absolute;
top: -0.5px;
width: 388px;
height: 732px;
left: 385px;
background: linear-gradient(198.62deg, rgba(255, 255, 255, 0.49) -1.62%, rgba(255, 255, 255, 0.73) -1.61%, rgba(255, 255, 255, 0.41) 79.34%);
box-shadow: 20px 4px 40px rgba(0, 0, 0, 0.25);
backdrop-filter: blur(20px);
border: 0px;
border-radius: 0px 20px 20px 0px;') }}
<link rel="stylesheet" href="static/style.css" type="text/css">
</head>
<body>
<div id="main-window">
<div id="rect1">
<div id="logo-container">
<img src="static/image/logo.svg" alt="logo"/>
</div>
<form id="my-dropzone" class="dropzone">
<div style="position: relative; right: 390px;">
<h1 id="title">Portal za oddajanje besedil</h1>
<div class="form-text">{{description|safe}}</div>
<label for="ime">* Ime in priimek:</label>
<input type="text" id="ime" name="ime" required="required"/>
<label for="naslov-predavanja">* Naslov predavanja:</label>
<input type="text" id="naslov-predavanja" name="naslov-predavanja" required="required"/>
<label for="predmet">* Predmet:</label>
<input type="text" id="predmet" name="predmet" required="required"/>
<label for="fakulteta">* Fakulteta:</label>
<input type="text" id="fakulteta" name="fakulteta" required="required"/>
<label for="email">* E-Pošta:</label>
<input type="text" id="email" name="email" required="required"/>
<label for="telefon">Telefon:</label>
<input type="text" id="telefon" name="telefon"/>
<label for="kljucne-besede">* Ključne besede:</label>
<input type="text" id="kljucne-besede" name="kljucne-besede" required="required"/>
<div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
<label>Ali se strinjate z javno objavo predavanja?</label>
<input style="width: 10%;" type="checkbox" name="javna-objava" value="javna-objava" checked>
</div>
<div class="form-text">*Po kliku na gumb “Oddaj” se bo prikazala vsebina pogodobe o odstopu avtorskih pravic. Če se z vsebino strinjate, kliknite gumb “Pošlji”, da podatke posredujete v korpus, po e-pošti pa boste prejeli svoj izvod pogodbe.</div>
<button id="button-submit" type="submit">Oddaj</button>
</div>
<div class="dropzone-previews"></div>
</form>
</div>
</div>
<div id="popup-terms" style="display: none">
<div id="popup-terms-text">
<h2>POGODBA O PRENOSU AVTORSKIH PRAVIC</h2>
<h3>UVODNE DOLOČBE</h3>
<h4><b>1. člen</b></h4>
<p>1.1. Stranki uvodoma ugotavljata, da naročnik izvaja projekt Razvoj slovenščine v digitalnem
okolju RSDO (v nadaljevanju projekt RSDO), ki je bil na javnem razpisu Razvoj slovenščine v
digitalnem okolju jezikovni viri in tehnologije (JR-ESRR-Razvoj slovenščine v digitalnem
okolju), objavljenem v Uradnem listu RS št. 70/19 dne 29. 11. 2019, sprejet v sofinanciranje
in katerega vsebina je razvidna s spletnih strani https://slovenscina.eu.</p>
<p>1.2. Stranki uvodoma ugotavljata, da bo naročnik v okviru projekta RSDO:
- izdelal osrednjo digitalno slovarsko bazo, ki združuje različne tipe jezikovnih podatkov o
slovenščini v odprtem dostopu,
- izdelal terminološki portal z integriranim iskalnikom po slovenskih terminoloških virih, zlasti
terminoloških slovarjih,
- izdelal korpus prevodov po različnih domenah za učenje strojnega prevajalnika za jezikovni
par angleščina-slovenščina in slovenščina-angleščina.</p>
<p>1.3. Stranki uvodoma ugotavljata, da bo naročnik pri projektu RSDO za vse zgoraj opisane
namene zbiral in uporabil besedilne vire, ki so navedeni v prilogi k tej pogodbi in ki so lahko
avtorska dela ali drugi predmeti varstva v skladu z Zakonom o avtorski in sorodnih pravicah
(Uradni list RS, št. 16/07 uradno prečiščeno besedilo, 68/08, 110/13, 56/15, 63/16 ZKUASP
in 59/19; ZASP) in na katerih ima imetnik pravic avtorske, avtorski sorodne ali druge pravice v
skladu z ZASP (v nadaljevanju avtorska dela).</p>
<p>1.4. Stranki ugotavljata, da bodo avtorska dela in vse njihove morebitne spremembe in
predelave, ter zbirke podatkov, ki bodo med izvajanjem projekta RSDO nastale, javno
dostopni pod pogoji prostih licenc (npr. CC BY-SA) in bodo na voljo za nekomercialen in
komercialen razvoj tehnologij, za raziskave in za druge raziskovalne namene
posameznikom, raziskovalnim in izobraževalnim institucijam, neprofitnim organizacijam,
državnim organom, organizacijam z javnimi pooblastili in gospodarskim družbam v Sloveniji
in tujini.</p>
<h3>PREDMET POGODBE</h3>
<h4><b>2. člen</b></h4>
<p>2.1. Predmet pogodbe so vsa avtorska dela imetnika pravic, ki so navedena v prilogi k tej
pogodbi.</p>
<p>2.2. S podpisom te pogodbe imetnik avtorskih pravic na naročnika prenaša avtorske pravice
na avtorskih delih na način in v obsegu, kakor je navedeno v 3. členu te pogodbe.</p>
<h3>PRENOS AVTORSKIH PRAVIC</h3>
<h4><b>3. člen</b></h4>
<p>3.1. S podpisom te pogodbe imetnik pravic na avtorskih delih, ki so predmet te pogodbe, na
naročnika neizključno, brez časovnih in teritorialnih omejitev prenaša vse materialne avtorske
pravice, avtorski sorodne pravice in druge pravice avtorja v skladu z ZASP, zlasti pravico
reproduciranja (23. člen ZASP), distribuiranja (24. člena ZASP), dajanja v najem (25. člen ZASP),
priobčitve javnosti (26. do 32.a člen ZASP), vključno s pravico dajanja na voljo javnosti (32.a
člen ZASP) in pravico predelave (33. člen ZASP).</p>
<p>3.2. S podpisom te pogodbe imetnik pravic izrecno soglaša, da naročnik pravice iz točke 3.1.
prenaša naprej na tretje osebe brez omejitev.</p>
<h3>JAMČEVANJE IMETNIKA PRAVIC</h3>
<h4><b>4. člen</b></h4>
<p>4.1. S podpisom te pogodbe imetnik pravic jamči, da je na avtorskih delih, ki so predmet te
pogodbe, imetnik vseh avtorskih pravic, avtorski sorodnih pravic in drugih pravic avtorja v
skladu z ZASP, ki so potrebne za prenos pravic po tej pogodbi, in da na avtorskih delih ne
obstajajo pravice tretjih oseb, ki bi naročniku preprečevale njihovo uporabo.</p>
<p>4.2. Določbe te pogodbe ne vplivajo na prenos moralnih avtorskih pravic, ki so v skladu z
določbami ZASP neprenosljive.</p>
<h3>OSEBNI PODATKI</h3>
<h4><b>5. člen</b></h4>
<p>6.1. Stranki se zavezujeta, da bosta vse morebitne osebne podatke, ki jih bosta obdelovali za
namene izvajanja te pogodbe, obdelovali na način, da bosta upoštevali vse veljavne predpise
o varstvu osebnih podatkov in da bosta posameznikom, na katere se osebni podatki nanašajo,
zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatkov.<p>
<h3>KONTAKTNE OSEBE</h3>
<h4><b>6. člen</b></h4>
<p>7.1 Kontaktna oseba za izvedbo te pogodbe na strani naročnika je [xxx].</p>
<p>7.2. Kontaktna oseba za izvedbo te pogodbe na strani imetnika pravic je [xxx].</p>
<h3>KONČNE DOLOČBE</h3>
<h4><b>7. člen</b></h4>
<p>8.1. Če je katerakoli določba te pogodbe nična, ostanejo druga določila te pogodbe v veljavi.</p>
<h4><b>8. člen</b></h4>
<p>9.1. Za razmerja v zvezi s to pogodbo se uporabljajo pravni predpisi Republike Slovenije.</p>
<p>9.2. Spore iz te pogodbe bosta stranki reševali po mirni poti. V primeru, da mirna rešitev ne
bo mogoča, je za vse spore v zvezi s to pogodbo pristojno sodišče v Ljubljani.</p>
<h4><b>9. člen</b></h4>
<p>10.1. Ta pogodba nadomešča vsa predhodna pogajanja, ponudbe in druge dogovore med
strankama.</p>
<p>10.2. Ta pogodba je sestavljena v [dveh] istovetnih izvodih, od katerih prejme vsaka stranka
po enega.</p>
<p>10.3. Pogodbeni stranki s podpisom potrjujeta veljavnost te pogodbe.</p>
</div>
<button id="button-submit-cancel" class="button-terms" style="background: #ff2d2d;">Prekliči</button>
<button id="button-submit-final" class="button-terms">Pošlji</button>
</div>
<!--{{ dropzone.load_js() }}-->
<script src="static/dropzone.js"></script>
<script>
/////////////////////////
// Dropzone //
/////////////////////////
var btnSubmit = document.getElementById("button-submit");
var btnSubmitFinal = document.getElementById("button-submit-final");
var btnSubmitCancel = document.getElementById("button-submit-cancel");
var elemTermsPopup = document.getElementById("popup-terms");
var termsScrollbox = document.getElementById("popup-terms-text");
var scrollboxTriggered = false;
var form = document.forms["my-dropzone"];
function isEmptyOrSpaces(str){
return str == null || str.match(/^ *$/) !== null;
}
const reEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
Dropzone.options.myDropzone = { // The camelized version of the ID of the form element
url: "/predavanja/upload",
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: {{max_files}},
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 1000, // MB
acceptedFiles: ".txt, .csv, .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx",
maxFiles: {{max_files}},
dictDefaultMessage: `Kliknite ali odložite datoteke sem.`,
dictFallbackMessage: "Vaš brskalnik ne podpira izbiranje datotek z odlaganjem (\"drag & drop\").",
dictInvalidFileType: "Datoteka je napačnega formata.",
dictFileTooBig: "Datoteke je prevelika {{filesize}}. Največja dovoljena velikost: {{maxFilesize}}MiB.",
dictResponseError: "Napaka strežnika: {{statusCode}}",
dictMaxFilesExceeded: "Največje število datotek že doseženo.",
dictCancelUpload: "Prekini prenos",
dictRemoveFile: "Odstrani datoteko",
dictCancelUploadConfirmation: "Ali res želite odstraniti to datoteko?",
dictUploadCanceled: "Prenos prekinjen",
// The setting up of the dropzone
init: function() {
var dz = this;
btnSubmit.addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
e.preventDefault();
e.stopPropagation();
// TODO: Check form validity.
// Then make terms popup visible
btnSubmit.disabled = true;
btnSubmitFinal.disabled = true;
elemTermsPopup.style.display = "inline";
scrollboxTriggered = false;
});
// First change the button to actually tell Dropzone to process the queue.
btnSubmitFinal.addEventListener("click", function(e) {
// Hand off data to dropzone
dz.processQueue();
// Clear fields and hide popup agian
btnSubmit.disabled = false;
elemTermsPopup.style.display = "none";
form.reset();
scrollboxTriggered = false;
});
btnSubmitCancel.addEventListener("click", function(e) {
btnSubmit.disabled = false;
scrollboxTriggered = false;
elemTermsPopup.style.display = "none";
});
// Enable final submit button only if user scrolls to the end of the terms.
function checkScrollboxTrigger(event) {
var element = event.target;
if (!scrollboxTriggered
&& element.scrollHeight - element.scrollTop <= element.clientHeight + 50
) {
scrollboxTriggered = true;
btnSubmitFinal.disabled = false;
}
}
termsScrollbox.addEventListener('scroll', function(event) {
checkScrollboxTrigger(event);
});
termsScrollbox.addEventListener("mouseenter", function(event) {
checkScrollboxTrigger(event);
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
this.on("successmultiple", function(files, response) {
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
alert("Odgovor strežnika: " + response);
location.reload();
});
this.on("errormultiple", function(files, response) {
// Gets triggered when there was an error sending the files.
// Maybe show form again, and notify user of error
});
}
}
</script>
</body>
</html>

View File

@ -2,38 +2,47 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal {{title}}</title>
<link rel="stylesheet" href="/static/style.css" type="text/css">
</head> </head>
<body> <body>
<div> <div id="main-window">
<h3>Login</h3> <div id="rect1">
<div> <div style="padding: 50px;">
{% with messages = get_flashed_messages() %} <div id="logo-container">
{% if messages %} <img src="/static/image/logo.svg" alt="logo"/>
<div>
{{ messages[0] }}
</div> </div>
{% endif %} <h3 id="title" style="font-size: 27px; text-align: left;">Prijava - {{title}}</h3>
{% endwith %}
<form method="POST" action="/{{corpus_name}}/login">
<div> <div>
<div> {% with messages = get_flashed_messages() %}
<input type="email" name="email" placeholder="Your Email" autofocus=""> {% if messages %}
</div> <div>
</div> {{ messages[0] }}
</div>
{% endif %}
{% endwith %}
<form method="POST" action="/{{corpus_name}}/login">
<div>
<div>
<input type="email" name="email" placeholder="Email" autofocus="">
</div>
</div>
<div> <div>
<div> <div>
<input type="password" name="password" placeholder="Your Password"> <input type="password" name="password" placeholder="Geslo">
</div> </div>
</div>
<div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
<label>Zapomni prijavo</label>
<input style="width: 10%;" type="checkbox">
</div>
<button class="button-general" style="margin-top: 20px;">PRIJAVA</button>
</form>
</div> </div>
<div> </div>
<label> </div>
<input type="checkbox"> <div id="rect2" class="mock-side">
Remember me
</label>
</div>
<button>Login</button>
</form>
</div> </div>
</div> </div>
</body> </body>

View File

@ -4,51 +4,35 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal za oddajanje besedil</title> <title>Portal za oddajanje besedil</title>
<!--{{ dropzone.load_css() }}--> <!--{{ dropzone.load_css() }}-->
<link rel="stylesheet" href="static/dropzone.css" type="text/css"> <link rel="stylesheet" href="/static/dropzone.css" type="text/css">
{{ dropzone.style('position: absolute; {{ dropzone.style('position: absolute;
top: -0.5px; top: -0.5px;
width: 388px; width: 388px;
height: 632px; height: 732px;
left: 385px; left: 385px;
background: linear-gradient(198.62deg, rgba(255, 255, 255, 0.49) -1.62%, rgba(255, 255, 255, 0.73) -1.61%, rgba(255, 255, 255, 0.41) 79.34%); background: linear-gradient(198.62deg, rgba(255, 255, 255, 0.49) -1.62%, rgba(255, 255, 255, 0.73) -1.61%, rgba(255, 255, 255, 0.41) 79.34%);
box-shadow: 20px 4px 40px rgba(0, 0, 0, 0.25); box-shadow: 20px 4px 40px rgba(0, 0, 0, 0.25);
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
border: 0px; border: 0px;
border-radius: 0px 20px 20px 0px;') }} border-radius: 0px 20px 20px 0px;') }}
<link rel="stylesheet" href="static/style.css" type="text/css"> <link rel="stylesheet" href="/static/style.css" type="text/css">
</head> </head>
<body> <body>
<div class="bg"></div> <div class="bg"></div>
<div id="main-window"> <div id="main-window">
<div id="rect1"> <div id="rect1">
<div id="logo-container"> <div id="logo-container">
<img src="static/image/logo.svg" alt="logo"/> <img src="/static/image/logo.svg" alt="logo"/>
</div> </div>
<form id="my-dropzone" class="dropzone"> <form id="my-dropzone" class="dropzone">
<div style="position: relative; right: 390px;"> <div style="position: relative; right: 390px;">
<h1 id="title">Korpus ŠOLAR</h1> <h1 id="title" style="font-size: 25px;">Korpus ŠOLAR</h1>
<!--<label for="ime">IME</label> <div class="selection-tabs">
<input type="text" id="ime" name="ime" required="required"/> <button class="selection-tab-button selected">ODDAJA</button>
<button class="selection-tab-button">ZGODOVINA</button>
<label for="institucija">INSTITUCIJA</label> <button class="selection-tab-button">POGODBE</button>
<input type="text" id="institucija" name="institucija"/> </div>
<label for="regija">REGIJA</label>
<select id="regija" name="regija">
<option value="CE" selected="selected">Celje (CE)</option>
<option value="GO">Nova Gorica (GO)</option>
<option value="KK">Krško (KK)</option>
<option value="KP">Koper (KP)</option>
<option value="KR">Kranj (KR)</option>
<option value="LJ">Ljubljana (LJ)</option>
<option value="MB">Maribor (MB)</option>
<option value="MS">Murska Sobota (MS)</option>
<option value="NM">Novo Mesto (NM)</option>
<option value="PO">Postojna (PO)</option>
<option value="SG">Slovenj Gradec (SG)</option>
</select>-->
<label for="program">PROGRAM</label> <label for="program">PROGRAM</label>
<select id="program" name="program"> <select id="program" name="program">
@ -71,6 +55,10 @@
<option value="drug-strok">Drugi strokovni predmeti</option> <option value="drug-strok">Drugi strokovni predmeti</option>
<option value="drug-izb">Drugi izbirni ali dodatni predmeti</option> <option value="drug-izb">Drugi izbirni ali dodatni predmeti</option>
</select> </select>
<div id="predmet-custom-box" style="display: none;">
<label for="predmet-custom">Ime predmeta:</label>
<input type="text" id="predmet-custom" name="predmet-custom"/>
</div>
<label for="letnik">LETNIK</label> <label for="letnik">LETNIK</label>
<select id="letnik" name="letnik"> <select id="letnik" name="letnik">
@ -92,6 +80,11 @@
<option value="solski-test">Šolski test</option> <option value="solski-test">Šolski test</option>
<option value="delo-v-razredu">Delo v razredu, ne za oceno</option> <option value="delo-v-razredu">Delo v razredu, ne za oceno</option>
</select> </select>
<div id="vrsta-custom-box" style="display: none;">
<label for="vrsta-custom">Vtipkajte besedilno vrsto:</label>
<input type="text" id="vrsta-custom" name="vrsta-custom"/>
</div>
<label for="solsko-leto">ŠOLSKO LETO</label> <label for="solsko-leto">ŠOLSKO LETO</label>
<select id="solsko-leto" name="solsko-leto"> <select id="solsko-leto" name="solsko-leto">
@ -222,11 +215,13 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
</div> </div>
<!--{{ dropzone.load_js() }}--> <!--{{ dropzone.load_js() }}-->
<script src="static/dropzone.js"></script> <script src="/static/dropzone.js"></script>
<script> <script>
///////////////////////// /////////////////////////
// Dropzone // // Dropzone //
///////////////////////// /////////////////////////
var selectPredmet = document.getElementById("predmet");
var selectVrsta = document.getElementById("vrsta");
var btnSubmit = document.getElementById("button-submit"); var btnSubmit = document.getElementById("button-submit");
var btnSubmitFinal = document.getElementById("button-submit-final"); var btnSubmitFinal = document.getElementById("button-submit-final");
var btnSubmitCancel = document.getElementById("button-submit-cancel"); var btnSubmitCancel = document.getElementById("button-submit-cancel");
@ -265,6 +260,23 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
init: function() { init: function() {
var dz = this; var dz = this;
selectPredmet.addEventListener("change", function(e) {
var predmetCustomBox = document.getElementById("predmet-custom-box");
if (selectPredmet.value.startsWith("drug")) {
predmetCustomBox.style.display = "inherit";
} else {
predmetCustomBox.style.display = "none";
}
});
selectVrsta.addEventListener("change", function(e) {
var vrstaCustomBox = document.getElementById("vrsta-custom-box");
if (selectVrsta.value == "delo-v-razredu") {
vrstaCustomBox.style.display = "inherit";
} else {
vrstaCustomBox.style.display = "none";
}
});
btnSubmit.addEventListener("click", function(e) { btnSubmit.addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent. // Make sure that the form isn't actually being sent.
@ -272,17 +284,19 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
e.stopPropagation(); e.stopPropagation();
// Check form validity. // Check form validity.
var ime = form["ime"].value; var program = form["program"].value;
var email = form["email"].value; var predmet = form["predmet"].value;
var podjetje = form["podjetje"].value; var predmetCustom = form["predmet-custom"].value;
var telefon = form["telefon"].value; var letnik = form["letnik"].value;
var izjava = form["izjava"].checked; var vrsta = form["vrsta"].value;
if (isEmptyOrSpaces(ime) || isEmptyOrSpaces(email) || !izjava) { var vrstaCustom = form["vrsta-custom"].value;
alert("Izpolnite vsa obvezna polja!"); var solskoLeto = form["solsko-leto"].value;
} else if (!reEmail.test(email.toLowerCase())) { var jezikovniPopravki = form["jezikovni-popravki"].value;
alert("Email napačnega formata!");
} else if (ime.length > 100 || email.length > 100 || podjetje.length > 100 || telefon.length > 100) { if (predmet.startsWith("drug") && isEmptyOrSpaces(predmetCustom)) {
alert("Velikost polj je omejena na 100 znakov."); alert("Polje za predmet ne more biti prazno!");
} else if (vrsta === "delo-v-razredu" && isEmptyOrSpaces(vrstaCustom)) {
alert("Polje za vrsto besedila ne more biti prazno!");
} else { } else {
// Then make terms popup visible // Then make terms popup visible
btnSubmit.disabled = true; btnSubmit.disabled = true;