registration, charts, contracts history
This commit is contained in:
parent
540f54dd06
commit
7da73f7d6a
|
@ -13,6 +13,6 @@ WORKDIR /usr/src/portal-webapp
|
|||
RUN apt-get update && apt-get -y install wkhtmltopdf && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN pip3 install --no-cache-dir pdfkit flask==1.1.4 flask-dropzone flask-log-request-id flask-login Flask-SQLAlchemy alembic flask-migrate==2.7.0 Flask-script psycopg2 gunicorn pdfkit Werkzeug==1.0.1
|
||||
RUN pip3 install --no-cache-dir pdfkit flask==1.1.4 flask-dropzone flask-log-request-id flask-login Flask-SQLAlchemy alembic flask-migrate==2.7.0 Flask-script psycopg2 gunicorn pdfkit Werkzeug==1.0.1, PyJWT
|
||||
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
|
|
326
app.py
326
app.py
|
@ -5,7 +5,7 @@ import configparser
|
|||
from pathlib import Path
|
||||
from werkzeug.security import check_password_hash
|
||||
|
||||
from flask import Flask, render_template, request, redirect, flash, safe_join, send_file
|
||||
from flask import Flask, render_template, request, redirect, flash, safe_join, send_file, jsonify, url_for
|
||||
from flask_dropzone import Dropzone
|
||||
from flask_migrate import Migrate, MigrateCommand
|
||||
from flask_script import Manager
|
||||
|
@ -15,7 +15,6 @@ from portal.model import db, RegisteredUser
|
|||
import portal.base
|
||||
import portal.solar
|
||||
import portal.regular
|
||||
import portal.predavanja
|
||||
|
||||
|
||||
# TODO: Implement user registration.
|
||||
|
@ -44,12 +43,9 @@ MAX_FILES_PER_UPLOAD = int(config['MAX_FILES_PER_UPLOAD'])
|
|||
CONTRACT_CLIENT_CONTACT = config['CONTRACT_CLIENT_CONTACT']
|
||||
MAIL_SUBJECT = config['MAIL_SUBJECT']
|
||||
MAIL_BODY = config['MAIL_BODY']
|
||||
MAIL_SUBJECT_PREDAVANJA = config['MAIL_SUBJECT_PREDAVANJA']
|
||||
MAIL_BODY_PREDAVANJA = config['MAIL_BODY_PREDAVANJA']
|
||||
SQL_CONN_STR = config['SQL_CONN_STR']
|
||||
DESC_PREVODI = config['DESC_PREVODI']
|
||||
DESC_GIGAFIDA = config['DESC_GIGAFIDA']
|
||||
DESC_PREDAVANJA = config['DESC_PREDAVANJA']
|
||||
|
||||
if 'UPLOADS_DIR' in config:
|
||||
UPLOADS_DIR = Path(config['UPLOADS_DIR'])
|
||||
|
@ -83,10 +79,6 @@ if 'PORTALDS4DS1_MAIL_SUBJECT' in os.environ:
|
|||
MAIL_SUBJECT = os.environ['PORTALDS4DS1_MAIL_SUBJECT']
|
||||
if 'PORTALDS4DS1_MAIL_BODY' in os.environ:
|
||||
MAIL_BODY = os.environ['PORTALDS4DS1_MAIL_BODY']
|
||||
if 'PORTALDS4DS1_MAIL_SUBJECT_PREDAVANJA' in os.environ:
|
||||
MAIL_SUBJECT_PREDAVANJA = os.environ['PORTALDS4DS1_MAIL_SUBJECT_PREDAVANJA']
|
||||
if 'PORTALDS4DS1_MAIL_BODY_PREDAVANJA' in os.environ:
|
||||
MAIL_BODY_PREDAVANJA = os.environ['PORTALDS4DS1_MAIL_BODY_PREDAVANJA']
|
||||
if 'PORTALDS4DS1_SQL_CONN_STR' in os.environ:
|
||||
SQL_CONN_STR = os.environ['PORTALDS4DS1_SQL_CONN_STR']
|
||||
if 'PORTALDS4DS1_DESC_PREVODI' in os.environ:
|
||||
|
@ -94,7 +86,7 @@ if 'PORTALDS4DS1_DESC_PREVODI' in os.environ:
|
|||
if 'PORTALDS4DS1_DESC_GIGAFIDA' in os.environ:
|
||||
DESC_GIGAFIDA = os.environ['PORTALDS4DS1_DESC_GIGAFIDA']
|
||||
|
||||
ENABLED_CORPUSES = ['prevodi', 'gigafida', 'solar', 'predavanja']
|
||||
ENABLED_CORPUSES = ['prevodi', 'gigafida', 'solar']
|
||||
CORPUSES_LOGIN_REQUIRED = ['solar']
|
||||
|
||||
|
||||
|
@ -147,25 +139,18 @@ upload_handler_solar = portal.solar.UploadHandlerSolar(
|
|||
MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD
|
||||
)
|
||||
|
||||
upload_handler_predavanja = portal.predavanja.UploadHandlerPredavanja(
|
||||
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_PREDAVANJA,
|
||||
MAIL_BODY=MAIL_BODY_PREDAVANJA,
|
||||
CONTRACT_CLIENT_CONTACT=CONTRACT_CLIENT_CONTACT,
|
||||
MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD
|
||||
)
|
||||
|
||||
|
||||
# Use flask-login to manage user sessions where they are required.
|
||||
login_manager = LoginManager(app)
|
||||
login_manager.init_app(app)
|
||||
|
||||
|
||||
def redirect_url(default='/'):
|
||||
return request.args.get('next') or \
|
||||
request.referrer or \
|
||||
url_for(default)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
@ -180,8 +165,6 @@ def index_corpus(corpus_name):
|
|||
description = DESC_PREVODI
|
||||
elif corpus_name == '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':
|
||||
if current_user.is_authenticated:
|
||||
return redirect('/solar/oddaja')
|
||||
|
@ -198,15 +181,17 @@ def load_user(user_id):
|
|||
|
||||
|
||||
@app.route('/solar/login')
|
||||
def login_get():
|
||||
return render_template('login.html', corpus_name='solar', title='ŠOLAR')
|
||||
def solar_login_get():
|
||||
return render_template('solar-login.html')
|
||||
|
||||
|
||||
@app.route('/<corpus_name>/login', methods=['POST'])
|
||||
def login_post(corpus_name):
|
||||
if corpus_name not in ENABLED_CORPUSES or corpus_name not in CORPUSES_LOGIN_REQUIRED:
|
||||
return '', 404
|
||||
@app.route('/solar/register')
|
||||
def solar_register_get():
|
||||
return render_template('solar-register.html')
|
||||
|
||||
|
||||
@app.route('/solar/login', methods=['POST'])
|
||||
def solar_login_post():
|
||||
email = request.form.get('email')
|
||||
password = request.form.get('password')
|
||||
remember = True if request.form.get('remember') else False
|
||||
|
@ -215,23 +200,59 @@ def login_post(corpus_name):
|
|||
|
||||
if not user or not check_password_hash(user.pass_hash, password):
|
||||
flash('Napačni podatki za prijavo. Poskusite ponovno.')
|
||||
return redirect('/{}/login'.format(corpus_name))
|
||||
return redirect('/solar/login')
|
||||
|
||||
if not user.active:
|
||||
flash('Vaš uporabniški račun še ni bil aktiviran.')
|
||||
return redirect('/{}/login'.format(corpus_name))
|
||||
|
||||
# Check if user is authorized to log into this corpus. Admins are an exception.
|
||||
if not portal.base.has_user_corpus_access(user.id, corpus_name):
|
||||
flash('Nimate dostopa do tega korpusa.')
|
||||
return redirect('/{}/login'.format(corpus_name))
|
||||
return redirect('/solar/login')
|
||||
|
||||
#portal.base.add_user_session(user.id)
|
||||
login_user(user, remember=remember)
|
||||
|
||||
if corpus_name == 'solar':
|
||||
return redirect('/solar/oddaja')
|
||||
return '', 404
|
||||
return redirect('/solar/oddaja')
|
||||
|
||||
|
||||
@app.route('/solar/register', methods=['POST'])
|
||||
def solar_register_post():
|
||||
name = request.form.get('name')
|
||||
email = request.form.get('email')
|
||||
password = request.form.get('password')
|
||||
|
||||
user = RegisteredUser.query.filter_by(email=email).first()
|
||||
|
||||
if user:
|
||||
flash('Uporabniški račun s tem emailom je že registriran.')
|
||||
return redirect('/solar/register')
|
||||
|
||||
if not name:
|
||||
flash('Prazno polje za ime.')
|
||||
return redirect('/solar/register')
|
||||
if len(name) > 100:
|
||||
flash('Predolgo ime.')
|
||||
return redirect('/solar/register')
|
||||
|
||||
if not email:
|
||||
flash('Prazno polje za elektronsko pošto.')
|
||||
return redirect('/solar/register')
|
||||
if len(email) > 100:
|
||||
flash('Predolgi email naslov')
|
||||
return redirect('/solar/register')
|
||||
elif not re.search(portal.base.REGEX_EMAIL, email):
|
||||
flash('Email napačnega formata.')
|
||||
return redirect('/solar/register')
|
||||
|
||||
if not password:
|
||||
flash('Prazno polje za geslo.')
|
||||
return redirect('/solar/register')
|
||||
if len(password) > 100:
|
||||
flash('Predolgo geslo.')
|
||||
return redirect('/solar/register')
|
||||
|
||||
portal.base.register_new_user(name, email, password, active=False)
|
||||
|
||||
flash('Uspešna registracija.')
|
||||
return redirect('/solar/login')
|
||||
|
||||
|
||||
|
||||
# TODO: Move solar stuff to seperate file using Flask blueprints.
|
||||
|
@ -247,10 +268,15 @@ def logout():
|
|||
@app.route('/solar/<path:text>')
|
||||
@login_required
|
||||
def solar(text):
|
||||
if not portal.base.has_user_corpus_access(current_user.id, 'solar'):
|
||||
return '', 404
|
||||
is_admin = current_user.role == 'admin'
|
||||
current_user_institution = portal.base.get_user_institution(current_user.id)
|
||||
if current_user_institution:
|
||||
current_user_institution_moderator = portal.base.is_institution_moderator(current_user.id, current_user_institution.id)
|
||||
else:
|
||||
current_user_institution_moderator = False
|
||||
|
||||
if text.startswith('oddaja/') or text == 'oddaja':
|
||||
return render_template('solar-oddaja.html')
|
||||
return render_template('solar-oddaja.html', is_admin=is_admin, is_institution_moderator=current_user_institution_moderator)
|
||||
elif text.startswith('zgodovina/') or text == 'zgodovina':
|
||||
upload_items = portal.solar.get_upload_history(current_user.id)
|
||||
uploader_names = []
|
||||
|
@ -263,7 +289,7 @@ def solar(text):
|
|||
else:
|
||||
institution_names.append(institution.name)
|
||||
return render_template('solar-zgodovina.html', upload_history=upload_items, uploader_names=uploader_names,
|
||||
institution_names=institution_names)
|
||||
institution_names=institution_names, is_admin=is_admin, is_institution_moderator=current_user_institution_moderator)
|
||||
elif text.startswith('pogodbe/') or text == 'pogodbe':
|
||||
# Check for ownload contract request.
|
||||
match = re.match('^pogodbe/([a-z0-9_]+\.pdf)$', text)
|
||||
|
@ -281,72 +307,154 @@ def solar(text):
|
|||
return '', 404
|
||||
|
||||
user_obj = portal.base.get_user_obj(current_user.get_id())
|
||||
institutions = portal.base.get_user_institutions(user_obj.id)
|
||||
institution = portal.base.get_user_institution(user_obj.id)
|
||||
contracts_students = []
|
||||
contract_school = []
|
||||
enable_upload_school_contract = False
|
||||
show_upload_form = False
|
||||
if len(institutions) > 0:
|
||||
collaborators = []
|
||||
if institution:
|
||||
collaborators = portal.base.get_all_active_institution_users(institution.id)
|
||||
show_upload_form = True
|
||||
institution = portal.base.get_user_institutions(user_obj.id)[0]
|
||||
contracts_students = portal.solar.get_institution_student_contracts(institution.id)
|
||||
contract_school = portal.solar.get_institution_contract(institution.id)
|
||||
|
||||
if portal.base.is_institution_moderator(user_obj.id, institution.id):
|
||||
contracts_students = portal.solar.get_institution_student_contracts(institution.id)
|
||||
enable_upload_school_contract = True
|
||||
else:
|
||||
contracts_students = portal.solar.get_institution_student_contracts(institution.id, user_obj.id)
|
||||
|
||||
return render_template('solar-pogodbe.html', contracts_students=contracts_students,
|
||||
contract_school=contract_school,
|
||||
enable_upload_school_contract=enable_upload_school_contract,
|
||||
show_upload_form=show_upload_form)
|
||||
show_upload_form=show_upload_form,
|
||||
collaborators=collaborators,
|
||||
is_admin=is_admin, is_institution_moderator=current_user_institution_moderator)
|
||||
elif text.startswith('admin/') or text == 'admin':
|
||||
solar_users = portal.base.get_all_active_users()
|
||||
users = portal.base.get_all_active_users_join_institutions()
|
||||
inactive_users = portal.base.get_all_inactive_users()
|
||||
solar_institutions = portal.solar.get_all_institutions()
|
||||
if current_user.role == 'admin':
|
||||
return render_template('solar-admin.html', users=solar_users, institutions=solar_institutions)
|
||||
if is_admin:
|
||||
return render_template('solar-admin.html', users=users,
|
||||
institutions=solar_institutions, inactive_users=inactive_users)
|
||||
elif text.startswith('manage-institution/') or text == 'manage-institution':
|
||||
institution = portal.base.get_user_institution(current_user.id)
|
||||
if portal.base.is_institution_moderator(current_user.id, institution.id):
|
||||
solar_users = portal.base.get_all_active_users()
|
||||
institution_users = portal.base.get_all_active_institution_users(institution.id)
|
||||
return render_template('solar-manage-institution.html', users=solar_users,
|
||||
institution_users=institution_users)
|
||||
return '', 404
|
||||
|
||||
@app.route('/solar/pogodbe', methods=['POST'])
|
||||
@login_required
|
||||
def solar_upload_contract():
|
||||
if not portal.base.has_user_corpus_access(current_user.id, 'solar'):
|
||||
return '', 404
|
||||
|
||||
return upload_handler_solar.handle_contract_upload(request, current_user.get_id())
|
||||
|
||||
|
||||
@app.route('/<corpus_name>/adduser', methods=['POST'])
|
||||
@app.route('/solar/adduser', methods=['POST'])
|
||||
@login_required
|
||||
def solar_add_user(corpus_name):
|
||||
def solar_add_user():
|
||||
|
||||
if not portal.base.is_admin(current_user.id):
|
||||
return '', 404
|
||||
if not corpus_name in ENABLED_CORPUSES:
|
||||
return '', 404
|
||||
|
||||
name = request.form['name']
|
||||
email = request.form['email']
|
||||
password = request.form['password']
|
||||
name = request.form.get('name')
|
||||
email = request.form.get('email')
|
||||
password = request.form.get('password')
|
||||
|
||||
if not name:
|
||||
return 'Prazno polje za ime.'
|
||||
flash('Prazno polje za ime.')
|
||||
return redirect(redirect_url())
|
||||
if len(name) > 100:
|
||||
return 'Predolgo ime.'
|
||||
flash('Predolgo ime.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
if not email:
|
||||
return 'Prazno polje za elektronsko pošto.'
|
||||
flash('Prazno polje za elektronsko pošto.')
|
||||
return redirect(redirect_url())
|
||||
if len(email) > 100:
|
||||
return 'Predolgi email naslov'
|
||||
flash('Predolg email naslov.')
|
||||
return redirect(redirect_url())
|
||||
elif not re.search(portal.base.REGEX_EMAIL, email):
|
||||
return 'Email napačnega formata.'
|
||||
flash('Email napačnega formata.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
if not password:
|
||||
return 'Prazno polje za geslo.'
|
||||
flash('Prazno polje za geslo.')
|
||||
return redirect(redirect_url())
|
||||
if len(password) > 100:
|
||||
return 'Predolgo geslo.'
|
||||
flash('Predolgo geslo.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
portal.base.register_new_user(name, email, password)
|
||||
|
||||
return 'Uporabnik je bil dodan.'
|
||||
flash('Uporabnik je bil uspešno dodan.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
|
||||
@app.route('/solar/activateuser', methods=['POST'])
|
||||
@login_required
|
||||
def solar_activate_user():
|
||||
if not portal.base.is_admin(current_user.id):
|
||||
return '', 404
|
||||
|
||||
user_id = request.form.get('id')
|
||||
if not user_id:
|
||||
flash('Prazno polje za ID uporabnika.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
rowcount = portal.base.activate_user(user_id)
|
||||
if rowcount == 0:
|
||||
return '', 404
|
||||
|
||||
flash('Uporabnik je bil aktiviran.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
|
||||
@app.route('/solar/forgotpass')
|
||||
def solar_forgotpass():
|
||||
return render_template('solar-forgotpass.html')
|
||||
|
||||
|
||||
@app.route('/solar/sendresetpass', methods=['POST'])
|
||||
def solar_sendresetpass():
|
||||
email = request.form.get('email')
|
||||
|
||||
portal.base.send_resetpass_mail(email, upload_handler_regular.config)
|
||||
|
||||
flash('Povezava za ponastavitev gesla je bila poslana na vpisan email naslov.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
|
||||
@app.route('/solar/resetpass/<token>')
|
||||
def solar_resetpass(token):
|
||||
user = portal.base.verify_reset_token(token)
|
||||
|
||||
if not user:
|
||||
return '', 404
|
||||
|
||||
return render_template('solar-resetpass.html', user=user, token=token)
|
||||
|
||||
|
||||
@app.route('/solar/resetpass/<token>', methods=['POST'])
|
||||
def solar_resetpass_post(token):
|
||||
new_password = request.form.get('new_password')
|
||||
user = portal.base.verify_reset_token(token)
|
||||
|
||||
if not user:
|
||||
return '', 404
|
||||
|
||||
rowcount = portal.base.update_user_password(user.id, new_password)
|
||||
if rowcount == 0:
|
||||
return '', 404
|
||||
|
||||
return 'Ponastavitev gesla uspešna.'
|
||||
|
||||
|
||||
@app.route('/solar/topuploads')
|
||||
@login_required
|
||||
def solar_topuploads_srednje():
|
||||
return jsonify(portal.solar.get_top_uploading_institutions())
|
||||
|
||||
|
||||
@app.route('/solar/deluser', methods=['POST'])
|
||||
|
@ -364,44 +472,76 @@ def add_institution(corpus_name):
|
|||
if not corpus_name in ENABLED_CORPUSES:
|
||||
return '', 404
|
||||
|
||||
name = request.form['name']
|
||||
region = request.form['region']
|
||||
name = request.form.get('name')
|
||||
region = request.form.get('region')
|
||||
|
||||
if not name:
|
||||
return 'Prazno polje za ime.'
|
||||
flash('Prazno polje za ime.')
|
||||
return redirect(redirect_url())
|
||||
if len(name) > 100:
|
||||
return 'Predolgo ime.'
|
||||
flash('Predolgo ime.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
if not region:
|
||||
return 'Prazno polje za regijo.'
|
||||
flash('Prazno polje za regijo.')
|
||||
return redirect(redirect_url())
|
||||
if len(region) > 100:
|
||||
return 'Predolgi niz za regijo.'
|
||||
flash('Predolgi niz za regijo.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
institution_id = portal.base.add_institution(name, region)
|
||||
portal.base.grant_institution_corpus_access(institution_id, corpus_name)
|
||||
return 'Institucija je bila dodana.'
|
||||
flash('Institucija je bila dodana.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
@app.route('/<corpus_name>/addusertoinstitution', methods=['POST'])
|
||||
@login_required
|
||||
def add_user_institution_mapping(corpus_name):
|
||||
if not portal.base.is_admin(current_user.id):
|
||||
if not corpus_name in ENABLED_CORPUSES:
|
||||
return '', 404
|
||||
|
||||
institution_id = request.form.get('institution_id')
|
||||
if not institution_id:
|
||||
institution = portal.base.get_user_institution(current_user.id)
|
||||
if institution:
|
||||
institution_id = institution.id
|
||||
|
||||
if not (portal.base.is_admin(current_user.id) or portal.base.is_institution_moderator(current_user.id, institution_id)):
|
||||
return '', 404
|
||||
|
||||
user_id = request.form['user_id']
|
||||
role = request.form['role']
|
||||
if role not in ['moderator', 'user']:
|
||||
return '', 404
|
||||
|
||||
if portal.base.get_user_institution(user_id):
|
||||
flash('Uporabnik je že dodeljen instituciji. Dodeljevanje večim institucijam '\
|
||||
'zaenkrat ni implementirano.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
portal.base.add_user_to_institution(user_id, institution_id, role)
|
||||
flash('Uporabnik je bil dodeljen instituciji.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
@app.route('/<corpus_name>/deluserfrominstitution', methods=['POST'])
|
||||
@login_required
|
||||
def del_user_institution_mapping(corpus_name):
|
||||
institution = portal.base.get_user_institution(current_user.id)
|
||||
if not portal.base.is_admin(current_user.id) \
|
||||
and not portal.base.is_institution_moderator(current_user.id, institution.id):
|
||||
return '', 404
|
||||
if not corpus_name in ENABLED_CORPUSES:
|
||||
return '', 404
|
||||
|
||||
user_id = request.form['user_id']
|
||||
institution_id = request.form['institution_id']
|
||||
role = request.form['role']
|
||||
if role not in ['moderator', 'user']:
|
||||
return '', 404
|
||||
|
||||
# TODO: remove this restriction
|
||||
if len(portal.base.get_user_institutions(user_id)) > 0:
|
||||
return 'Uporabnik je že dodeljen instituciji. Dodeljevanje večim institucijam '\
|
||||
'zaenkrat ni implementirano.'
|
||||
if not portal.base.is_institution_member(user_id, institution.id):
|
||||
flash('Uporabnik ni član vaše institucije.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
portal.base.add_user_to_institution(user_id, institution_id, role)
|
||||
return 'Uporabnik je bil dodeljen instituciji.'
|
||||
portal.base.del_user_from_institution(user_id, institution.id)
|
||||
flash('Uporabnik je bil odstranjen iz institucije.')
|
||||
return redirect(redirect_url())
|
||||
|
||||
@app.route('/<corpus_name>/delinstitution', methods=['POST'])
|
||||
@login_required
|
||||
|
@ -420,11 +560,9 @@ def handle_upload(corpus_name):
|
|||
if corpus_name == 'solar':
|
||||
if not current_user.is_authenticated:
|
||||
return '', 404
|
||||
if not portal.base.has_user_corpus_access(current_user.id, corpus_name):
|
||||
return '', 404
|
||||
#if not portal.base.has_user_corpus_access(current_user.id, corpus_name):
|
||||
# return '', 404
|
||||
return upload_handler_solar.handle_upload(request, current_user.get_id())
|
||||
elif corpus_name == 'predavanja':
|
||||
return upload_handler_predavanja.handle_upload(request)
|
||||
else:
|
||||
return upload_handler_regular.handle_upload(request, corpus_name)
|
||||
|
||||
|
|
|
@ -12,17 +12,9 @@ UPLOADS_DIR=./uploads
|
|||
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_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_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.
|
||||
|
||||
|
||||
Lep pozdrav,
|
||||
ekipa RSDO
|
||||
MAIL_SUBJECT_PREDAVANJA=Projekt ON ({upload_id})
|
||||
MAIL_BODY_PREDAVANJA=Spoštovani,
|
||||
|
||||
sodelavci projekta ON se vam zahvaljujemo za prispevek in sodelovanje. Morebitna vprašanja pošljite na naslov predavajalnik@cjvt.si.
|
||||
|
||||
Hvala in lep pozdrav,
|
||||
ekipa CJVT UL
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import os
|
||||
import hashlib
|
||||
import time
|
||||
import ssl
|
||||
|
@ -20,6 +21,8 @@ from email.mime.application import MIMEApplication
|
|||
import pdfkit
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
import jwt
|
||||
|
||||
from werkzeug.security import generate_password_hash
|
||||
|
||||
from . model import db, UploadRegular, UploadSolar, RegisteredUser, UserInstitutionMapping, Institution, InstitutionContract, CorpusAccess
|
||||
|
@ -238,8 +241,11 @@ class UploadHandler:
|
|||
return None
|
||||
|
||||
|
||||
def get_user_institutions(user_id):
|
||||
return UserInstitutionMapping.query.filter_by(user=user_id).all()
|
||||
def get_user_institution(user_id):
|
||||
mapping = UserInstitutionMapping.query.filter_by(user=user_id).first()
|
||||
if mapping:
|
||||
return Institution.query.filter_by(id=mapping.institution).first()
|
||||
return None
|
||||
|
||||
|
||||
def has_user_corpus_access(user_id, corpus_name):
|
||||
|
@ -252,13 +258,11 @@ def has_user_corpus_access(user_id, corpus_name):
|
|||
return True
|
||||
|
||||
# Check if user belongs to an institution, that has access to this corpus.
|
||||
institutions = get_user_institutions(user_id)
|
||||
institution = get_user_institution(user_id)
|
||||
has_access = False
|
||||
for institution in institutions:
|
||||
row = CorpusAccess.query.filter_by(institution=institution.id, corpus=corpus_name).first()
|
||||
if row:
|
||||
has_access = True
|
||||
break
|
||||
row = CorpusAccess.query.filter_by(institution=institution.id, corpus=corpus_name).first()
|
||||
if row:
|
||||
has_access = True
|
||||
return has_access
|
||||
|
||||
|
||||
|
@ -322,15 +326,86 @@ def add_user_to_institution(user_id, institution_id, role):
|
|||
return model_obj.id
|
||||
|
||||
|
||||
def activate_user(user_id):
|
||||
rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'active': True})
|
||||
db.session.commit()
|
||||
return rowcount
|
||||
|
||||
|
||||
def update_user_password(user_id, new_password):
|
||||
phash = generate_password_hash(new_password)
|
||||
rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'pass_hash': pass_hash})
|
||||
db.session.commit()
|
||||
return rowcount
|
||||
|
||||
|
||||
def del_user_from_institution(user_id, institution_id):
|
||||
db.session.query(UserInstitutionMapping).filter(UserInstitutionMapping.institution == institution_id).filter(UserInstitutionMapping.user == user_id).delete()
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_all_active_users():
|
||||
return RegisteredUser.query.filter_by(active=True).all()
|
||||
return RegisteredUser.query.filter_by(active=True).order_by(RegisteredUser.id).all()
|
||||
|
||||
def get_all_inactive_users():
|
||||
return RegisteredUser.query.filter_by(active=False).order_by(RegisteredUser.id).all()
|
||||
|
||||
def get_all_active_users_join_institutions():
|
||||
#return RegisteredUser.query.filter_by(active=True).order_by(RegisteredUser.id).all()
|
||||
return db.session.query(RegisteredUser, UserInstitutionMapping).outerjoin(UserInstitutionMapping,
|
||||
RegisteredUser.id == UserInstitutionMapping.user).order_by(RegisteredUser.id).all()
|
||||
|
||||
def get_all_active_institution_users(institution_id):
|
||||
return RegisteredUser.query.filter_by(active=True).join(UserInstitutionMapping,
|
||||
RegisteredUser.id == UserInstitutionMapping.user).filter(UserInstitutionMapping.institution == institution_id).all()
|
||||
|
||||
|
||||
def is_institution_moderator(user_id, institution_id):
|
||||
user_inst_mapping = UserInstitutionMapping.query.filter_by(user=user_id).first()
|
||||
user_inst_mapping = UserInstitutionMapping.query.filter_by(user=user_id).filter_by(institution=institution_id).first()
|
||||
if not user_inst_mapping:
|
||||
return False
|
||||
if user_inst_mapping.role != 'moderator':
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_institution_member(user_id, institution_id):
|
||||
user_inst_mapping = UserInstitutionMapping.query.filter_by(user=user_id).filter_by(institution=institution_id).first()
|
||||
if not user_inst_mapping:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_password_reset_token(email, expires=500):
|
||||
return jwt.encode({'reset_password': email,
|
||||
'exp': time() + expires},
|
||||
key=os.getenv('APP_SECRET_KEY'), algorithm='HS256')
|
||||
|
||||
def verify_reset_token(token):
|
||||
try:
|
||||
email = jwt.decode(token,
|
||||
key=os.getenv('APP_SECRET_KEY'), algorithms=["HS256"])['reset_password']
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
return
|
||||
return RegisteredUser.query.filter_by(email=email).first()
|
||||
|
||||
|
||||
def send_resetpass_mail(email, config):
|
||||
jwt_token = get_password_reset_token(email)
|
||||
|
||||
text = '''
|
||||
Zahtevali ste ponastavitev gesla vašega uporabniškega računa.
|
||||
|
||||
Geslo lahko ponastavite na naslednji povezavi: https://zbiranje.slovenscina.eu/solar/resetpass/{}'''.format(
|
||||
'https://zbiranje.slovenscina.eu/solar/resetpass/{}'.format(jwt_token))
|
||||
|
||||
# Create a secure SSL context
|
||||
context = ssl.create_default_context()
|
||||
|
||||
try:
|
||||
with SMTP_SSL(config['MAIL_HOST'], config['SMTP_PORT'], context=context) as server:
|
||||
server.login(config['MAIL_LOGIN'], config['MAIL_PASS'])
|
||||
server.sendmail(config['MAIL_LOGIN'], email, text)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
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):
|
||||
|
||||
ENABLED_FILETYPES = None # None means all filetypes
|
||||
|
||||
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()
|
||||
|
||||
# Normalize keywords list
|
||||
keywords_list = []
|
||||
for keyword in form_data['kljucne-besede'].split(','):
|
||||
keyword = keyword.strip()
|
||||
keywords_list.append(keyword)
|
||||
keywords = ','.join(keywords_list)
|
||||
|
||||
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=keywords,
|
||||
agree_publish_future=form_data['javna-objava-prihodnost'],
|
||||
agree_machine_translation=True if 'strojno-prevajanje' in form_data else False,
|
||||
agree_news_cjvt=True if 'obvestila' 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'])))
|
||||
|
||||
# Store uploaded files to disk.
|
||||
self.store_datafiles(request.files, upload_metadata)
|
||||
|
||||
# Store metadata to database.
|
||||
self.store_metadata(upload_metadata)
|
||||
|
||||
# Send confirmation mail
|
||||
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')
|
||||
agree_publish_future = form.get('javna-objava-prihodnost')
|
||||
|
||||
if not agree_publish_future:
|
||||
return 'Manjkajoča izbrana vrednost pri polju za javno objavo.'
|
||||
|
||||
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(','):
|
||||
# keyword = keyword.strip()
|
||||
# if keyword.isspace() or not keyword.replace(' ', '').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 key == 'kljucne-besde':
|
||||
if len(val) > 500:
|
||||
return 'Polje "{}" presega dolžino {} znakov.'.format(key, 500)
|
||||
else:
|
||||
if len(val) > MAXLEN_FORM:
|
||||
return 'Polje "{}" presega dolžino {} znakov.'.format(key, MAXLEN_FORM)
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
import logging
|
||||
import re
|
||||
import traceback
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from sqlalchemy import desc, exists
|
||||
from sqlalchemy import desc
|
||||
from collections import Counter
|
||||
|
||||
from portal.base import UploadHandler, get_user_institutions, has_user_corpus_access
|
||||
from portal.model import db, UploadSolar, ContractsSolar, RegisteredUser, Institution, InstitutionContract, UserInstitutionMapping, CorpusAccess
|
||||
from portal.base import UploadHandler, get_user_institution, has_user_corpus_access
|
||||
from portal.model import UploadSolar, ContractsSolar, RegisteredUser, Institution, InstitutionContract, UserInstitutionMapping, CorpusAccess
|
||||
|
||||
|
||||
VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'}
|
||||
|
@ -27,8 +27,7 @@ class UploadHandlerSolar(UploadHandler):
|
|||
sorted_f_hashes = list(file_hashes.values())
|
||||
sorted_f_hashes.sort()
|
||||
|
||||
# If user is mapped to multiple institutions, let him chose in name of which one he makes the upload.
|
||||
institution_id = get_user_institutions(user_id)[0].id
|
||||
institution_id = get_user_institution(user_id).id
|
||||
|
||||
model_obj = UploadSolar(
|
||||
upload_user = user_id,
|
||||
|
@ -147,7 +146,7 @@ class UploadHandlerSolar(UploadHandler):
|
|||
if program not in VALID_PROGRAMS:
|
||||
return 'Invalid program "{}"'.format(program)
|
||||
if predmet not in VALID_SUBJECTS:
|
||||
return 'Invalid subject "{}"'.format(premdet)
|
||||
return 'Invalid subject "{}"'.format(predmet)
|
||||
if letnik < 1 or letnik > 9:
|
||||
return 'Invalid grade: {}'.format(letnik)
|
||||
if vrsta not in VALID_TEXT_TYPES:
|
||||
|
@ -176,14 +175,30 @@ def get_all_institutions():
|
|||
return res
|
||||
|
||||
|
||||
def get_institution_student_contracts(institution_id):
|
||||
return ContractsSolar.query.filter_by(institution=institution_id, contract_type='ucenci-starsi').all()
|
||||
def get_institution_student_contracts(institution_id, user_id=None):
|
||||
if not user_id:
|
||||
return ContractsSolar.query.filter_by(institution=institution_id, contract_type='ucenci-starsi').all()
|
||||
return ContractsSolar.query.filter_by(institution=institution_id, contract_type='ucenci-starsi', upload_user=user_id).all()
|
||||
|
||||
|
||||
def get_institution_contract(institution_id):
|
||||
return InstitutionContract.query.filter_by(institution=institution_id, corpus='solar').order_by(desc(InstitutionContract.timestamp)).first()
|
||||
|
||||
|
||||
def get_top_uploading_institutions():
|
||||
res = dict()
|
||||
institutions = get_all_institutions()
|
||||
for institution in institutions:
|
||||
uploads = UploadSolar.query.filter_by(institution=institution.id).all()
|
||||
for upload in uploads:
|
||||
if institution.name not in res:
|
||||
res[institution.name] = 0
|
||||
res[institution.name] += len(upload.upload_file_hashes)
|
||||
if len(res) >= 5:
|
||||
return dict(sorted(res.items(), key=lambda x:x[1], reverse=True)[:5])
|
||||
return dict(sorted(res.items(), key=lambda x:x[1], reverse=True))
|
||||
|
||||
|
||||
def get_all_active_users():
|
||||
# TODO: do filtering purely within an SQL query
|
||||
res = []
|
||||
|
|
13222
static/chart.js
Normal file
13222
static/chart.js
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -119,6 +119,89 @@ label {
|
|||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.container-title {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
line-height: 14px;
|
||||
color: #46535b;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
#history-container {
|
||||
height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#contract-container {
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.contract-item {
|
||||
height: 50px;
|
||||
margin: 5px;
|
||||
border: 0px;
|
||||
border-bottom: 2px solid #c4c4c4;
|
||||
}
|
||||
|
||||
.contract-item-title {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
color: #46535b;
|
||||
}
|
||||
|
||||
.contract-item-button {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.contract-item-date {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 10px;
|
||||
color: #46535b;
|
||||
}
|
||||
|
||||
#collaborators-container {
|
||||
height: 370px;
|
||||
background: #f5f5f5;
|
||||
margin: 25px;
|
||||
padding:5px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.collaborators-item {
|
||||
height: 30px;
|
||||
margin: 5px;
|
||||
border: 0px;
|
||||
border-bottom: 2px solid #c4c4c4;
|
||||
}
|
||||
|
||||
.collaborators-item-name {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
color: #46535b;
|
||||
}
|
||||
|
||||
#awards-container {
|
||||
height: 250px;
|
||||
background: #f5f5f5;
|
||||
margin: 25px;
|
||||
padding:5px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#button-submit {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
@ -1,199 +0,0 @@
|
|||
<!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: 831px;
|
||||
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" style="top: 45%;">
|
||||
<div id="rect1" style="height: 831px;">
|
||||
<div id="logo-container" style="top: -7.8%;">
|
||||
<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">* Članica:</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 (ločene z vejico):</label>
|
||||
<input type="text" id="kljucne-besede" name="kljucne-besede" required="required"/>
|
||||
|
||||
<br>
|
||||
<div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
|
||||
<label style="width: 95%; text-transform: none; font-size: 12px;"><b>*Privolitev:</b><br>Strinjam se, da Univerza v Ljubljani uporabi posnetek naloženega predavanja v okviru projekta za strojno prevajanje predavanj ON. Dostop do posnetka bodo imeli izključno sodelavci projekta za namen transkripcije govora.</label>
|
||||
<input style="width: 5%;" type="checkbox" name="strojno-prevajanje" value="strojno-prevajanje">
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: row; justify-content: left; align-items: center; width: 310px;">
|
||||
<label style="text-transform: none; font-size: 12px;"><b>Objava posnetka na portalu ON:</b><br>Ali bi se v prihodnosti strinjali z objavo posnetka na portalu sistema ON? (V primeru strinjanja bi podpisali poseben dogovor o pogojih objave.)</label>
|
||||
<div style="display: inline-block;">
|
||||
<input type="radio" name="javna-objava-prihodnost" value="da" style="display: inline; float: left; width: 20px;" >
|
||||
<label for="da" style="display: inline; float: right; position: absolute; margin-top: 5px;">Da</label><br>
|
||||
<input type="radio" name="javna-objava-prihodnost" value="morda" style="display: inline; float: left; width: 20px;">
|
||||
<label for="morda" style="display: inline; float: right; position: absolute; margin-top: 10px;">Morda</label><br>
|
||||
<input type="radio" name="javna-objava-prihodnost" value="ne" style="display: inline; float: left; width: 20px;">
|
||||
<label for="ne" style="display: inline; float: right; position: absolute; margin-top: 18px;">Ne</label><br>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
|
||||
<label style="width: 95%; text-transform: none; font-size: 12px;"><b>Obvestila:</b><br>Želim, da me Center za jezikovne vire in tehnologije UL obvešča o novicah v zvezi s sistemom za strojno prevajanje predavanj ON.</label>
|
||||
<input style="width: 5%;" type="checkbox" name="obvestila" value="obvestila">
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<a class="form-text" href="https://www.cjvt.si/obvestilo-o-obdelavi-osebnih-podatkov/" style="cursor: pointer;">Obvestilo o obdelavi osebnih podatkov</a>
|
||||
|
||||
<button id="button-submit" type="submit" style="top: 745px;">Oddaj</button>
|
||||
</div>
|
||||
|
||||
<div class="dropzone-previews"></div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--{{ dropzone.load_js() }}-->
|
||||
<script src="/static/dropzone.js"></script>
|
||||
<script>
|
||||
/////////////////////////
|
||||
// Dropzone //
|
||||
/////////////////////////
|
||||
var btnSubmit = document.getElementById("button-submit");
|
||||
var form = document.forms["my-dropzone"];
|
||||
|
||||
function isEmptyOrSpaces(str){
|
||||
return str == null || str.match(/^ *$/) !== null;
|
||||
}
|
||||
|
||||
const reEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
//const reKeyword = /^[a-zA-Zščđ枊ČĐĆŽ, \-]+$/;
|
||||
|
||||
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: 10000, // MB
|
||||
timeout: 10000000, // milliseconds
|
||||
//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();
|
||||
|
||||
// Check form validity.
|
||||
var ime = form["ime"].value;
|
||||
var naslov = form["naslov-predavanja"].value;
|
||||
var predmet = form["predmet"].value;
|
||||
var fakulteta = form["fakulteta"].value;
|
||||
var kljucneBesede = form["kljucne-besede"].value;
|
||||
var email = form["email"].value;
|
||||
var telefon = form["telefon"].value;
|
||||
var privolitev = form["strojno-prevajanje"].checked;
|
||||
var javnaObjava = form["javna-objava-prihodnost"];
|
||||
|
||||
if (isEmptyOrSpaces(ime) ||
|
||||
isEmptyOrSpaces(naslov) ||
|
||||
isEmptyOrSpaces(predmet) ||
|
||||
isEmptyOrSpaces(fakulteta) ||
|
||||
isEmptyOrSpaces(kljucneBesede) ||
|
||||
isEmptyOrSpaces(email)) {
|
||||
alert("Izpolnite vsa obvezna polja!");
|
||||
} else if (!reEmail.test(email.toLowerCase())) {
|
||||
alert("Email napačnega formata!");
|
||||
// } else if (!reKeyword.test(kljucneBesede)) {
|
||||
// alert("Ključne besede so napačnega formata! Besede ločujte z vejico. Besede naj ne vsebujejo posebnih znakov.");
|
||||
} else if (ime.length > 100 ||
|
||||
naslov.length > 100 ||
|
||||
predmet.length > 100 ||
|
||||
fakulteta.length > 100 ||
|
||||
kljucneBesede.length > 100 ||
|
||||
email.length > 100 ||
|
||||
telefon.length > 100) {
|
||||
alert("Velikost polj je omejena na 100 znakov.");
|
||||
} else if (!privolitev) {
|
||||
alert("Odkljukana privolitev je pogoj za oddajo.");
|
||||
} else if (javnaObjava.value == "") {
|
||||
alert("Izberite eno izmed možnosti pri polju za objavo na portalu ON!");
|
||||
} else {
|
||||
|
||||
// Hand off data to dropzone
|
||||
dz.processQueue();
|
||||
|
||||
// Clear fields and hide popup agian
|
||||
btnSubmit.disabled = false;
|
||||
form.reset();
|
||||
}
|
||||
});
|
||||
|
||||
// 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>
|
|
@ -6,6 +6,6 @@
|
|||
<body>
|
||||
<a href="/prevodi">Korpus paralelnih besdil ANG-SLO</a><br>
|
||||
<a href="/gigafida">Korpus Gigafida</a><br>
|
||||
<a href="/predavanja">Korpus Predavanja</a><br>
|
||||
<a href="/solar">Korpus Šolar</a><br>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<style>
|
||||
.tableFixHead {
|
||||
overflow-y: auto;
|
||||
height: 106px;
|
||||
height: 306px;
|
||||
}
|
||||
.tableFixHead thead th {
|
||||
position: sticky;
|
||||
|
@ -27,6 +27,13 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div style="background: blue;">
|
||||
{{ messages[0] }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<h2>Uporabniki</h2>
|
||||
<h3>Dodaj uporabnika</h3>
|
||||
<form action="/solar/adduser" method="post">
|
||||
|
@ -35,7 +42,7 @@
|
|||
<label for="email">Email:</label><br>
|
||||
<input type="text" id="email" name="email"><br>
|
||||
<label for="password">Geslo:</label><br>
|
||||
<input type="text" id="password" name="password"><br>
|
||||
<input type="password" id="password" name="password"><br>
|
||||
<input type="submit" value="Dodaj">
|
||||
</form>
|
||||
<!--<h3>Odstrani uporabnika</h3>
|
||||
|
@ -52,15 +59,16 @@
|
|||
<th>ID</th>
|
||||
<th>Ime in priimek</th>
|
||||
<th>Email</th>
|
||||
<th>ID institucije</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in users %}
|
||||
<tr>
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.name}}</td>
|
||||
<td>{{item.email}}</td>
|
||||
</tr>
|
||||
<td>{{item[0].id}}</td>
|
||||
<td>{{item[0].name}}</td>
|
||||
<td>{{item[0].email}}</td>
|
||||
<td>{{item[1].institution}}</td>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
@ -107,4 +115,30 @@
|
|||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
<h3>Seznam uporabnikov, ki niso aktivirani</h3>
|
||||
<div class="tableFixHead">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Ime in priimek</th>
|
||||
<th>Email</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in inactive_users %}
|
||||
<tr>
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.name}}</td>
|
||||
<td>{{item.email}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
<h3>Aktiviraj uporabnika</h3>
|
||||
<form action="/solar/activateuser" method="post">
|
||||
<label for="id">ID uporabnika:</label>
|
||||
<input type="text" id="id" name="id"><br>
|
||||
<input type="submit" value="Aktiviraj">
|
||||
</form>
|
||||
</body>
|
||||
|
|
40
templates/solar-forgotpass.html
Normal file
40
templates/solar-forgotpass.html
Normal file
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Portal ŠOLAR</title>
|
||||
<link rel="stylesheet" href="/static/style.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main-window">
|
||||
<div id="rect1">
|
||||
<div style="padding: 50px;">
|
||||
<div id="logo-container">
|
||||
<img src="/static/image/logo.svg" alt="logo"/>
|
||||
</div>
|
||||
<h3 id="title" style="font-size: 27px; text-align: left;">Pozabljeno geslo - ŠOLAR</h3>
|
||||
<div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{{ messages[0] }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="POST" action="/solar/sendresetpass">
|
||||
<div>
|
||||
<div>
|
||||
<input type="email" name="email" placeholder="Email" autofocus="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="button-general" style="margin-top: 20px;">Pošlji povezavo za ponastavitev geslo</button>
|
||||
</form>
|
||||
<a href="/solar/register" class="contract-item-button">Registracija</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rect2" class="mock-side">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
|
@ -1,13 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Admin panel - Šolar</title>
|
||||
</head>
|
||||
<body>
|
||||
<h3>Uporabniki</h3>
|
||||
TODO: odobri registracije
|
||||
<form> </form>
|
||||
<div> </div>
|
||||
|
||||
</body>
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Portal {{title}}</title>
|
||||
<title>Portal ŠOLAR</title>
|
||||
<link rel="stylesheet" href="/static/style.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<div id="logo-container">
|
||||
<img src="/static/image/logo.svg" alt="logo"/>
|
||||
</div>
|
||||
<h3 id="title" style="font-size: 27px; text-align: left;">Prijava - {{title}}</h3>
|
||||
<h3 id="title" style="font-size: 27px; text-align: left;">Prijava - ŠOLAR</h3>
|
||||
<div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||