Added predavanja, restructure, progress on solar.
This commit is contained in:
parent
51b1237b5f
commit
9acce4a8e9
|
@ -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
83
app.py
|
@ -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__':
|
||||||
|
|
|
@ -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
30
contract/predavanja.html
Normal 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>
|
|
@ -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 ###
|
||||||
|
|
|
@ -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 ###
|
||||||
|
|
256
portal/base.py
256
portal/base.py
|
@ -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)
|
||||||
|
|
||||||
|
@ -57,16 +65,25 @@ class UploadHandler:
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.config = kwargs
|
self.config = kwargs
|
||||||
|
|
||||||
self.contract_creator = ContractCreator()
|
def set_contract_creator(self, contract_creator):
|
||||||
|
assert isinstance(contract_creator, ContractCreator)
|
||||||
|
self._contract_creator = contract_creator
|
||||||
|
|
||||||
def extract_upload_metadata(self, corpus_name, request):
|
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
|
||||||
|
|
||||||
|
@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()
|
db.session.commit()
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
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()
|
|
||||||
except Exception:
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
|
@ -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
123
portal/predavanja.py
Normal 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
130
portal/regular.py
Normal 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
|
||||||
|
|
130
portal/solar.py
130
portal/solar.py
|
@ -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)
|
||||||
|
|
|
@ -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()),
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
294
templates/basic-predavanja.html
Normal file
294
templates/basic-predavanja.html
Normal 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>
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user