3 Commits

Author SHA1 Message Date
Leon Noe Jovan
e6c87bb3f6 fixes 2023-01-14 13:45:33 +01:00
mihasinkec
10e8116d83 Added route prefix support. 2022-11-06 13:51:12 +01:00
Leon Noe Jovan
f671c365a3 reverted menu 2022-02-14 21:56:10 +01:00
15 changed files with 564 additions and 342 deletions

View File

@@ -13,6 +13,5 @@ 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==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 RUN pip3 install --no-cache-dir pdfkit markupsafe==2.0.1 flask==1.1.4 flask-dropzone flask-log-request-id flask-login Flask-SQLAlchemy==2.5.1 alembic flask-migrate==2.7.0 Flask-script psycopg2 gunicorn pdfkit Werkzeug==1.0.1 PyJWT
ENTRYPOINT ["./entrypoint.sh"] ENTRYPOINT ["./entrypoint.sh"]

302
app.py
View File

@@ -2,6 +2,8 @@ import logging
import os import os
import re import re
import configparser import configparser
import random
import string
from pathlib import Path from pathlib import Path
from werkzeug.security import check_password_hash from werkzeug.security import check_password_hash
@@ -12,6 +14,10 @@ from flask_script import Manager
from flask_login import LoginManager, login_required, login_user, current_user, logout_user from flask_login import LoginManager, login_required, login_user, current_user, logout_user
from portal.model import db, RegisteredUser from portal.model import db, RegisteredUser
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
import portal.solar import portal.solar
# TODO: Integrate Shibboleth login. # TODO: Integrate Shibboleth login.
@@ -27,6 +33,7 @@ config.read('config.ini')
config = config['DEFAULT'] config = config['DEFAULT']
SERVER_NAME = config['SERVER_NAME'] SERVER_NAME = config['SERVER_NAME']
ROUTE_PREFIX = config['ROUTE_PREFIX']
MAIL_HOST = config['MAIL_HOST'] MAIL_HOST = config['MAIL_HOST']
MAIL_LOGIN = config['MAIL_LOGIN'] MAIL_LOGIN = config['MAIL_LOGIN']
MAIL_PASS = config['MAIL_PASS'] MAIL_PASS = config['MAIL_PASS']
@@ -50,6 +57,8 @@ if not UPLOADS_DIR.exists:
# Override configs with environment variables, if set # Override configs with environment variables, if set
if 'PORTALDS4DS1_SERVER_NAME' in os.environ: if 'PORTALDS4DS1_SERVER_NAME' in os.environ:
SERVER_NAME = os.environ['PORTALDS4DS1_SERVER_NAME'] SERVER_NAME = os.environ['PORTALDS4DS1_SERVER_NAME']
if 'PORTALDS4DS1_ROUTE_PREFIX' in os.environ:
ROUTE_PREFIX = os.environ['PORTALDS4DS1_ROUTE_PREFIX']
if 'PORTALDS4DS1_MAIL_HOST' in os.environ: if 'PORTALDS4DS1_MAIL_HOST' in os.environ:
MAIL_HOST = os.environ['PORTALDS4DS1_MAIL_HOST'] MAIL_HOST = os.environ['PORTALDS4DS1_MAIL_HOST']
if 'PORTALDS4DS1_MAIL_LOGIN' in os.environ: if 'PORTALDS4DS1_MAIL_LOGIN' in os.environ:
@@ -80,7 +89,8 @@ if 'PORTALDS4DS1_SQL_CONN_STR' in os.environ:
###################### ######################
app = Flask(__name__) app = Flask(__name__, static_url_path = ROUTE_PREFIX + '/static')
#app = Flask(__name__)
app.config.update( app.config.update(
SERVER_NAME = SERVER_NAME, SERVER_NAME = SERVER_NAME,
@@ -129,11 +139,11 @@ def redirect_url(default='/'):
url_for(default) url_for(default)
@app.route('/') @app.route(ROUTE_PREFIX + '/')
def index(): def index():
if current_user.is_authenticated: if current_user.is_authenticated:
return redirect('/oddaja') return redirect(ROUTE_PREFIX + '/oddaja/')
return redirect('/login') return redirect(ROUTE_PREFIX + '/login/')
@login_manager.user_loader @login_manager.user_loader
@@ -142,17 +152,17 @@ def load_user(user_id):
return user return user
@app.route('/login') @app.route(ROUTE_PREFIX + '/login')
def solar_login_get(): def solar_login_get():
return render_template('solar-login.html') return render_template('solar-login.html', ROUTE_PREFIX=ROUTE_PREFIX)
@app.route('/register') @app.route(ROUTE_PREFIX + '/register')
def solar_register_get(): def solar_register_get():
return render_template('solar-register.html') return render_template('solar-register.html', ROUTE_PREFIX=ROUTE_PREFIX)
@app.route('/login', methods=['POST']) @app.route(ROUTE_PREFIX + '/login', methods=['POST'])
def solar_login_post(): def solar_login_post():
email = request.form.get('email') email = request.form.get('email')
password = request.form.get('password') password = request.form.get('password')
@@ -162,19 +172,19 @@ def solar_login_post():
if not user or not check_password_hash(user.pass_hash, password): if not user or not check_password_hash(user.pass_hash, password):
flash('Napačni podatki za prijavo. Poskusite ponovno.') flash('Napačni podatki za prijavo. Poskusite ponovno.')
return redirect('/login') return redirect(ROUTE_PREFIX + '/login/')
if not user.active: if not user.active:
flash('Vaš uporabniški račun še ni bil aktiviran.') flash('Vaš uporabniški račun še ni bil aktiviran.')
return redirect('/login') return redirect(ROUTE_PREFIX + '/login/')
#portal.solar.add_user_session(user.id) #portal.solar.add_user_session(user.id)
login_user(user, remember=remember) login_user(user, remember=remember)
return redirect('/oddaja') return redirect(ROUTE_PREFIX + '/oddaja/')
@app.route('/register', methods=['POST']) @app.route(ROUTE_PREFIX + '/register', methods=['POST'])
def solar_register_post(): def solar_register_post():
name = request.form.get('name') name = request.form.get('name')
email = request.form.get('email') email = request.form.get('email')
@@ -187,38 +197,38 @@ def solar_register_post():
if user: if user:
flash('Uporabniški račun s tem emailom je že registriran.') flash('Uporabniški račun s tem emailom je že registriran.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if not name: if not name:
flash('Prazno polje za ime.') flash('Prazno polje za ime.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if len(name) > 100: if len(name) > 100:
flash('Predolgo ime.') flash('Predolgo ime.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if not email: if not email:
flash('Prazno polje za elektronsko pošto.') flash('Prazno polje za elektronsko pošto.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if len(email) > 100: if len(email) > 100:
flash('Predolgi email naslov') flash('Predolgi email naslov')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
elif not re.search(portal.solar.REGEX_EMAIL, email): elif not re.search(portal.solar.REGEX_EMAIL, email):
flash('Email napačnega formata.') flash('Email napačnega formata.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if not password: if not password:
flash('Prazno polje za geslo.') flash('Prazno polje za geslo.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if len(password) < 8: if len(password) < 8:
flash('Geslo mora biti vsaj 8 znakov dolgo.') flash('Geslo mora biti vsaj 8 znakov dolgo.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if len(password) > 100: if len(password) > 100:
flash('Predolgo geslo.') flash('Predolgo geslo.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if institution_role not in ['coordinator', 'mentor', 'other']: if institution_role not in ['coordinator', 'mentor', 'other']:
flash('Neveljavna vloga v instituciji.') flash('Neveljavna vloga v instituciji.')
return redirect('/register') return redirect(ROUTE_PREFIX + '/register/')
if not institution: if not institution:
institution_id = portal.solar.add_institution(institution_name, "") institution_id = portal.solar.add_institution(institution_name, "")
@@ -234,17 +244,17 @@ def solar_register_post():
portal.solar.send_admins_new_user_notification_mail(user_id, upload_handler_solar.config) portal.solar.send_admins_new_user_notification_mail(user_id, upload_handler_solar.config)
flash('Podatki so bili poslani v potrditev. Ko bo registracija potrjena, boste o tem obveščeni po e-mailu.') flash('Podatki so bili poslani v potrditev. Ko bo registracija potrjena, boste o tem obveščeni po e-mailu.')
return redirect('/login') return redirect(ROUTE_PREFIX + '/login/')
@app.route('/logout') @app.route(ROUTE_PREFIX + '/logout')
@login_required @login_required
def logout(): def logout():
logout_user() logout_user()
return redirect('/login') return redirect(ROUTE_PREFIX + '/login/')
@app.route('/<path:text>') @app.route(ROUTE_PREFIX + '/<path:text>')
@login_required @login_required
def solar(text): def solar(text):
is_admin = current_user.role == 'admin' is_admin = current_user.role == 'admin'
@@ -259,6 +269,7 @@ def solar(text):
if text.startswith('oddaja/') or text == 'oddaja': if text.startswith('oddaja/') or text == 'oddaja':
return render_template('solar-oddaja.html', return render_template('solar-oddaja.html',
ROUTE_PREFIX=ROUTE_PREFIX,
is_admin=is_admin, is_admin=is_admin,
institution=current_user_institution, institution=current_user_institution,
institution_contract=institution_contract, institution_contract=institution_contract,
@@ -277,7 +288,8 @@ def solar(text):
else: else:
institution_names.append(institution.name) institution_names.append(institution.name)
return render_template('solar-zgodovina.html', upload_history=upload_items, uploader_names=uploader_names, return render_template('solar-zgodovina.html', upload_history=upload_items, uploader_names=uploader_names,
institution_names=institution_names, is_admin=is_admin, is_institution_coordinator=current_user_institution_coordinator) institution_names=institution_names, is_admin=is_admin, is_institution_coordinator=current_user_institution_coordinator,
ROUTE_PREFIX=ROUTE_PREFIX)
elif text.startswith('pogodbe-institucije/') or text.startswith('pogodbe-ucencistarsi/'): elif text.startswith('pogodbe-institucije/') or text.startswith('pogodbe-ucencistarsi/'):
# Check for download contract request. # Check for download contract request.
match = re.match('^pogodbe-(institucije|ucencistarsi)/([a-z0-9_]+\.pdf)$', text) match = re.match('^pogodbe-(institucije|ucencistarsi)/([a-z0-9_]+\.pdf)$', text)
@@ -321,7 +333,9 @@ def solar(text):
else: else:
contracts_students = portal.solar.get_institution_student_contracts(current_user_institution.id, current_user_obj.id) contracts_students = portal.solar.get_institution_student_contracts(current_user_institution.id, current_user_obj.id)
return render_template('solar-pogodbe.html', contracts_students=contracts_students, return render_template('solar-pogodbe.html',
ROUTE_PREFIX=ROUTE_PREFIX,
contracts_students=contracts_students,
contract_school=contract_school, contract_school=contract_school,
enable_upload_school_contract=enable_upload_school_contract, enable_upload_school_contract=enable_upload_school_contract,
show_upload_form=show_upload_form, show_upload_form=show_upload_form,
@@ -336,7 +350,7 @@ def solar(text):
solar_institutions = portal.solar.get_all_institutions() solar_institutions = portal.solar.get_all_institutions()
uploads = portal.solar.get_all_upload_history(-1) uploads = portal.solar.get_all_upload_history(-1)
if is_admin: if is_admin:
return render_template('solar-admin.html', users=users, return render_template('solar-admin.html', ROUTE_PREFIX=ROUTE_PREFIX, users=users,
institutions=solar_institutions, inactive_users=inactive_users, uploads=uploads) institutions=solar_institutions, inactive_users=inactive_users, uploads=uploads)
elif text.startswith('manage-institution/') or text == 'manage-institution': elif text.startswith('manage-institution/') or text == 'manage-institution':
if portal.solar.is_institution_coordinator(current_user.id, current_user_institution.id): if portal.solar.is_institution_coordinator(current_user.id, current_user_institution.id):
@@ -348,21 +362,22 @@ def solar(text):
role_map[institution_user.id] = portal.solar.get_user_institution_role_str(institution_user.id, current_user_institution.id) role_map[institution_user.id] = portal.solar.get_user_institution_role_str(institution_user.id, current_user_institution.id)
return render_template('solar-manage-institution.html', return render_template('solar-manage-institution.html',
ROUTE_PREFIX=ROUTE_PREFIX,
institution=current_user_institution, institution=current_user_institution,
users=solar_users, users=solar_users,
institution_users=institution_users, institution_users=institution_users,
role_map=role_map) role_map=role_map)
return '', 404 return '', 404
@app.route('/pogodbe', methods=['POST']) @app.route(ROUTE_PREFIX + '/pogodbe', methods=['POST'])
@login_required @login_required
def solar_upload_contract(): def solar_upload_contract():
msg = upload_handler_solar.handle_contract_upload(request, current_user.get_id()) msg = upload_handler_solar.handle_contract_upload(request, current_user.get_id())
flash(msg) flash(msg)
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/adduser', methods=['POST']) @app.route(ROUTE_PREFIX + '/adduser', methods=['POST'])
@login_required @login_required
def solar_add_user(): def solar_add_user():
@@ -375,41 +390,41 @@ def solar_add_user():
if not name: if not name:
flash('Prazno polje za ime.') flash('Prazno polje za ime.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if len(name) > 100: if len(name) > 100:
flash('Predolgo ime.') flash('Predolgo ime.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if not email: if not email:
flash('Prazno polje za elektronsko pošto.') flash('Prazno polje za elektronsko pošto.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if len(email) > 100: if len(email) > 100:
flash('Predolg email naslov.') flash('Predolg email naslov.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
elif not re.search(portal.solar.REGEX_EMAIL, email): elif not re.search(portal.solar.REGEX_EMAIL, email):
flash('Email napačnega formata.') flash('Email napačnega formata.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if not password: if not password:
flash('Prazno polje za geslo.') flash('Prazno polje za geslo.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if len(password) > 100: if len(password) > 100:
flash('Predolgo geslo.') flash('Predolgo geslo.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
user = portal.solar.get_user_obj_by_email(email) user = portal.solar.get_user_obj_by_email(email)
if user: if user:
#portal.solar.undo_remove_user(user.id) #portal.solar.undo_remove_user(user.id)
flash('Uporabnik s tem emailom je že vnešen v sistem.') flash('Uporabnik s tem emailom je že vnešen v sistem.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.register_new_user(name, email, password) portal.solar.register_new_user(name, email, password)
flash('Uporabnik je bil uspešno dodan.') flash('Uporabnik je bil uspešno dodan.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/activateuser', methods=['POST']) @app.route(ROUTE_PREFIX + '/activateuser', methods=['POST'])
@login_required @login_required
def solar_activate_user(): def solar_activate_user():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -418,7 +433,7 @@ def solar_activate_user():
user_id = request.form.get('id') user_id = request.form.get('id')
if not user_id: if not user_id:
flash('Prazno polje za ID uporabnika.') flash('Prazno polje za ID uporabnika.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
rowcount = portal.solar.activate_user(user_id) rowcount = portal.solar.activate_user(user_id)
if rowcount == 0: if rowcount == 0:
@@ -427,35 +442,35 @@ def solar_activate_user():
portal.solar.send_user_activation_mail(user_id, upload_handler_solar.config) portal.solar.send_user_activation_mail(user_id, upload_handler_solar.config)
flash('Uporabnik je bil aktiviran.') flash('Uporabnik je bil aktiviran.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/forgotpass') @app.route(ROUTE_PREFIX + '/forgotpass')
def solar_forgotpass(): def solar_forgotpass():
return render_template('solar-forgotpass.html') return render_template('solar-forgotpass.html', ROUTE_PREFIX=ROUTE_PREFIX)
@app.route('/sendresetpass', methods=['POST']) @app.route(ROUTE_PREFIX + '/sendresetpass', methods=['POST'])
def solar_sendresetpass(): def solar_sendresetpass():
email = request.form.get('email') email = request.form.get('email')
portal.solar.send_resetpass_mail(email, upload_handler_solar.config) portal.solar.send_resetpass_mail(email, upload_handler_solar.config)
flash('Povezava za ponastavitev gesla je bila poslana na vpisani e-naslov.') flash('Povezava za ponastavitev gesla je bila poslana na vpisani e-naslov.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/resetpass/<token>') @app.route(ROUTE_PREFIX + '/resetpass/<token>')
def solar_resetpass(token): def solar_resetpass(token):
user = portal.solar.verify_reset_token(token, upload_handler_solar.config['APP_SECRET_KEY']) user = portal.solar.verify_reset_token(token, upload_handler_solar.config['APP_SECRET_KEY'])
if not user: if not user:
return '', 404 return '', 404
return render_template('solar-resetpass.html', user=user, token=token) return render_template('solar-resetpass.html',ROUTE_PREFIX=ROUTE_PREFIX, user=user, token=token)
@app.route('/resetpass/<token>', methods=['POST']) @app.route(ROUTE_PREFIX + '/resetpass/<token>', methods=['POST'])
def solar_resetpass_post(token): def solar_resetpass_post(token):
new_password = request.form.get('new_password') new_password = request.form.get('new_password')
user = portal.solar.verify_reset_token(token, upload_handler_solar.config['APP_SECRET_KEY']) user = portal.solar.verify_reset_token(token, upload_handler_solar.config['APP_SECRET_KEY'])
@@ -468,28 +483,33 @@ def solar_resetpass_post(token):
return '', 404 return '', 404
flash('Ponastavitev gesla je bila uspešna.') flash('Ponastavitev gesla je bila uspešna.')
return redirect('/login') return redirect(ROUTE_PREFIX + '/login/')
@app.route('/topuploads') @app.route(ROUTE_PREFIX + '/topuploads')
@login_required @login_required
def solar_topuploads(): def solar_topuploads():
return jsonify(portal.solar.get_top_uploading_institutions()) return jsonify(portal.solar.get_top_uploading_institutions())
@app.route('/topuploads-institution/<institution_id>') @app.route(ROUTE_PREFIX + '/topuploads-institution/<institution_id>')
@login_required @login_required
def solar_topuploads_institution(institution_id): def solar_topuploads_institution(institution_id):
return jsonify(portal.solar.get_top_uploading_users(institution_id)) return jsonify(portal.solar.get_top_uploading_users(institution_id))
@app.route('/uploadstats-institution/<institution_id>') @app.route(ROUTE_PREFIX + '/uploadstats-institution/<institution_id>')
@login_required @login_required
def solar_uploadstats_institution(institution_id): def solar_uploadstats_institution(institution_id):
return jsonify(portal.solar.get_institution_upload_stats(institution_id)) return jsonify(portal.solar.get_institution_upload_stats(institution_id))
@app.route(ROUTE_PREFIX + '/uploadstats-per-region')
@login_required
def solar_uploadstats_per_region():
return jsonify(portal.solar.get_region_stats())
@app.route('/deluser', methods=['POST'])
@app.route(ROUTE_PREFIX + '/deluser', methods=['POST'])
@login_required @login_required
def solar_del_user(): def solar_del_user():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -497,9 +517,9 @@ def solar_del_user():
user_id = request.form.get('user_id') user_id = request.form.get('user_id')
portal.solar.remove_user(user_id) portal.solar.remove_user(user_id)
flash('Uporabnik je bil odstranjen.') flash('Uporabnik je bil odstranjen.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/addinstitution', methods=['POST']) @app.route(ROUTE_PREFIX + '/addinstitution', methods=['POST'])
@login_required @login_required
def add_institution(): def add_institution():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -510,21 +530,21 @@ def add_institution():
if not name: if not name:
flash('Prazno polje za naziv.') flash('Prazno polje za naziv.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if len(name) > 100: if len(name) > 100:
flash('Predolgo ime.') flash('Predolgo ime.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if not region in portal.solar.VALID_REGIONS: if not region in portal.solar.VALID_REGIONS:
flash('Neveljavna vrednost za regijo.') flash('Neveljavna vrednost za regijo.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
institution_id = portal.solar.add_institution(name, region) institution_id = portal.solar.add_institution(name, region)
portal.solar.grant_institution_corpus_access(institution_id, "solar") # TODO: throw out portal.solar.grant_institution_corpus_access(institution_id, "solar") # TODO: throw out
flash('Institucija je bila dodana.') flash('Institucija je bila dodana.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/mergeinstitutions', methods=['POST']) @app.route(ROUTE_PREFIX + '/mergeinstitutions', methods=['POST'])
@login_required @login_required
def merge_institutions(): def merge_institutions():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -535,18 +555,18 @@ def merge_institutions():
if not id_from or not id_to: if not id_from or not id_to:
flash('Prazno polje.') flash('Prazno polje.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
institution_from = portal.solar.get_institution_obj(id_from) institution_from = portal.solar.get_institution_obj(id_from)
institution_to = portal.solar.get_institution_obj(id_to) institution_to = portal.solar.get_institution_obj(id_to)
if not institution_from: if not institution_from:
flash('Institucija z ID "{}" ne obstaja.'.format(id_from)) flash('Institucija z ID "{}" ne obstaja.'.format(id_from))
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if not institution_to: if not institution_to:
flash('Institucija z ID "{}" ne obstaja.'.format(id_to)) flash('Institucija z ID "{}" ne obstaja.'.format(id_to))
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.transfer_users_institution(institution_from.id, institution_to.id) portal.solar.transfer_users_institution(institution_from.id, institution_to.id)
@@ -555,9 +575,9 @@ def merge_institutions():
portal.solar.remove_institution(institution_from.id) portal.solar.remove_institution(institution_from.id)
flash('Instituciji uspešno združeni') flash('Instituciji uspešno združeni')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
#@app.route('/addcooperationhistoryitem', methods=['POST']) #@app.route(ROUTE_PREFIX + '/addcooperationhistoryitem', methods=['POST'])
#@login_required #@login_required
#def add_cooperation_history_item(): #def add_cooperation_history_item():
# if not portal.solar.is_admin(current_user.id): # if not portal.solar.is_admin(current_user.id):
@@ -574,26 +594,26 @@ def merge_institutions():
# #
# if not user: # if not user:
# flash('Uporabnik s tem ID-jem ne obstaja.') # flash('Uporabnik s tem ID-jem ne obstaja.')
# return redirect(redirect_url()) # return redirect(ROUTE_PREFIX + redirect_url())
# #
# if not institution: # if not institution:
# flash('Institucija s tem ID-jem ne obstaja.') # flash('Institucija s tem ID-jem ne obstaja.')
# return redirect(redirect_url()) # return redirect(ROUTE_PREFIX + redirect_url())
# #
# if not role in ['coordinator', 'mentor', 'other']: # if not role in ['coordinator', 'mentor', 'other']:
# flash('Neveljavna vloga "{}".'.format(role)) # flash('Neveljavna vloga "{}".'.format(role))
# return redirect(redirect_url()) # return redirect(ROUTE_PREFIX + redirect_url())
# #
# if not school_year or not re.match('[0-9]{4}/[0-9]{2}', school_year): # if not school_year or not re.match('[0-9]{4}/[0-9]{2}', school_year):
# flash('Šolsko leto mora biti formata "2021/22".') # flash('Šolsko leto mora biti formata "2021/22".')
# return redirect(redirect_url()) # return redirect(ROUTE_PREFIX + redirect_url())
# #
# portal.solar.add_cooperation_history_item(user_id, institution_id, role, school_year, badge_text) # portal.solar.add_cooperation_history_item(user_id, institution_id, role, school_year, badge_text)
# #
# flash('Vnos dodan.') # flash('Vnos dodan.')
# return redirect(redirect_url()) # return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/updateuploaditem', methods=['POST']) @app.route(ROUTE_PREFIX + '/updateuploaditem', methods=['POST'])
@login_required @login_required
def update_upload_item(): def update_upload_item():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -602,7 +622,7 @@ def update_upload_item():
err_msg = portal.solar.UploadHandlerSolar.check_form(request.form) err_msg = portal.solar.UploadHandlerSolar.check_form(request.form)
if err_msg: if err_msg:
flash(err_msg) flash(err_msg)
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
item_id = request.form.get('item-id') item_id = request.form.get('item-id')
program = request.form.get('program') program = request.form.get('program')
@@ -629,10 +649,10 @@ def update_upload_item():
return '', 404 return '', 404
flash('Vnos spremenjen.') flash('Vnos spremenjen.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
#@app.route('/delcooperationhistoryitem', methods=['POST']) #@app.route(ROUTE_PREFIX + '/delcooperationhistoryitem', methods=['POST'])
#@login_required #@login_required
#def del_cooperation_history_item(): #def del_cooperation_history_item():
# if not portal.solar.is_admin(current_user.id): # if not portal.solar.is_admin(current_user.id):
@@ -642,9 +662,9 @@ def update_upload_item():
# portal.solar.del_cooperation_history_item(entry_id) # portal.solar.del_cooperation_history_item(entry_id)
# #
# flash('Vnos odstranjen.') # flash('Vnos odstranjen.')
# return redirect(redirect_url()) # return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/changeinstitutiondata', methods=['POST']) @app.route(ROUTE_PREFIX + '/changeinstitutiondata', methods=['POST'])
@login_required @login_required
def change_institution_data(): def change_institution_data():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -656,21 +676,21 @@ def change_institution_data():
if not new_name: if not new_name:
flash('Prazno polje za naziv.') flash('Prazno polje za naziv.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if len(new_name) > 100: if len(new_name) > 100:
flash('Predolgo ime.') flash('Predolgo ime.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if not new_region in portal.solar.VALID_REGIONS: if not new_region in portal.solar.VALID_REGIONS:
flash('Neveljavna vrednost za regijo.') flash('Neveljavna vrednost za regijo.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.update_institution_data(institution_id, new_name, new_region) portal.solar.update_institution_data(institution_id, new_name, new_region)
flash('Podatki institucije so bili spremenjeni.') flash('Podatki institucije so bili spremenjeni.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/changeuseremail', methods=['POST']) @app.route(ROUTE_PREFIX + '/changeuseremail', methods=['POST'])
@login_required @login_required
def change_user_email(): def change_user_email():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -681,14 +701,14 @@ def change_user_email():
if not re.search(portal.solar.REGEX_EMAIL, email): if not re.search(portal.solar.REGEX_EMAIL, email):
flash('Email napačnega formata.') flash('Email napačnega formata.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.update_user_email(user_id, email) portal.solar.update_user_email(user_id, email)
flash('Email spremenjen.') flash('Email spremenjen.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/changeuserrole-institution', methods=['POST']) @app.route(ROUTE_PREFIX + '/changeuserrole-institution', methods=['POST'])
@login_required @login_required
def change_user_role_institution(): def change_user_role_institution():
institution = portal.solar.get_user_institution(current_user.id) institution = portal.solar.get_user_institution(current_user.id)
@@ -705,16 +725,16 @@ def change_user_role_institution():
if role not in ['coordinator', 'mentor', 'other']: if role not in ['coordinator', 'mentor', 'other']:
flash('Neveljavna vloga.') flash('Neveljavna vloga.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.update_user_institution_role(user_id, institution.id, role) portal.solar.update_user_institution_role(user_id, institution.id, role)
portal.solar.add_cooperation_history_item(user_id, institution.id, role) portal.solar.add_cooperation_history_item(user_id, institution.id, role)
flash('Vloga v instituciji spremenjena.') flash('Vloga v instituciji spremenjena.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/changeuserrole', methods=['POST']) @app.route(ROUTE_PREFIX + '/changeuserrole', methods=['POST'])
@login_required @login_required
def change_user_role(): def change_user_role():
institution = portal.solar.get_user_institution(current_user.id) institution = portal.solar.get_user_institution(current_user.id)
@@ -726,14 +746,14 @@ def change_user_role():
if not role in ['admin', 'user']: if not role in ['admin', 'user']:
flash('Neveljavna vloga.') flash('Neveljavna vloga.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.update_user_role(user_id, role) portal.solar.update_user_role(user_id, role)
flash('Vloga spremenjena.') flash('Vloga spremenjena.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/changeusername', methods=['POST']) @app.route(ROUTE_PREFIX + '/changeusername', methods=['POST'])
@login_required @login_required
def change_user_name(): def change_user_name():
if not portal.solar.is_admin(current_user.id): if not portal.solar.is_admin(current_user.id):
@@ -745,9 +765,9 @@ def change_user_name():
portal.solar.update_user_name(user_id, name) portal.solar.update_user_name(user_id, name)
flash('Ime in priimek spremenjena.') flash('Ime in priimek spremenjena.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/addusertoinstitution', methods=['POST']) @app.route(ROUTE_PREFIX + '/addusertoinstitution', methods=['POST'])
@login_required @login_required
def add_user_institution_mapping(): def add_user_institution_mapping():
institution_id = request.form.get('institution_id') institution_id = request.form.get('institution_id')
@@ -766,39 +786,39 @@ def add_user_institution_mapping():
if portal.solar.get_user_institution(user_id): if portal.solar.get_user_institution(user_id):
flash('Uporabnik je že dodeljen instituciji.') flash('Uporabnik je že dodeljen instituciji.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.add_user_to_institution(user_id, institution_id, role) portal.solar.add_user_to_institution(user_id, institution_id, role)
portal.solar.add_cooperation_history_item(user_id, institution_id, role) portal.solar.add_cooperation_history_item(user_id, institution_id, role)
flash('Uporabnik je bil dodeljen instituciji.') flash('Uporabnik je bil dodeljen instituciji.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/deluserfrominstitution', methods=['POST']) @app.route(ROUTE_PREFIX + '/deluserfrominstitution', methods=['POST'])
@login_required @login_required
def del_user_institution_mapping(): def del_user_institution_mapping():
user_id = request.form['user_id'] user_id = request.form['user_id']
institution = portal.solar.get_user_institution(user_id) institution = portal.solar.get_user_institution(user_id)
if not institution: if not institution:
flash('Uporabnik ni član nobene institucije.') flash('Uporabnik ni član nobene institucije.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
if not portal.solar.is_admin(current_user.id) \ if not portal.solar.is_admin(current_user.id) \
and not portal.solar.is_institution_coordinator(current_user.id, institution.id): and not portal.solar.is_institution_coordinator(current_user.id, institution.id):
flash('Nimate ustreznih pravic za odstranitev uporabnika iz institucije.') flash('Nimate ustreznih pravic za odstranitev uporabnika iz institucije.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
portal.solar.del_user_from_institution(user_id, institution.id) portal.solar.del_user_from_institution(user_id, institution.id)
flash('Uporabnik je bil odstranjen iz institucije.') flash('Uporabnik je bil odstranjen iz institucije.')
return redirect(redirect_url()) return redirect(ROUTE_PREFIX + redirect_url())
@app.route('/upload', methods=['POST']) @app.route(ROUTE_PREFIX + '/upload', methods=['POST'])
def handle_upload(): def handle_upload():
if not current_user.is_authenticated: if not current_user.is_authenticated:
return '', 404 return '', 404
return upload_handler_solar.handle_upload(request, current_user.get_id()) return upload_handler_solar.handle_upload(request, current_user.get_id())
@app.route('/getuploadfile/<upload_id>/<file_hash>', methods=['GET']) @app.route(ROUTE_PREFIX + '/getuploadfile/<upload_id>/<file_hash>', methods=['GET'])
@login_required @login_required
def get_upload_file(upload_id, file_hash): def get_upload_file(upload_id, file_hash):
is_admin = current_user.role == 'admin' is_admin = current_user.role == 'admin'
@@ -829,6 +849,80 @@ def get_upload_file(upload_id, file_hash):
except FileNotFoundError: except FileNotFoundError:
return '', 404 return '', 404
@app.route(ROUTE_PREFIX + '/institutionadduser', methods=['POST'])
@login_required
def solar_institution_add_user():
current_user_institution = portal.solar.get_user_institution(current_user.id)
if not portal.solar.is_institution_coordinator(current_user.id, current_user_institution.id):
return '', 404
name = request.form.get('name')
email = request.form.get('email')
role = request.form.get('role')
password=''.join(random.choices(string.ascii_lowercase, k=8))
if not name:
flash('Prazno polje za ime.')
return redirect(ROUTE_PREFIX + redirect_url())
if len(name) > 100:
flash('Predolgo ime.')
return redirect(ROUTE_PREFIX + redirect_url())
if not email:
flash('Prazno polje za elektronsko pošto.')
return redirect(ROUTE_PREFIX + redirect_url())
if len(email) > 100:
flash('Predolg email naslov.')
return redirect(ROUTE_PREFIX + redirect_url())
elif not re.search(portal.solar.REGEX_EMAIL, email):
flash('Email napačnega formata.')
return redirect(ROUTE_PREFIX + redirect_url())
if not password:
flash('Prazno polje za geslo.')
return redirect(ROUTE_PREFIX + redirect_url())
if len(password) > 100:
flash('Predolgo geslo.')
return redirect(ROUTE_PREFIX + redirect_url())
user = portal.solar.get_user_obj_by_email(email)
if user:
#portal.solar.undo_remove_user(user.id)
flash('Uporabnik s tem emailom je že vnešen v sistem.')
return redirect(ROUTE_PREFIX + redirect_url())
new_user_id = portal.solar.register_new_user(name, email, password)
portal.solar.add_user_to_institution(new_user_id, current_user_institution.id, role)
portal.solar.activate_user(new_user_id)
#token za nastaviti geslo
jwt_token = portal.solar.get_password_reset_token(email, config['APP_SECRET_KEY'])
#pošlji email uporabniku
body = '''
Ustvarjen je bil uporabniški račun na Portalu Šolar.
Geslo lahko nastavite na naslednji povezavi: https://{}/resetpass/{}'''.format(config['SERVER_NAME'], jwt_token)
message = MIMEMultipart()
message['From'] = config['MAIL_LOGIN']
message['To'] = email
message['Subject'] = 'Portal Šolar: Ponastavitev gesla'
message.attach(MIMEText(body, "plain"))
text = message.as_string()
# 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()
flash('Uporabnik je bil uspešno dodan.')
return redirect(ROUTE_PREFIX + redirect_url())
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True) app.run(debug=True)

View File

@@ -1,5 +1,6 @@
[DEFAULT] [DEFAULT]
SERVER_NAME=localhost:5000 SERVER_NAME=localhost:5000
ROUTE_PREFIX=
SQL_CONN_STR=postgresql://portal:randompass123@localhost/portal SQL_CONN_STR=postgresql://portal:randompass123@localhost/portal
MAIL_HOST=posta.cjvt.si MAIL_HOST=posta.cjvt.si
MAIL_LOGIN=oddaja-besedil@cjvt.si MAIL_LOGIN=oddaja-besedil@cjvt.si

View File

@@ -6,6 +6,7 @@ import traceback
import ssl import ssl
from datetime import datetime from datetime import datetime
from sqlalchemy import desc from sqlalchemy import desc
from sqlalchemy import func
from pathlib import Path from pathlib import Path
from smtplib import SMTP_SSL from smtplib import SMTP_SSL
@@ -24,6 +25,7 @@ from werkzeug.security import generate_password_hash
from . model import * from . model import *
VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'} VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'}
VALID_SUBJECTS = {'SLO', 'DJP', 'DDP', 'DNP', 'DSP', 'DIP'} VALID_SUBJECTS = {'SLO', 'DJP', 'DDP', 'DNP', 'DSP', 'DIP'}
VALID_TEXT_TYPES = {'E', 'PB', 'T', 'R'} VALID_TEXT_TYPES = {'E', 'PB', 'T', 'R'}
@@ -491,6 +493,24 @@ def get_institution_upload_stats(institution_id):
return res return res
def get_region_stats():
ret = {'CE': [0,0], 'GO': [0,0], 'KK': [0,0], 'KP': [0,0], 'KR': [0,0], 'LJ': [0,0], 'MB': [0,0], 'MS': [0,0], 'NM': [0,0], 'PO': [0,0], 'SG': [0,0]}
os = db.session.query(UploadSolar.region, func.count(UploadSolar.id)).filter_by(program="OS").group_by(UploadSolar.region).all()
neos = db.session.query(UploadSolar.region, func.count(UploadSolar.id)).filter(sqlalchemy.not_(UploadSolar.program.contains("OS"))).group_by(UploadSolar.region).all()
#logging.error(os)
#logging.error(neos)
for key, val in os:
ret[key][0] = val
for key, val in neos:
ret[key][1] = val
logging.error(ret)
return ret
def get_all_active_users(): def get_all_active_users():
# TODO: do filtering purely within an SQL query # TODO: do filtering purely within an SQL query
@@ -809,9 +829,11 @@ def get_actual_studentparent_contract_filename(f_hash):
def get_password_reset_token(email, key, expires=600): def get_password_reset_token(email, key, expires=600):
return jwt.encode({'reset_password': email, token = jwt.encode({'reset_password': email,
'exp': int(time.time()) + expires}, 'exp': int(time.time()) + expires},
key=key, algorithm='HS256') key=key, algorithm='HS256')
logging.error(token)
return token
def transfer_users_institution(institution_id_from, institution_id_to): def transfer_users_institution(institution_id_from, institution_id_to):
@@ -860,7 +882,7 @@ def send_resetpass_mail(email, config):
message = MIMEMultipart() message = MIMEMultipart()
message['From'] = config['MAIL_LOGIN'] message['From'] = config['MAIL_LOGIN']
message['To'] = email message['To'] = email
message['Subject'] = 'Ponastavitev gesla' message['Subject'] = 'Portal Šolar: Ponastavitev gesla'
message.attach(MIMEText(body, "plain")) message.attach(MIMEText(body, "plain"))
text = message.as_string() text = message.as_string()
@@ -909,7 +931,7 @@ def send_user_activation_mail(user_id, config):
message = MIMEMultipart() message = MIMEMultipart()
message['From'] = config['MAIL_LOGIN'] message['From'] = config['MAIL_LOGIN']
message['To'] = user.email message['To'] = user.email
message['Subject'] = 'Ponastavitev gesla' message['Subject'] = 'Portal Šolar: Vaš uporabniški račun je odobren'
message.attach(MIMEText(body, "plain")) message.attach(MIMEText(body, "plain"))
text = message.as_string() text = message.as_string()

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

10
static/favicon.svg Normal file
View File

@@ -0,0 +1,10 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect fill="#006CB7" width="512" height="512"/>
<path fill="#fff" d="M409.26,145.32V69.5l-46.06,55.16c-5.06-1.88-10.5-3.99-16.1-5.71c-16.12-4.52-32.56-7.82-49.17-9.86
c-5.37-0.47-11.2-0.47-17.04-0.47c-64.88,0-87.21,25.27-87.21,51.25c0,29.89,32.44,46.95,107.28,66.27
c89.47,22.07,117.94,63.93,117.94,114.79c0.04,6.77-0.59,13.54-1.87,20.19c41.39-26.92,66.98-64.24,66.98-105.48
c0-43.74-28.79-83.02-74.61-110.33"/>
<path fill="#fff" d="M241.92,278.65c-84.49-19.95-124.47-61.66-124.47-112.6c-0.13-10.68,1.69-21.29,5.37-31.3
c-57.41,27.07-94.76,71.13-94.76,120.89c0,42.02,26.61,79.89,69.32,107.04v79.81l47.38-56.73c23.89,8.63,48.73,14.33,73.98,16.98
c8.56,0.7,17.35,1.17,26.53,1.17c65.66,0,96.39-23.47,96.39-58.45c0-29.26-28.32-50-99.81-66.82"/>
</svg>

After

Width:  |  Height:  |  Size: 852 B

View File

@@ -3,10 +3,12 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Admin panel - Šolar</title> <title>Admin panel - Šolar</title>
<link rel="stylesheet" href="../static/css/header.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/form.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="../static/css/simple-grid.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/header.css" type="text/css">
<link rel="stylesheet" href="../static/css/manage-institution.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/form.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/simple-grid.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/manage-institution.css" type="text/css">
<style> <style>
.tableFixHead { .tableFixHead {
overflow-y: scroll; overflow-y: scroll;
@@ -35,26 +37,17 @@
</head> </head>
<body> <body>
<header> <header>
<div class="logo"><a href="../"><img src="../static/image/logo-white.svg"/></a></div> <div class="logo"><a href="{{ROUTE_PREFIX}}/"><img src="{{ROUTE_PREFIX}}/static/image/logo-white.svg"/></a></div>
<div class="dropdown"> <div class="menu-items">
<button class="dropbtn"><img src="/static/image/menu.svg"/></button> <a href="{{ROUTE_PREFIX}}/oddaja">Oddaja besedil</a>
<div class="dropdown-content"> {% if is_institution_coordinator %}
<a href="../oddaja">Oddaja</a> <a href="{{ROUTE_PREFIX}}/manage-institution">Upravljaj z ekipo</a>
<a href="../zgodovina">Zgodovina</a> {% endif %}
<a href="../pogodbe">Ekipa</a> {% if is_admin %}
{% if is_institution_coordinator %} <a href="{{ROUTE_PREFIX}}/admin">Administracijski meni</a>
<hr/> {% endif %}
<a href="../manage-institution">Upravljaj z institucijo</a> <a href="https://slovenscina.eu/" target="_blank">Več informacij o sodelovanju</a>
{% endif %} <a href="{{ROUTE_PREFIX}}/logout">Odjava</a>
{% if is_admin %}
<hr/>
<a href="../admin">Administracijski meni</a>
{% endif %}
<hr/>
<a href="https://slovenscina.eu/" target="_blank">Več informacij</a>
<hr/>
<a href="../logout">Odjava</a>
</div>
</div> </div>
</header> </header>
<div class="container" style="margin-top:8rem;"> <div class="container" style="margin-top:8rem;">
@@ -92,7 +85,7 @@
</table> </table>
</div> </div>
<h3>Dodaj uporabnika</h3> <h3>Dodaj uporabnika</h3>
<form action="../adduser" method="post"> <form action="{{ROUTE_PREFIX}}/adduser" method="post">
<label for="name">Ime in priimek:</label><br> <label for="name">Ime in priimek:</label><br>
<input type="text" id="name" name="name"><br> <input type="text" id="name" name="name"><br>
<label for="email">Email:</label><br> <label for="email">Email:</label><br>
@@ -102,7 +95,7 @@
<input type="submit" value="Dodaj"> <input type="submit" value="Dodaj">
</form> </form>
<h3>Spremeni email uporabnika</h3> <h3>Spremeni email uporabnika</h3>
<form action="../changeuseremail" method="post"> <form action="{{ROUTE_PREFIX}}/changeuseremail" method="post">
<label for="user-id">ID uporabnika:</label><br> <label for="user-id">ID uporabnika:</label><br>
<input type="text" id="user-id" name="user-id"><br> <input type="text" id="user-id" name="user-id"><br>
<label for="email">Nov email:</label><br> <label for="email">Nov email:</label><br>
@@ -110,7 +103,7 @@
<input type="submit" value="Spremeni"> <input type="submit" value="Spremeni">
</form> </form>
<h3>Spremeni ime in priimek uporabnika</h3> <h3>Spremeni ime in priimek uporabnika</h3>
<form action="../changeusername" method="post"> <form action="{{ROUTE_PREFIX}}/changeusername" method="post">
<label for="user-id">ID uporabnika:</label><br> <label for="user-id">ID uporabnika:</label><br>
<input type="text" id="user-id" name="user-id"><br> <input type="text" id="user-id" name="user-id"><br>
<label for="name">Ime in priimek:</label><br> <label for="name">Ime in priimek:</label><br>
@@ -118,13 +111,13 @@
<input type="submit" value="Spremeni"> <input type="submit" value="Spremeni">
</form> </form>
<h3>Odstrani uporabnika</h3> <h3>Odstrani uporabnika</h3>
<form action="../deluser" method="post"> <form action="{{ROUTE_PREFIX}}/deluser" method="post">
<label for="user_id">ID uporabnika:</label><br> <label for="user_id">ID uporabnika:</label><br>
<input type="text" id="user_id" name="user_id"><br> <input type="text" id="user_id" name="user_id"><br>
<input type="submit" value="Odstrani"> <input type="submit" value="Odstrani">
</form> </form>
<h3>Dodeli uporabnika instituciji</h3> <h3>Dodeli uporabnika instituciji</h3>
<form action="../addusertoinstitution" method="post"> <form action="{{ROUTE_PREFIX}}/addusertoinstitution" method="post">
<label for="user_id">ID uporabnika:</label> <label for="user_id">ID uporabnika:</label>
<input type="text" id="user_id" name="user_id"><br> <input type="text" id="user_id" name="user_id"><br>
<label for="institution_id">ID institucije:</label> <label for="institution_id">ID institucije:</label>
@@ -138,13 +131,13 @@
<input type="submit" value="Dodeli"> <input type="submit" value="Dodeli">
</form> </form>
<h3>Odstrani uporabnika iz institucije</h3> <h3>Odstrani uporabnika iz institucije</h3>
<form action="../deluserfrominstitution" method="post"> <form action="{{ROUTE_PREFIX}}/deluserfrominstitution" method="post">
<label for="user_id">ID uporabnika:</label> <label for="user_id">ID uporabnika:</label>
<input type="text" id="user_id" name="user_id"><br> <input type="text" id="user_id" name="user_id"><br>
<input type="submit" value="Odstrani"> <input type="submit" value="Odstrani">
</form> </form>
<h3>Spremeni vlogo uporabniškega računa</h3> <h3>Spremeni vlogo uporabniškega računa</h3>
<form action="../changeuserrole" method="post"> <form action="{{ROUTE_PREFIX}}/changeuserrole" method="post">
<label for="user-id">ID uporabnika:</label> <label for="user-id">ID uporabnika:</label>
<input type="text" id="user-id" name="user-id"><br> <input type="text" id="user-id" name="user-id"><br>
<label for="role">Vloga:</label> <label for="role">Vloga:</label>
@@ -176,7 +169,7 @@
<td>{{item[1].institution}}</td> <td>{{item[1].institution}}</td>
<td>{{item[1].role}}</td> <td>{{item[1].role}}</td>
<td> <td>
<form action="../activateuser" method="post"> <form action="{{ROUTE_PREFIX}}/activateuser" method="post">
<input type="hidden" id="id" name="id" value="{{item[0].id}}"> <input type="hidden" id="id" name="id" value="{{item[0].id}}">
<input type="submit" value="Aktiviraj"> <input type="submit" value="Aktiviraj">
</form> </form>
@@ -189,7 +182,7 @@
<div> </div> <div> </div>
<h2>Institucije</h2> <h2>Institucije</h2>
<h3>Dodaj institucijo</h3> <h3>Dodaj institucijo</h3>
<form action="../addinstitution" method="post"> <form action="{{ROUTE_PREFIX}}/addinstitution" method="post">
<label for="name">Naziv:</label> <label for="name">Naziv:</label>
<input type="text" id="name" name="name"><br> <input type="text" id="name" name="name"><br>
<label for="region">Regija:</label> <label for="region">Regija:</label>
@@ -229,7 +222,7 @@
</table> </table>
</div> </div>
<h3>Združi instituciji</h3> <h3>Združi instituciji</h3>
<form action="../mergeinstitutions" method="post"> <form action="{{ROUTE_PREFIX}}/mergeinstitutions" method="post">
<label for="id-from">Institucijo z ID</label> <label for="id-from">Institucijo z ID</label>
<input type="text" id="id-from" name="id-from"> <input type="text" id="id-from" name="id-from">
<label for="id-to">združi v institucijo z ID</label> <label for="id-to">združi v institucijo z ID</label>
@@ -237,7 +230,7 @@
<input type="submit" value="Združi"> <input type="submit" value="Združi">
</form> </form>
<h3>Spremeni podatke institucije</h3> <h3>Spremeni podatke institucije</h3>
<form action="../changeinstitutiondata" method="post"> <form action="{{ROUTE_PREFIX}}/changeinstitutiondata" method="post">
<label for="id">ID institucije</label> <label for="id">ID institucije</label>
<input type="text" id="id" name="id"><br> <input type="text" id="id" name="id"><br>
<label for="name">Nov naziv:</label> <label for="name">Nov naziv:</label>
@@ -259,7 +252,7 @@
<input type="submit" value="Spremeni"> <input type="submit" value="Spremeni">
</form> </form>
<h3>Odstrani vnos</h3> <h3>Odstrani vnos</h3>
<form action="../delcooperationhistoryitem" method="post"> <form action="{{ROUTE_PREFIX}}/delcooperationhistoryitem" method="post">
<label for="entry-id">ID vnosa</label> <label for="entry-id">ID vnosa</label>
<input type="text" id="entry-id" name="entry-id"><br> <input type="text" id="entry-id" name="entry-id"><br>
<input type="submit" value="Odstrani"> <input type="submit" value="Odstrani">
@@ -305,7 +298,7 @@
</table> </table>
</div> </div>
<h3>Posodobi podatke nalaganja</h3> <h3>Posodobi podatke nalaganja</h3>
<form action="../updateuploaditem" method="post"> <form action="{{ROUTE_PREFIX}}/updateuploaditem" method="post">
<label for="item-id">ID nalaganja</label> <label for="item-id">ID nalaganja</label>
<input type="text" id="item-id" name="item-id"/><br> <input type="text" id="item-id" name="item-id"/><br>
<label for="program">Program</label> <label for="program">Program</label>

View File

@@ -3,20 +3,22 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal ŠOLAR</title> <title>Portal ŠOLAR</title>
<link rel="stylesheet" href="../static/css/login-styles.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/utils.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/login-styles.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/utils.css" type="text/css">
</head> </head>
<body> <body>
<div class="background"> <div class="background">
<div class="panel login-panel"> <div class="panel login-panel">
<div class="panel-logo"> <div class="panel-logo">
<img src="../static/image/logo.svg" alt="logo"/> <img src="{{ROUTE_PREFIX}}/static/image/logo.svg" alt="logo"/>
</div> </div>
<h1 class="m-b-3">Pozabljeno geslo - ŠOLAR</h1> <h1 class="m-b-3">Pozabljeno geslo - ŠOLAR</h1>
<div> <div>
<form method="POST" action="../sendresetpass" class="m-b-2"> <form method="POST" action="{{ROUTE_PREFIX}}/sendresetpass" class="m-b-2">
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/user.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/user.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>E-mail</label> <label>E-mail</label>
<input type="text" name="email"> <input type="text" name="email">
@@ -28,15 +30,15 @@
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
{% if messages %} {% if messages %}
<div class="alert alert-success"> <div class="alert alert-success">
<img src="../static/image/success.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/success.svg" alt="alert"/>
<p>{{ messages[0] }}</p> <p>{{ messages[0] }}</p>
</div> </div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<div class="back-to-login"> <div class="back-to-login">
<img src="../static/image/chevron-left.svg"/> <img src="{{ROUTE_PREFIX}}/static/image/chevron-left.svg"/>
<a href="../login">Nazaj na prijavo</a> <a href="{{ROUTE_PREFIX}}/login">Nazaj na prijavo</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,14 +3,16 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal ŠOLAR</title> <title>Portal ŠOLAR</title>
<link rel="stylesheet" href="../static/css/login-styles.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/utils.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/login-styles.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/utils.css" type="text/css">
</head> </head>
<body> <body>
<div class="background"> <div class="background">
<div class="panel login-panel"> <div class="panel login-panel">
<div class="panel-logo"> <div class="panel-logo">
<img src="../static/image/logo.svg" alt="logo"/> <img src="{{ROUTE_PREFIX}}/static/image/logo.svg" alt="logo"/>
</div> </div>
<h2 class="text-center">Portal za oddajanje besedil</h2> <h2 class="text-center">Portal za oddajanje besedil</h2>
<div class="line"></div> <div class="line"></div>
@@ -23,41 +25,41 @@
{% if messages %} {% if messages %}
{% if "potrditev" in messages[0] or "uspešna" in messages[0] %} {% if "potrditev" in messages[0] or "uspešna" in messages[0] %}
<div class="alert alert-success"> <div class="alert alert-success">
<img src="../static/image/success.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/success.svg" alt="alert"/>
<p>{{ messages[0] }}</p> <p>{{ messages[0] }}</p>
</div> </div>
{% else %} {% else %}
<div class="alert"> <div class="alert">
<img src="../static/image/alert.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/alert.svg" alt="alert"/>
<p>{{ messages[0] }}</p> <p>{{ messages[0] }}</p>
</div> </div>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<div> <div>
<form method="POST" action="../login" class="m-b-2"> <form method="POST" action="{{ROUTE_PREFIX}}/login" class="m-b-2">
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/user.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/user.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>E-mail</label> <label>E-mail</label>
<input type="text" name="email"> <input type="text" name="email">
</div> </div>
</div> </div>
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/password.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/password.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>Geslo</label> <label>Geslo</label>
<input type="password" name="password"> <input type="password" name="password">
</div> </div>
</div> </div>
<a href="../forgotpass" class="a-right m-b-1">Pozabljeno geslo</a> <a href="{{ROUTE_PREFIX}}/forgotpass" class="a-right m-b-1">Pozabljeno geslo</a>
<button class="btn" style="margin-left: 46px;">PRIJAVA</button> <button class="btn" style="margin-left: 46px;">PRIJAVA</button>
</form> </form>
</div> </div>
<a href="../register" class="register-button"> <a href="{{ROUTE_PREFIX}}/register" class="register-button">
<img src="../static/image/register.svg" alt="register"/> <img src="{{ROUTE_PREFIX}}/static/image/register.svg" alt="register"/>
<h3>Registracija</h3> <h3>Registracija</h3>
<p>Še nimate uporabniškega računa? Registrirajte se!</p> <p>Še nimate uporabniškega računa? Registrirajte se!</p>
</a> </a>

View File

@@ -3,36 +3,29 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Upravljanje institucije - Šolar</title> <title>Upravljanje institucije - Šolar</title>
<link rel="stylesheet" href="../static/css/header.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/form.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="../static/css/simple-grid.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/header.css" type="text/css">
<link rel="stylesheet" href="../static/css/slovenscina-admin.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/form.css" type="text/css">
<link rel="stylesheet" href="../static/css/manage-institution.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/simple-grid.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/slovenscina-admin.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/manage-institution.css" type="text/css">
</head> </head>
<body> <body>
<header> <header>
<div class="logo"><a href="../"><img src="../static/image/logo-white.svg"/></a></div> <div class="logo"><a href="{{ROUTE_PREFIX}}/"><img src="{{ROUTE_PREFIX}}/static/image/logo-white.svg"/></a></div>
<div class="dropdown"> <div class="menu-items">
<button class="dropbtn"><img src="/static/image/menu.svg"/></button> <a href="{{ROUTE_PREFIX}}/oddaja">Oddaja besedil</a>
<div class="dropdown-content"> {% if is_institution_coordinator %}
<a href="../oddaja">Oddaja</a> <a href="{{ROUTE_PREFIX}}/manage-institution">Upravljaj z ekipo</a>
<a href="../zgodovina">Zgodovina</a> {% endif %}
<a href="../pogodbe">Ekipa</a> {% if is_admin %}
{% if is_institution_coordinator %} <a href="{{ROUTE_PREFIX}}/admin">Administracijski meni</a>
<hr/> {% endif %}
<a href="../manage-institution">Upravljaj z institucijo</a> <a href="https://slovenscina.eu/" target="_blank">Več informacij o sodelovanju</a>
{% endif %} <a href="{{ROUTE_PREFIX}}/logout">Odjava</a>
{% if is_admin %}
<hr/>
<a href="../admin">Administracijski meni</a>
{% endif %}
<hr/>
<a href="https://slovenscina.eu/" target="_blank">Več informacij</a>
<hr/>
<a href="../logout">Odjava</a>
</div>
</div> </div>
</header> </header>
<div class="container" style="margin-top:8rem;"> <div class="container" style="margin-top:8rem;">
@@ -44,49 +37,82 @@
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<h1>{{institution.name}}</h1> <div class="row">
<h3>Seznam uporabnikov v vaši instituciji</h3> <div class="col-12">
<table class="tableFixHead"> <h1>{{institution.name}}</h1>
<thead> <h3>Seznam uporabnikov v vaši instituciji</h3>
<tr> <table class="tableFixHead">
<th>Ime in priimek</th> <thead>
<th>Email</th> <tr>
<th>Vloga</th> <th>Ime in priimek</th>
<th>Akcije</th> <th>Email</th>
</tr> <th>Vloga</th>
</thead> <th>Akcije</th>
<tbody> </tr>
{% for item in institution_users %} </thead>
<tr> <tbody>
<td>{{item.name}}</td> {% for item in institution_users %}
<td>{{item.email}}</td> <tr>
<td> <td>{{item.name}}</td>
<div> <td>{{item.email}}</td>
<a href="javascript:void(0);" onclick="toggleEditForm(this)" class="toggle-edit-role">Spremeni</a> <td>
{{role_map[item.id]}} <div>
</div> <a href="javascript:void(0);" onclick="toggleEditForm(this)" class="toggle-edit-role">Spremeni</a>
<form action="../changeuserrole-institution" method="post" style="display:none;"> {{role_map[item.id]}}
<input type="hidden" id="user-id" name="user-id" value="{{item.id}}"/> </div>
<select class="role" name="role"> <form action="{{ROUTE_PREFIX}}/changeuserrole-institution" method="post" style="display:none;">
<option value="coordinator">Koordinator/-ka</option> <input type="hidden" id="user-id" name="user-id" value="{{item.id}}"/>
<option value="mentor">Mentor/-ica</option> <select class="role" name="role">
<option value="other">Druga vloga</option> <option value="coordinator">Koordinator/-ka</option>
</select> <option value="mentor">Mentor/-ica</option>
<input type="submit" value="Shrani"/> <option value="other">Druga vloga</option>
</form> </select>
</td> <input type="submit" value="Shrani"/>
<td> </form>
<form action="../deluserfrominstitution" method="post"> </td>
<input type="hidden" id="user_id" name="user_id" value="{{item.id}}"> <td>
<input type="submit" value="Odstrani uporabnika"> <form action="{{ROUTE_PREFIX}}/deluserfrominstitution" method="post">
</form> <input type="hidden" id="user_id" name="user_id" value="{{item.id}}">
</td> <input type="submit" value="Odstrani uporabnika">
</tr> </form>
{% endfor %} </td>
</table> </tr>
{% endfor %}
</tbody>
</table>
</div>
</div> </div>
<form action="/institutionadduser" method="POST">
<div class="row">
<div class="col-6">
<h1>Dodaj uporabnika</h1>
<div class="form-wrapper">
<label for="regija">Ime</label>
<input type="text" name="name" />
</div>
<div class="form-wrapper">
<label for="regija">Email</label>
<input type="text" name="email" />
</div>
<div class="form-wrapper">
<label for="regija">Vloga</label>
<select class="role" name="role">
<option value="coordinator">Koordinator/-ka</option>
<option value="mentor">Mentor/-ica</option>
<option value="other">Druga vloga</option>
</select>
</div>
<input type="submit" class="btn" value="Dodaj"/>
</div>
</div>
</form>
<br> <br>
</div> </div>
</body> </body>
<script> <script>

View File

@@ -3,33 +3,25 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal za oddajanje besedil</title> <title>Portal za oddajanje besedil</title>
<link rel="stylesheet" href="../static/css/header.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/form.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="../static/css/simple-grid.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/header.css" type="text/css">
<link rel="stylesheet" href="../static/css/utils.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/form.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/simple-grid.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/utils.css" type="text/css">
</head> </head>
<body> <body>
<header> <header>
<div class="logo"><a href="../"><img src="../static/image/logo-white.svg"/></a></div> <div class="logo"><a href="{{ROUTE_PREFIX}}/"><img src="{{ROUTE_PREFIX}}/static/image/logo-white.svg"/></a></div>
<div class="dropdown"> <div class="menu-items">
<button class="dropbtn"><img src="/static/image/menu.svg"/></button> {% if is_institution_coordinator %}
<div class="dropdown-content"> <a href="{{ROUTE_PREFIX}}/manage-institution">Upravljaj z ekipo</a>
<a href="../oddaja">Oddaja</a> {% endif %}
<a href="../zgodovina">Zgodovina</a> {% if is_admin %}
<a href="../pogodbe">Ekipa</a> <a href="{{ROUTE_PREFIX}}/admin">Administracijski meni</a>
{% if is_institution_coordinator %} {% endif %}
<hr/> <a href="https://slovenscina.eu/" target="_blank">Več informacij o sodelovanju</a>
<a href="../manage-institution">Upravljaj z institucijo</a> <a href="{{ROUTE_PREFIX}}/logout">Odjava</a>
{% endif %}
{% if is_admin %}
<hr/>
<a href="../admin">Administracijski meni</a>
{% endif %}
<hr/>
<a href="https://slovenscina.eu/" target="_blank">Več informacij</a>
<hr/>
<a href="../logout">Odjava</a>
</div>
</div> </div>
</header> </header>
<div class="container" style="margin-top:8rem;"> <div class="container" style="margin-top:8rem;">
@@ -40,9 +32,9 @@
<div class="tab-nav"> <div class="tab-nav">
<a href="../oddaja" class="active">Oddaja besedil</a> <a href="{{ROUTE_PREFIX}}/oddaja" class="active">Oddaja besedil</a>
<a href="../zgodovina">Zgodovina sodelovanja</a> <a href="{{ROUTE_PREFIX}}/zgodovina">Zgodovina sodelovanja</a>
<a href="../pogodbe">Ekipa</a> <a href="{{ROUTE_PREFIX}}/pogodbe">Ekipa</a>
</div> </div>
</div> </div>
</div> </div>
@@ -53,21 +45,21 @@
<div class="col-6"> <div class="col-6">
{% if not institution %} {% if not institution %}
<div class="alert"> <div class="alert">
<img src="../static/image/alert.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/alert.svg" alt="alert"/>
<p>Niste član nobene institucije!</p> <p>Niste član nobene institucije!</p>
</div> </div>
{% elif not institution_contract %} {% elif not institution_contract %}
<!--<div class="alert"> <!--<div class="alert">
<img src="../static/image/alert.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/alert.svg" alt="alert"/>
<p>Pogodba s šolo še ni naložena!</p> <p>Pogodba s šolo še ni naložena!</p>
</div>--> </div>-->
{% endif %} {% endif %}
<div class="alert" id="error-message"> <div class="alert" id="error-message">
<img src="../static/image/alert.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/alert.svg" alt="alert"/>
<p></p> <p></p>
</div> </div>
<div class="alert alert-success" id="success-message"> <div class="alert alert-success" id="success-message">
<img src="../static/image/success.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/success.svg" alt="alert"/>
<p></p> <p></p>
</div> </div>
</div> </div>
@@ -152,7 +144,7 @@
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
<div class="form-wrapper"> <div class="form-wrapper">
<label for="letnik">Letnik</label> <label for="letnik">Razred/Letnik</label>
<select id="letnik" name="letnik"> <select id="letnik" name="letnik">
<option value="1" selected="selected">1</option> <option value="1" selected="selected">1</option>
<option value="2">2</option> <option value="2">2</option>
@@ -177,7 +169,7 @@
<label for="vrsta">Vrsta besedila</label> <label for="vrsta">Vrsta besedila</label>
<select id="vrsta" name="vrsta"> <select id="vrsta" name="vrsta">
<option value="E" selected="selected">Esej ali spis (E)</option> <option value="E" selected="selected">Esej ali spis (E)</option>
<option value="PB">Praktično besedilo (npr. vabila, prošnje ipd. pri pouku slovenščine), napisano za oceno (PB)</option> <option value="PB">Praktično besedilo, napisano za oceno - npr. vabilo, prošnja ali podobno (PE)</option>
<option value="T">Šolski test (T)</option> <option value="T">Šolski test (T)</option>
<option value="R">Delo v razredu, ne za oceno (vtipkajte besedilo vrsto) (R)</option> <option value="R">Delo v razredu, ne za oceno (vtipkajte besedilo vrsto) (R)</option>
</select> </select>
@@ -281,7 +273,7 @@
<!--{{ dropzone.load_js() }}--> <!--{{ dropzone.load_js() }}-->
<script src="../static/dropzone.js"></script> <script src="{{ROUTE_PREFIX}}/static/dropzone.js"></script>
<script> <script>
///////////////////////// /////////////////////////
// Dropzone // // Dropzone //
@@ -350,7 +342,7 @@
Dropzone.options.myDropzone = { // The camelized version of the ID of the form element Dropzone.options.myDropzone = { // The camelized version of the ID of the form element
url: "../upload", url: "{{ROUTE_PREFIX}}/upload",
autoProcessQueue: false, autoProcessQueue: false,
uploadMultiple: true, uploadMultiple: true,
parallelUploads: 20, parallelUploads: 20,

View File

@@ -3,33 +3,25 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal za oddajanje besedil</title> <title>Portal za oddajanje besedil</title>
<link rel="stylesheet" href="../static/css/header.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/form.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="../static/css/simple-grid.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/header.css" type="text/css">
<link rel="stylesheet" href="../static/css/contracts.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/form.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/simple-grid.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/contracts.css" type="text/css">
</head> </head>
<body> <body>
<header> <header>
<div class="logo"><a href="../"><img src="../static/image/logo-white.svg"/></a></div> <div class="logo"><a href="{{ROUTE_PREFIX}}/"><img src="{{ROUTE_PREFIX}}/static/image/logo-white.svg"/></a></div>
<div class="dropdown"> <div class="menu-items">
<button class="dropbtn"><img src="/static/image/menu.svg"/></button> {% if is_institution_coordinator %}
<div class="dropdown-content"> <a href="{{ROUTE_PREFIX}}/manage-institution">Upravljaj z ekipo</a>
<a href="../oddaja">Oddaja</a> {% endif %}
<a href="../zgodovina">Zgodovina</a> {% if is_admin %}
<a href="../pogodbe">Ekipa</a> <a href="{{ROUTE_PREFIX}}/admin">Administracijski meni</a>
{% if is_institution_coordinator %} {% endif %}
<hr/> <a href="https://slovenscina.eu/" target="_blank">Več informacij o sodelovanju</a>
<a href="../manage-institution">Upravljaj z institucijo</a> <a href="{{ROUTE_PREFIX}}/logout">Odjava</a>
{% endif %}
{% if is_admin %}
<hr/>
<a href="../admin">Administracijski meni</a>
{% endif %}
<hr/>
<a href="https://slovenscina.eu/" target="_blank">Več informacij</a>
<hr/>
<a href="../logout">Odjava</a>
</div>
</div> </div>
</header> </header>
<div class="container" style="margin-top:8rem;"> <div class="container" style="margin-top:8rem;">
@@ -39,9 +31,9 @@
<p class="subtitle"></p> <p class="subtitle"></p>
<div class="tab-nav"> <div class="tab-nav">
<a href="../oddaja">Oddaja besedil</a> <a href="{{ROUTE_PREFIX}}/oddaja">Oddaja besedil</a>
<a href="../zgodovina">Zgodovina sodelovanja</a> <a href="{{ROUTE_PREFIX}}/zgodovina">Zgodovina sodelovanja</a>
<a href="../pogodbe" class="active">Ekipa</a> <a href="{{ROUTE_PREFIX}}/pogodbe" class="active">Ekipa</a>
</div> </div>
</div> </div>
</div> </div>
@@ -82,14 +74,34 @@
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
<div class="team-item"> <div class="team-item">
<div class="team-item-name">{{entry.name}} <span class="team-item-role">{%if entry.role == "mentor" %}Mentor{%elif entry.role == "coordinator" %}Koordinator{%elif entry.role == "other" %}Druga vloga{%endif%}</span></div> <div class="team-item-name">{{entry.name}} <span class="team-item-role">{%if entry.role == "mentor" %}Mentor/-ica{%elif entry.role == "coordinator" %}Koordinator/-ica{%elif entry.role == "other" %}Druga vloga{%endif%}</span></div>
</div> </div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
<div class="row" id="my_dataviz__region_title">
<div class="col-12">
<h2>Število vseh oddaj po regijah</h2>
</div>
</div>
<div class="row">
<div class="col-6">
<div id="my_dataviz_region">
</div>
<div>
<div style="display:inline-block;width:12px;height:12px;background:#006CB7"></div>
<p style="display:inline-block">Osnovne šole</p>
<div style="margin-left:32px;display:inline-block;width:12px;height:12px;background:#B86D00"></div>
<p style="display:inline-block">Sredje šole</p>
</div>
</div>
</div>
</div> </div>
@@ -106,6 +118,12 @@
#my_dataviz path.domain{ #my_dataviz path.domain{
visibility:hidden; visibility:hidden;
} }
#my_dataviz_region .tick line{
visibility:hidden;
}
#my_dataviz_region path.domain{
visibility:hidden;
}
</style> </style>
<script> <script>
var data; var data;
@@ -168,10 +186,77 @@
.attr("width", function(d) { return x(d.value); }) .attr("width", function(d) { return x(d.value); })
.attr("height", 32 ) .attr("height", 32 )
.attr("fill", "#006CB7"); .attr("fill", "#006CB7");
})
</script>
<script>
var data;
// Parse the Data
d3.json("/uploadstats-per-region").then(function(jsondata) {
data = [];
console.log(Object.keys(jsondata).length);
var margin = {top: 20, right: 0, bottom: 40, left: 0};
var width = document.getElementById("my_dataviz_region").clientWidth - margin.left - margin.right;
var height = Object.keys(jsondata).length * 56;
var svg = d3.select("#my_dataviz_region")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("overflow","visible")
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
for(var key in jsondata) {
data.push({'name': key, 'value':jsondata[key]});
}
console.log(data);
// Add X axis
var x = d3.scaleLinear()
.domain([0,d3.max(data, function (d) { return Math.max(...d.value)})])
.range([ 0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "center");
// Y axis
var y = d3.scaleBand()
.range([ 0, data.length*56 ])
.domain(data.map(function(d) { return d.name; }))
.padding(0);
svg.append("g")
.call(d3.axisLeft(y))
.selectAll("text")
.style("text-anchor", "start")
.style("font-size", "14px")
.attr("transform", "translate(8,-36)");
//Bars
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0) )
.attr("y", function(d) { return y(d.name); })
.attr("width", function(d) { return x(d.value[0]); })
.attr("height", 16 )
.attr("fill", "#006CB7");
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0) )
.attr("y", function(d) { return y(d.name); })
.attr("width", function(d) { return x(d.value[1]); })
.attr("height", 16 )
.attr("transform", "translate(0,16)")
.attr("fill", "#B86D00");
}) })
</script> </script>

View File

@@ -3,15 +3,17 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal ŠOLAR</title> <title>Portal ŠOLAR</title>
<link rel="stylesheet" href="../static/css/login-styles.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/utils.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/login-styles.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/utils.css" type="text/css">
</head> </head>
<body> <body>
<div class="background"> <div class="background">
<div class="panel login-panel"> <div class="panel login-panel">
<div class="panel-logo"> <div class="panel-logo">
<img src="../static/image/logo.svg" alt="logo"/> <img src="{{ROUTE_PREFIX}}/static/image/logo.svg" alt="logo"/>
</div> </div>
<h2 class="text-center">Portal za oddajanje besedil</h2> <h2 class="text-center">Portal za oddajanje besedil</h2>
<div class="line"></div> <div class="line"></div>
@@ -23,29 +25,29 @@
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
{% if messages %} {% if messages %}
<div class="alert"> <div class="alert">
<img src="../static/image/alert.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/alert.svg" alt="alert"/>
<p>{{ messages[0] }}</p> <p>{{ messages[0] }}</p>
</div> </div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<div> <div>
<form method="POST" action="../register" class="m-b-2"> <form method="POST" action="{{ROUTE_PREFIX}}/register" class="m-b-2">
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/user.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/user.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>Ime in priimek</label> <label>Ime in priimek</label>
<input type="name" name="name" autofocus=""> <input type="name" name="name" autofocus="">
</div> </div>
</div> </div>
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/user.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/user.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>Email</label> <label>Email</label>
<input type="email" name="email"> <input type="email" name="email">
</div> </div>
</div> </div>
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/password.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/password.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>Geslo</label> <label>Geslo</label>
<input type="password" name="password"> <input type="password" name="password">
@@ -53,14 +55,14 @@
</div> </div>
</div> </div>
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/user.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/user.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>Naziv institucije</label> <label>Naziv institucije</label>
<input type="institution" name="institution"> <input type="institution" name="institution">
</div> </div>
</div> </div>
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/password.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/password.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>Vloga v instituciji</label> <label>Vloga v instituciji</label>
<select id="role" name="role" > <select id="role" name="role" >
@@ -75,8 +77,8 @@
</div> </div>
<div class="back-to-login"> <div class="back-to-login">
<img src="../static/image/chevron-left.svg"/> <img src="{{ROUTE_PREFIX}}/static/image/chevron-left.svg"/>
<a href="../login">Nazaj na prijavo</a> <a href="{{ROUTE_PREFIX}}/login">Nazaj na prijavo</a>
</div> </div>

View File

@@ -3,20 +3,22 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal ŠOLAR</title> <title>Portal ŠOLAR</title>
<link rel="stylesheet" href="../static/css/login-styles.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/utils.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/login-styles.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/utils.css" type="text/css">
</head> </head>
<body> <body>
<div class="background"> <div class="background">
<div class="panel login-panel"> <div class="panel login-panel">
<div class="panel-logo"> <div class="panel-logo">
<img src="../static/image/logo.svg" alt="logo"/> <img src="{{ROUTE_PREFIX}}/static/image/logo.svg" alt="logo"/>
</div> </div>
<h1 class="m-b-3">Ponastavitev gesla - ŠOLAR</h1> <h1 class="m-b-3">Ponastavitev gesla - ŠOLAR</h1>
<div> <div>
<form method="POST" action="" class="m-b-2"> <form method="POST" action="" class="m-b-2">
<div class="input-wrapper"> <div class="input-wrapper">
<img src="../static/image/password.svg" alt="user" class="input-icon"/> <img src="{{ROUTE_PREFIX}}/static/image/password.svg" alt="user" class="input-icon"/>
<div class="input-floating-label"> <div class="input-floating-label">
<label>Novo geslo</label> <label>Novo geslo</label>
<input type="password" name="new_password"> <input type="password" name="new_password">
@@ -29,7 +31,7 @@
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
{% if messages %} {% if messages %}
<div class="alert"> <div class="alert">
<img src="../static/image/alert.svg" alt="alert"/> <img src="{{ROUTE_PREFIX}}/static/image/alert.svg" alt="alert"/>
<p>{{ messages[0] }}</p> <p>{{ messages[0] }}</p>
</div> </div>
{% endif %} {% endif %}

View File

@@ -3,35 +3,27 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Portal za oddajanje besedil</title> <title>Portal za oddajanje besedil</title>
<!--<link rel="stylesheet" href="../static/style.css" type="text/css">--> <!--<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/style.css" type="text/css">-->
<script src="../static/chart.js"></script> <script src="{{ROUTE_PREFIX}}/static/chart.js"></script>
<link rel="stylesheet" href="../static/css/header.css" type="text/css"> <link rel="icon" href="/static/favicon.ico" type="image/x-icon" >
<link rel="stylesheet" href="../static/css/form.css" type="text/css"> <link rel="icon" href="static/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="../static/css/simple-grid.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/header.css" type="text/css">
<link rel="stylesheet" href="../static/css/history.css" type="text/css"> <link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/form.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/simple-grid.css" type="text/css">
<link rel="stylesheet" href="{{ROUTE_PREFIX}}/static/css/history.css" type="text/css">
</head> </head>
<body> <body>
<header> <header>
<div class="logo"><a href="../"><img src="../static/image/logo-white.svg"/></a></div> <div class="logo"><a href="{{ROUTE_PREFIX}}/"><img src="{{ROUTE_PREFIX}}/static/image/logo-white.svg"/></a></div>
<div class="dropdown"> <div class="menu-items">
<button class="dropbtn"><img src="/static/image/menu.svg"/></button> {% if is_institution_coordinator %}
<div class="dropdown-content"> <a href="{{ROUTE_PREFIX}}/manage-institution">Upravljaj z ekipo</a>
<a href="../oddaja">Oddaja</a> {% endif %}
<a href="../zgodovina">Zgodovina</a> {% if is_admin %}
<a href="../pogodbe">Ekipa</a> <a href="{{ROUTE_PREFIX}}/admin">Administracijski meni</a>
{% if is_institution_coordinator %} {% endif %}
<hr/> <a href="https://slovenscina.eu/" target="_blank">Več informacij o sodelovanju</a>
<a href="../manage-institution">Upravljaj z institucijo</a> <a href="{{ROUTE_PREFIX}}/logout">Odjava</a>
{% endif %}
{% if is_admin %}
<hr/>
<a href="../admin">Administracijski meni</a>
{% endif %}
<hr/>
<a href="https://slovenscina.eu/" target="_blank">Več informacij</a>
<hr/>
<a href="../logout">Odjava</a>
</div>
</div> </div>
</header> </header>
<div class="container" style="margin-top:8rem;"> <div class="container" style="margin-top:8rem;">
@@ -42,9 +34,9 @@
<div class="tab-nav"> <div class="tab-nav">
<a href="../oddaja">Oddaja besedil</a> <a href="{{ROUTE_PREFIX}}/oddaja">Oddaja besedil</a>
<a href="../zgodovina" class="active">Zgodovina sodelovanja</a> <a href="{{ROUTE_PREFIX}}/zgodovina" class="active">Zgodovina sodelovanja</a>
<a href="../pogodbe">Ekipa</a> <a href="{{ROUTE_PREFIX}}/pogodbe">Ekipa</a>
</div> </div>
</div> </div>
</div> </div>
@@ -143,7 +135,7 @@
<div class="history-item-date">Dodano {{ item.timestamp.strftime('%d. %m. %Y') }}</div> <div class="history-item-date">Dodano {{ item.timestamp.strftime('%d. %m. %Y') }}</div>
<div class="history-item-uploader">{{ uploader_names[loop.index - 1] }}</div> <div class="history-item-uploader">{{ uploader_names[loop.index - 1] }}</div>
<div class="history-item-filecount">Št. datotek: {{ item.upload_file_hashes|length }}</div> <div class="history-item-filecount">Št. datotek: {{ item.upload_file_hashes|length }}</div>
<div class="history-item-chevron"><img src="../static/image/chevron-down.svg"/></div> <div class="history-item-chevron"><img src="{{ROUTE_PREFIX}}/static/image/chevron-down.svg"/></div>
<div class="history-item-desc"> <div class="history-item-desc">
{{ item_values | join(" | ") |truncate(120) }} {{ item_values | join(" | ") |truncate(120) }}
</div> </div>
@@ -160,7 +152,7 @@
{% if item.upload_file_names != None %} {% if item.upload_file_names != None %}
{% for f_name in item.upload_file_names %} {% for f_name in item.upload_file_names %}
<div class="file-item"> <div class="file-item">
<div class="file-icon"><img src="../static/image/file.svg"/></div> <div class="file-icon"><img src="{{ROUTE_PREFIX}}/static/image/file.svg"/></div>
<a href="getuploadfile/{{item.id}}/{{item.upload_file_hashes[loop.index - 1]}}" class="file-name" {% if item.upload_file_codes != None %}download="{{item.upload_file_codes[loop.index - 1]}}.{{f_name.split('.')[1]}}"{%endif%}> <a href="getuploadfile/{{item.id}}/{{item.upload_file_hashes[loop.index - 1]}}" class="file-name" {% if item.upload_file_codes != None %}download="{{item.upload_file_codes[loop.index - 1]}}.{{f_name.split('.')[1]}}"{%endif%}>
{% if item.upload_file_codes != None %} {% if item.upload_file_codes != None %}
{{item.upload_file_codes[loop.index - 1]}}.{{f_name.split('.')[1]}} {{item.upload_file_codes[loop.index - 1]}}.{{f_name.split('.')[1]}}
@@ -177,7 +169,7 @@
{% else %} {% else %}
{% for f_hash in item.upload_file_hashes %} {% for f_hash in item.upload_file_hashes %}
<div class="file-item"> <div class="file-item">
<div class="file-icon"><img src="../static/image/file.svg"/></div> <div class="file-icon"><img src="{{ROUTE_PREFIX}}/static/image/file.svg"/></div>
<a href="getuploadfile/{{item.id}}/{{f_hash}}" class="file-name">{{f_hash}}</a> <a href="getuploadfile/{{item.id}}/{{f_hash}}" class="file-name">{{f_hash}}</a>
</div> </div>
{% endfor %} {% endfor %}