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 && \ | 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 | 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"] | ENTRYPOINT ["./entrypoint.sh"] | ||||||
|  | |||||||
							
								
								
									
										324
									
								
								app.py
									
									
									
									
									
								
							
							
						
						
									
										324
									
								
								app.py
									
									
									
									
									
								
							| @ -5,7 +5,7 @@ import configparser | |||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from werkzeug.security import check_password_hash | 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_dropzone import Dropzone | ||||||
| from flask_migrate import Migrate, MigrateCommand | from flask_migrate import Migrate, MigrateCommand | ||||||
| from flask_script import Manager | from flask_script import Manager | ||||||
| @ -15,7 +15,6 @@ from portal.model import db, RegisteredUser | |||||||
| import portal.base | import portal.base | ||||||
| import portal.solar | import portal.solar | ||||||
| import portal.regular | import portal.regular | ||||||
| import portal.predavanja |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # TODO: Implement user registration. | # 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'] | CONTRACT_CLIENT_CONTACT = config['CONTRACT_CLIENT_CONTACT'] | ||||||
| MAIL_SUBJECT = config['MAIL_SUBJECT'] | MAIL_SUBJECT = config['MAIL_SUBJECT'] | ||||||
| MAIL_BODY = config['MAIL_BODY'] | 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'] | SQL_CONN_STR = config['SQL_CONN_STR'] | ||||||
| DESC_PREVODI = config['DESC_PREVODI'] | DESC_PREVODI = config['DESC_PREVODI'] | ||||||
| DESC_GIGAFIDA = config['DESC_GIGAFIDA'] | DESC_GIGAFIDA = config['DESC_GIGAFIDA'] | ||||||
| DESC_PREDAVANJA = config['DESC_PREDAVANJA'] |  | ||||||
| 
 | 
 | ||||||
| if 'UPLOADS_DIR' in config: | if 'UPLOADS_DIR' in config: | ||||||
|     UPLOADS_DIR = Path(config['UPLOADS_DIR']) |     UPLOADS_DIR = Path(config['UPLOADS_DIR']) | ||||||
| @ -83,10 +79,6 @@ if 'PORTALDS4DS1_MAIL_SUBJECT' in os.environ: | |||||||
|     MAIL_SUBJECT = os.environ['PORTALDS4DS1_MAIL_SUBJECT'] |     MAIL_SUBJECT = os.environ['PORTALDS4DS1_MAIL_SUBJECT'] | ||||||
| if 'PORTALDS4DS1_MAIL_BODY' in os.environ: | if 'PORTALDS4DS1_MAIL_BODY' in os.environ: | ||||||
|     MAIL_BODY = os.environ['PORTALDS4DS1_MAIL_BODY'] |     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: | if 'PORTALDS4DS1_SQL_CONN_STR' in os.environ: | ||||||
|     SQL_CONN_STR = os.environ['PORTALDS4DS1_SQL_CONN_STR'] |     SQL_CONN_STR = os.environ['PORTALDS4DS1_SQL_CONN_STR'] | ||||||
| if 'PORTALDS4DS1_DESC_PREVODI' in os.environ: | 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: | if 'PORTALDS4DS1_DESC_GIGAFIDA' in os.environ: | ||||||
|     DESC_GIGAFIDA = os.environ['PORTALDS4DS1_DESC_GIGAFIDA'] |     DESC_GIGAFIDA = os.environ['PORTALDS4DS1_DESC_GIGAFIDA'] | ||||||
| 
 | 
 | ||||||
| ENABLED_CORPUSES = ['prevodi', 'gigafida', 'solar', 'predavanja'] | ENABLED_CORPUSES = ['prevodi', 'gigafida', 'solar'] | ||||||
| CORPUSES_LOGIN_REQUIRED = ['solar'] | CORPUSES_LOGIN_REQUIRED = ['solar'] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -147,25 +139,18 @@ upload_handler_solar = portal.solar.UploadHandlerSolar( | |||||||
|         MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD |         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. | # Use flask-login to manage user sessions where they are required. | ||||||
| login_manager = LoginManager(app) | login_manager = LoginManager(app) | ||||||
| login_manager.init_app(app) | login_manager.init_app(app) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def redirect_url(default='/'): | ||||||
|  |     return request.args.get('next') or \ | ||||||
|  |            request.referrer or \ | ||||||
|  |            url_for(default) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @app.route('/') | @app.route('/') | ||||||
| def index(): | def index(): | ||||||
|     return render_template('index.html') |     return render_template('index.html') | ||||||
| @ -180,8 +165,6 @@ def index_corpus(corpus_name): | |||||||
|         description = DESC_PREVODI |         description = DESC_PREVODI | ||||||
|     elif corpus_name == 'gigafida': |     elif corpus_name == 'gigafida': | ||||||
|         description = DESC_GIGAFIDA |         description = DESC_GIGAFIDA | ||||||
|     elif corpus_name == 'predavanja': |  | ||||||
|         return render_template('basic-predavanja.html', description=DESC_PREDAVANJA, max_files=MAX_FILES_PER_UPLOAD) |  | ||||||
|     elif corpus_name == 'solar': |     elif corpus_name == 'solar': | ||||||
|         if current_user.is_authenticated: |         if current_user.is_authenticated: | ||||||
|             return redirect('/solar/oddaja') |             return redirect('/solar/oddaja') | ||||||
| @ -198,15 +181,17 @@ def load_user(user_id): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.route('/solar/login') | @app.route('/solar/login') | ||||||
| def login_get(): | def solar_login_get(): | ||||||
|     return render_template('login.html', corpus_name='solar', title='ŠOLAR') |     return render_template('solar-login.html') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.route('/<corpus_name>/login', methods=['POST']) | @app.route('/solar/register') | ||||||
| def login_post(corpus_name): | def solar_register_get(): | ||||||
|     if corpus_name not in ENABLED_CORPUSES or corpus_name not in CORPUSES_LOGIN_REQUIRED: |     return render_template('solar-register.html') | ||||||
|         return '', 404 |  | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | @app.route('/solar/login', methods=['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') | ||||||
|     remember = True if request.form.get('remember') else False |     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): |     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'.format(corpus_name)) |         return redirect('/solar/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'.format(corpus_name)) |         return redirect('/solar/login') | ||||||
| 
 |  | ||||||
|     # 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)) |  | ||||||
| 
 | 
 | ||||||
|     #portal.base.add_user_session(user.id) |     #portal.base.add_user_session(user.id) | ||||||
|     login_user(user, remember=remember) |     login_user(user, remember=remember) | ||||||
| 
 | 
 | ||||||
|     if corpus_name == 'solar': |  | ||||||
|     return redirect('/solar/oddaja') |     return redirect('/solar/oddaja') | ||||||
|     return '', 404 | 
 | ||||||
|  | 
 | ||||||
|  | @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. | # TODO: Move solar stuff to seperate file using Flask blueprints. | ||||||
| @ -247,10 +268,15 @@ def logout(): | |||||||
| @app.route('/solar/<path:text>') | @app.route('/solar/<path:text>') | ||||||
| @login_required | @login_required | ||||||
| def solar(text): | def solar(text): | ||||||
|     if not portal.base.has_user_corpus_access(current_user.id, 'solar'): |     is_admin = current_user.role == 'admin' | ||||||
|         return '', 404 |     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': |     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': |     elif text.startswith('zgodovina/') or text == 'zgodovina': | ||||||
|         upload_items = portal.solar.get_upload_history(current_user.id) |         upload_items = portal.solar.get_upload_history(current_user.id) | ||||||
|         uploader_names = [] |         uploader_names = [] | ||||||
| @ -263,7 +289,7 @@ 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) |                 institution_names=institution_names, is_admin=is_admin, is_institution_moderator=current_user_institution_moderator) | ||||||
|     elif text.startswith('pogodbe/') or text == 'pogodbe': |     elif text.startswith('pogodbe/') or text == 'pogodbe': | ||||||
|         # Check for ownload contract request. |         # Check for ownload contract request. | ||||||
|         match = re.match('^pogodbe/([a-z0-9_]+\.pdf)$', text) |         match = re.match('^pogodbe/([a-z0-9_]+\.pdf)$', text) | ||||||
| @ -281,72 +307,154 @@ def solar(text): | |||||||
|                 return '', 404 |                 return '', 404 | ||||||
| 
 | 
 | ||||||
|         user_obj = portal.base.get_user_obj(current_user.get_id()) |         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 = [] |         contracts_students = [] | ||||||
|         contract_school = [] |         contract_school = [] | ||||||
|         enable_upload_school_contract = False |         enable_upload_school_contract = False | ||||||
|         show_upload_form = 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 |             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) |             contract_school = portal.solar.get_institution_contract(institution.id) | ||||||
| 
 |  | ||||||
|             if portal.base.is_institution_moderator(user_obj.id, 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 |                 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, |         return render_template('solar-pogodbe.html', 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, | ||||||
|  |                 collaborators=collaborators, | ||||||
|  |                 is_admin=is_admin, is_institution_moderator=current_user_institution_moderator) | ||||||
|     elif text.startswith('admin/') or text == 'admin': |     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() |         solar_institutions = portal.solar.get_all_institutions() | ||||||
|         if current_user.role == 'admin': |         if is_admin: | ||||||
|             return render_template('solar-admin.html', users=solar_users, institutions=solar_institutions) |             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 |     return '', 404 | ||||||
| 
 | 
 | ||||||
| @app.route('/solar/pogodbe', methods=['POST']) | @app.route('/solar/pogodbe', methods=['POST']) | ||||||
| @login_required | @login_required | ||||||
| def solar_upload_contract(): | 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()) |     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 | @login_required | ||||||
| def solar_add_user(corpus_name): | def solar_add_user(): | ||||||
|  | 
 | ||||||
|     if not portal.base.is_admin(current_user.id): |     if not portal.base.is_admin(current_user.id): | ||||||
|         return '', 404 |         return '', 404 | ||||||
|     if not corpus_name in ENABLED_CORPUSES: |  | ||||||
|         return '', 404 |  | ||||||
| 
 | 
 | ||||||
|     name = request.form['name'] |     name = request.form.get('name') | ||||||
|     email = request.form['email'] |     email = request.form.get('email') | ||||||
|     password = request.form['password'] |     password = request.form.get('password') | ||||||
| 
 | 
 | ||||||
|     if not name: |     if not name: | ||||||
|         return 'Prazno polje za ime.' |         flash('Prazno polje za ime.') | ||||||
|  |         return redirect(redirect_url()) | ||||||
|     if len(name) > 100: |     if len(name) > 100: | ||||||
|         return 'Predolgo ime.' |         flash('Predolgo ime.') | ||||||
|  |         return redirect(redirect_url()) | ||||||
| 
 | 
 | ||||||
|     if not email: |     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: |     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): |     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: |     if not password: | ||||||
|         return 'Prazno polje za geslo.' |         flash('Prazno polje za geslo.') | ||||||
|  |         return redirect(redirect_url()) | ||||||
|     if len(password) > 100: |     if len(password) > 100: | ||||||
|         return 'Predolgo geslo.' |         flash('Predolgo geslo.') | ||||||
|  |         return redirect(redirect_url()) | ||||||
| 
 | 
 | ||||||
|     portal.base.register_new_user(name, email, password) |     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']) | @app.route('/solar/deluser', methods=['POST']) | ||||||
| @ -364,44 +472,76 @@ def add_institution(corpus_name): | |||||||
|     if not corpus_name in ENABLED_CORPUSES: |     if not corpus_name in ENABLED_CORPUSES: | ||||||
|         return '', 404 |         return '', 404 | ||||||
| 
 | 
 | ||||||
|     name = request.form['name'] |     name = request.form.get('name') | ||||||
|     region = request.form['region'] |     region = request.form.get('region') | ||||||
| 
 | 
 | ||||||
|     if not name: |     if not name: | ||||||
|         return 'Prazno polje za ime.' |         flash('Prazno polje za ime.') | ||||||
|  |         return redirect(redirect_url()) | ||||||
|     if len(name) > 100: |     if len(name) > 100: | ||||||
|         return 'Predolgo ime.' |         flash('Predolgo ime.') | ||||||
|  |         return redirect(redirect_url()) | ||||||
| 
 | 
 | ||||||
|     if not region: |     if not region: | ||||||
|         return 'Prazno polje za regijo.' |         flash('Prazno polje za regijo.') | ||||||
|  |         return redirect(redirect_url()) | ||||||
|     if len(region) > 100: |     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) |     institution_id = portal.base.add_institution(name, region) | ||||||
|     portal.base.grant_institution_corpus_access(institution_id, corpus_name) |     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']) | @app.route('/<corpus_name>/addusertoinstitution', methods=['POST']) | ||||||
| @login_required | @login_required | ||||||
| def add_user_institution_mapping(corpus_name): | 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 |         return '', 404 | ||||||
|     if not corpus_name in ENABLED_CORPUSES: |     if not corpus_name in ENABLED_CORPUSES: | ||||||
|         return '', 404 |         return '', 404 | ||||||
| 
 | 
 | ||||||
|     user_id = request.form['user_id'] |     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 not portal.base.is_institution_member(user_id, institution.id): | ||||||
|     if len(portal.base.get_user_institutions(user_id)) > 0: |         flash('Uporabnik ni član vaše institucije.') | ||||||
|         return 'Uporabnik je že dodeljen instituciji. Dodeljevanje večim institucijam '\ |         return redirect(redirect_url()) | ||||||
|                 'zaenkrat ni implementirano.' |  | ||||||
| 
 | 
 | ||||||
|     portal.base.add_user_to_institution(user_id, institution_id, role) |     portal.base.del_user_from_institution(user_id, institution.id) | ||||||
|     return 'Uporabnik je bil dodeljen instituciji.' |     flash('Uporabnik je bil odstranjen iz institucije.') | ||||||
|  |     return redirect(redirect_url()) | ||||||
| 
 | 
 | ||||||
| @app.route('/<corpus_name>/delinstitution', methods=['POST']) | @app.route('/<corpus_name>/delinstitution', methods=['POST']) | ||||||
| @login_required | @login_required | ||||||
| @ -420,11 +560,9 @@ def handle_upload(corpus_name): | |||||||
|     if corpus_name == 'solar': |     if corpus_name == 'solar': | ||||||
|         if not current_user.is_authenticated: |         if not current_user.is_authenticated: | ||||||
|             return '', 404 |             return '', 404 | ||||||
|         if not portal.base.has_user_corpus_access(current_user.id, corpus_name): |         #if not portal.base.has_user_corpus_access(current_user.id, corpus_name): | ||||||
|             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()) | ||||||
|     elif corpus_name == 'predavanja': |  | ||||||
|         return upload_handler_predavanja.handle_upload(request) |  | ||||||
|     else: |     else: | ||||||
|         return upload_handler_regular.handle_upload(request, corpus_name) |         return upload_handler_regular.handle_upload(request, corpus_name) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,17 +12,9 @@ UPLOADS_DIR=./uploads | |||||||
| CONTRACT_CLIENT_CONTACT=Testko Tester | CONTRACT_CLIENT_CONTACT=Testko Tester | ||||||
| DESC_PREVODI=<h2 id="subtitle">Prevodi</h2><p>Strojno prevajanje je ena od uporabnih jezikovnih tehnologij, saj omogoča hitro sporazumevanje med ljudmi iz različnih kultur in jezikovnih okolij. Več o razvoju slovenskega strojnega prevajalnika lahko preberete na tej <a href="https://slovenscina.eu/strojno-prevajanje">povezavi</a>. Za kakovosten strojni prevajalnik so ključnega pomena prevodi, iz kateri se algoritmi umetne inteligence naučijo prevajati. S prispevanjem besedil v korpus prevodov boste pomembno prispevali k razvoju slovenskega strojnega prevajalnika med angleščino in slovenščino. Več informacij o prispevanju besedil najdete <a href="https://slovenscina.eu/zbiranje-besedil">tukaj</a>.</p> | DESC_PREVODI=<h2 id="subtitle">Prevodi</h2><p>Strojno prevajanje je ena od uporabnih jezikovnih tehnologij, saj omogoča hitro sporazumevanje med ljudmi iz različnih kultur in jezikovnih okolij. Več o razvoju slovenskega strojnega prevajalnika lahko preberete na tej <a href="https://slovenscina.eu/strojno-prevajanje">povezavi</a>. Za kakovosten strojni prevajalnik so ključnega pomena prevodi, iz kateri se algoritmi umetne inteligence naučijo prevajati. S prispevanjem besedil v korpus prevodov boste pomembno prispevali k razvoju slovenskega strojnega prevajalnika med angleščino in slovenščino. Več informacij o prispevanju besedil najdete <a href="https://slovenscina.eu/zbiranje-besedil">tukaj</a>.</p> | ||||||
| DESC_GIGAFIDA=<h2 id="subtitle">Gigafida</h2><p><a href="https://viri.cjvt.si/gigafida/">Gigafida</a> je referenčni korpus pisne slovenščine. Besedila so izbrana in strojno obdelana z namenom, da bi korpus kot vzorec sodobne standardne slovenščine lahko služil za jezikoslovne in druge humanistične raziskave, izdelavo sodobnih slovarjev, slovnic, učnih gradiv in razvoj jezikovnih tehnologij za slovenščino. S prispevanjem besedil v korpus Gigafida pomembno prispevate k razvoju sodobnih jezikovnih tehnologij za slovenski jezik.</p> | DESC_GIGAFIDA=<h2 id="subtitle">Gigafida</h2><p><a href="https://viri.cjvt.si/gigafida/">Gigafida</a> je referenčni korpus pisne slovenščine. Besedila so izbrana in strojno obdelana z namenom, da bi korpus kot vzorec sodobne standardne slovenščine lahko služil za jezikoslovne in druge humanistične raziskave, izdelavo sodobnih slovarjev, slovnic, učnih gradiv in razvoj jezikovnih tehnologij za slovenščino. S prispevanjem besedil v korpus Gigafida pomembno prispevate k razvoju sodobnih jezikovnih tehnologij za slovenski jezik.</p> | ||||||
| DESC_PREDAVANJA=<h2 id="subtitle">Predavanja</h2> |  | ||||||
| MAIL_SUBJECT=RSDO: pogodba za oddana besedila ({upload_id}) | MAIL_SUBJECT=RSDO: pogodba za oddana besedila ({upload_id}) | ||||||
| MAIL_BODY=Hvala, ker ste prispevali besedila in na ta način pomagali pri razvoju slovenskega jezika v digitalnem okolju. V prilogi vam pošiljamo pogodbo s seznamom naloženih datotek. | MAIL_BODY=Hvala, ker ste prispevali besedila in na ta način pomagali pri razvoju slovenskega jezika v digitalnem okolju. V prilogi vam pošiljamo pogodbo s seznamom naloženih datotek. | ||||||
|     |     | ||||||
|   |   | ||||||
|  Lep pozdrav, |  Lep pozdrav, | ||||||
|  ekipa RSDO |  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 hashlib | ||||||
| import time | import time | ||||||
| import ssl | import ssl | ||||||
| @ -20,6 +21,8 @@ from email.mime.application import MIMEApplication | |||||||
| import pdfkit | import pdfkit | ||||||
| from jinja2 import Environment, FileSystemLoader | from jinja2 import Environment, FileSystemLoader | ||||||
| 
 | 
 | ||||||
|  | import jwt | ||||||
|  | 
 | ||||||
| from werkzeug.security import generate_password_hash | from werkzeug.security import generate_password_hash | ||||||
| 
 | 
 | ||||||
| from . model import db, UploadRegular, UploadSolar, RegisteredUser, UserInstitutionMapping, Institution, InstitutionContract, CorpusAccess | from . model import db, UploadRegular, UploadSolar, RegisteredUser, UserInstitutionMapping, Institution, InstitutionContract, CorpusAccess | ||||||
| @ -238,8 +241,11 @@ class UploadHandler: | |||||||
|         return None |         return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_user_institutions(user_id): | def get_user_institution(user_id): | ||||||
|     return UserInstitutionMapping.query.filter_by(user=user_id).all() |     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): | def has_user_corpus_access(user_id, corpus_name): | ||||||
| @ -252,13 +258,11 @@ def has_user_corpus_access(user_id, corpus_name): | |||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
|     # Check if user belongs to an institution, that has access to this corpus. |     # 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 |     has_access = False | ||||||
|     for institution in institutions: |  | ||||||
|     row = CorpusAccess.query.filter_by(institution=institution.id, corpus=corpus_name).first() |     row = CorpusAccess.query.filter_by(institution=institution.id, corpus=corpus_name).first() | ||||||
|     if row: |     if row: | ||||||
|         has_access = True |         has_access = True | ||||||
|             break |  | ||||||
|     return has_access |     return has_access | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -322,15 +326,86 @@ def add_user_to_institution(user_id, institution_id, role): | |||||||
|     return model_obj.id |     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(): | 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): | 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: |     if not user_inst_mapping: | ||||||
|         return False |         return False | ||||||
|     if user_inst_mapping.role != 'moderator': |     if user_inst_mapping.role != 'moderator': | ||||||
|         return False |         return False | ||||||
|     return True |     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 logging | ||||||
| import re | import re | ||||||
| import traceback |  | ||||||
| import hashlib | import hashlib | ||||||
| from datetime import datetime | 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.base import UploadHandler, get_user_institution, has_user_corpus_access | ||||||
| from portal.model import db, UploadSolar, ContractsSolar, RegisteredUser, Institution, InstitutionContract, UserInstitutionMapping, CorpusAccess | from portal.model import UploadSolar, ContractsSolar, RegisteredUser, Institution, InstitutionContract, UserInstitutionMapping, CorpusAccess | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'} | 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 = list(file_hashes.values()) | ||||||
|         sorted_f_hashes.sort() |         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_institution(user_id).id | ||||||
|         institution_id = get_user_institutions(user_id)[0].id |  | ||||||
| 
 | 
 | ||||||
|         model_obj = UploadSolar( |         model_obj = UploadSolar( | ||||||
|                     upload_user = user_id, |                     upload_user = user_id, | ||||||
| @ -147,7 +146,7 @@ class UploadHandlerSolar(UploadHandler): | |||||||
|         if program not in VALID_PROGRAMS: |         if program not in VALID_PROGRAMS: | ||||||
|             return 'Invalid program "{}"'.format(program) |             return 'Invalid program "{}"'.format(program) | ||||||
|         if predmet not in VALID_SUBJECTS: |         if predmet not in VALID_SUBJECTS: | ||||||
|             return 'Invalid subject "{}"'.format(premdet) |             return 'Invalid subject "{}"'.format(predmet) | ||||||
|         if letnik < 1 or letnik > 9: |         if letnik < 1 or letnik > 9: | ||||||
|             return 'Invalid grade: {}'.format(letnik) |             return 'Invalid grade: {}'.format(letnik) | ||||||
|         if vrsta not in VALID_TEXT_TYPES: |         if vrsta not in VALID_TEXT_TYPES: | ||||||
| @ -176,14 +175,30 @@ def get_all_institutions(): | |||||||
|     return res |     return res | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_institution_student_contracts(institution_id): | 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').all() | ||||||
|  |     return ContractsSolar.query.filter_by(institution=institution_id, contract_type='ucenci-starsi', upload_user=user_id).all() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_institution_contract(institution_id): | def get_institution_contract(institution_id): | ||||||
|     return InstitutionContract.query.filter_by(institution=institution_id, corpus='solar').order_by(desc(InstitutionContract.timestamp)).first() |     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(): | def get_all_active_users(): | ||||||
|     # TODO: do filtering purely within an SQL query |     # TODO: do filtering purely within an SQL query | ||||||
|     res = [] |     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; |   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 { | #button-submit { | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: row; |   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> | <body> | ||||||
|     <a href="/prevodi">Korpus paralelnih besdil ANG-SLO</a><br> |     <a href="/prevodi">Korpus paralelnih besdil ANG-SLO</a><br> | ||||||
|     <a href="/gigafida">Korpus Gigafida</a><br> |     <a href="/gigafida">Korpus Gigafida</a><br> | ||||||
|     <a href="/predavanja">Korpus Predavanja</a><br> |     <a href="/solar">Korpus Šolar</a><br> | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
|     <style> |     <style> | ||||||
|           .tableFixHead { |           .tableFixHead { | ||||||
|             overflow-y: auto; |             overflow-y: auto; | ||||||
|             height: 106px; |             height: 306px; | ||||||
|           } |           } | ||||||
|           .tableFixHead thead th { |           .tableFixHead thead th { | ||||||
|             position: sticky; |             position: sticky; | ||||||
| @ -27,6 +27,13 @@ | |||||||
|     </style> |     </style> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|  |     {% with messages = get_flashed_messages() %} | ||||||
|  |     {% if messages %} | ||||||
|  |         <div style="background: blue;"> | ||||||
|  |             {{ messages[0] }} | ||||||
|  |         </div> | ||||||
|  |     {% endif %} | ||||||
|  |     {% endwith %} | ||||||
|     <h2>Uporabniki</h2> |     <h2>Uporabniki</h2> | ||||||
|     <h3>Dodaj uporabnika</h3> |     <h3>Dodaj uporabnika</h3> | ||||||
|     <form action="/solar/adduser" method="post"> |     <form action="/solar/adduser" method="post"> | ||||||
| @ -35,7 +42,7 @@ | |||||||
|         <label for="email">Email:</label><br> |         <label for="email">Email:</label><br> | ||||||
|         <input type="text" id="email" name="email"><br> |         <input type="text" id="email" name="email"><br> | ||||||
|         <label for="password">Geslo:</label><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"> |         <input type="submit" value="Dodaj"> | ||||||
|     </form>  |     </form>  | ||||||
|     <!--<h3>Odstrani uporabnika</h3> |     <!--<h3>Odstrani uporabnika</h3> | ||||||
| @ -52,15 +59,16 @@ | |||||||
|                 <th>ID</th> |                 <th>ID</th> | ||||||
|                 <th>Ime in priimek</th> |                 <th>Ime in priimek</th> | ||||||
|                 <th>Email</th> |                 <th>Email</th> | ||||||
|  |                 <th>ID institucije</th> | ||||||
|               </tr> |               </tr> | ||||||
|           </thead> |           </thead> | ||||||
|           <tbody> |           <tbody> | ||||||
|           {% for item in users %} |           {% for item in users %} | ||||||
|           <tr> |           <tr> | ||||||
|               <td>{{item.id}}</td> |               <td>{{item[0].id}}</td> | ||||||
|               <td>{{item.name}}</td> |               <td>{{item[0].name}}</td> | ||||||
|               <td>{{item.email}}</td> |               <td>{{item[0].email}}</td> | ||||||
|           </tr> |               <td>{{item[1].institution}}</td> | ||||||
|           {% endfor %} |           {% endfor %} | ||||||
|       </table> |       </table> | ||||||
|     </div> |     </div> | ||||||
| @ -107,4 +115,30 @@ | |||||||
|           {% endfor %} |           {% endfor %} | ||||||
|       </table> |       </table> | ||||||
|     </div> |     </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> | </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"> | <html lang="en"> | ||||||
| <head> | <head> | ||||||
|     <meta charset="UTF-8"> |     <meta charset="UTF-8"> | ||||||
|     <title>Portal {{title}}</title> |     <title>Portal ŠOLAR</title> | ||||||
|     <link rel="stylesheet" href="/static/style.css" type="text/css"> |     <link rel="stylesheet" href="/static/style.css" type="text/css"> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| @ -12,7 +12,7 @@ | |||||||
|                 <div id="logo-container"> |                 <div id="logo-container"> | ||||||
|                     <img src="/static/image/logo.svg" alt="logo"/> |                     <img src="/static/image/logo.svg" alt="logo"/> | ||||||
|                 </div> |                 </div> | ||||||
|                 <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> |                 <div> | ||||||
|                     {% with messages = get_flashed_messages() %} |                     {% with messages = get_flashed_messages() %} | ||||||
|                     {% if messages %} |                     {% if messages %} | ||||||
| @ -21,7 +21,7 @@ | |||||||
|                         </div> |                         </div> | ||||||
|                     {% endif %} |                     {% endif %} | ||||||
|                     {% endwith %} |                     {% endwith %} | ||||||
|                     <form method="POST" action="/{{corpus_name}}/login"> |                     <form method="POST" action="/solar/login"> | ||||||
|                         <div> |                         <div> | ||||||
|                             <div> |                             <div> | ||||||
|                                 <input  type="email" name="email" placeholder="Email" autofocus=""> |                                 <input  type="email" name="email" placeholder="Email" autofocus=""> | ||||||
| @ -39,6 +39,7 @@ | |||||||
|                         </div> |                         </div> | ||||||
|                         <button class="button-general" style="margin-top: 20px;">PRIJAVA</button> |                         <button class="button-general" style="margin-top: 20px;">PRIJAVA</button> | ||||||
|                     </form> |                     </form> | ||||||
|  |                     <a href="/solar/register" class="contract-item-button">Registracija</a> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
							
								
								
									
										97
									
								
								templates/solar-manage-institution.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								templates/solar-manage-institution.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <title>Upravljanje institucije - Šolar</title> | ||||||
|  |     <style> | ||||||
|  |           .tableFixHead { | ||||||
|  |             overflow-y: auto; | ||||||
|  |             height: 206px; | ||||||
|  |           } | ||||||
|  |           .tableFixHead thead th { | ||||||
|  |             position: sticky; | ||||||
|  |             top: 0; | ||||||
|  |           } | ||||||
|  |           table { | ||||||
|  |             border-collapse: collapse; | ||||||
|  |             width: 100%; | ||||||
|  |           } | ||||||
|  |           th, | ||||||
|  |           td { | ||||||
|  |             padding: 8px 16px; | ||||||
|  |             border: 1px solid #ccc; | ||||||
|  |           } | ||||||
|  |           th { | ||||||
|  |             background: #eee; | ||||||
|  |           } | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |     {% with messages = get_flashed_messages() %} | ||||||
|  |     {% if messages %} | ||||||
|  |         <div> | ||||||
|  |             {{ messages[0] }} | ||||||
|  |         </div> | ||||||
|  |     {% endif %} | ||||||
|  |     {% endwith %} | ||||||
|  |     <h3>Seznam vseh aktivnih uporabnikov</h3> | ||||||
|  |     <div class="tableFixHead"> | ||||||
|  |       <table> | ||||||
|  |           <thead> | ||||||
|  |               <tr> | ||||||
|  |                 <th>ID</th> | ||||||
|  |                 <th>Ime in priimek</th> | ||||||
|  |                 <th>Email</th> | ||||||
|  |               </tr> | ||||||
|  |           </thead> | ||||||
|  |           <tbody> | ||||||
|  |           {% for item in users %} | ||||||
|  |           <tr> | ||||||
|  |               <td>{{item.id}}</td> | ||||||
|  |               <td>{{item.name}}</td> | ||||||
|  |               <td>{{item.email}}</td> | ||||||
|  |           </tr> | ||||||
|  |           {% endfor %} | ||||||
|  |       </table> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <h3>Seznam uporabnikov v vaši instituciji</h3> | ||||||
|  |     <div class="tableFixHead"> | ||||||
|  |       <table> | ||||||
|  |           <thead> | ||||||
|  |               <tr> | ||||||
|  |                 <th>ID</th> | ||||||
|  |                 <th>Ime in priimek</th> | ||||||
|  |                 <th>Email</th> | ||||||
|  |               </tr> | ||||||
|  |           </thead> | ||||||
|  |           <tbody> | ||||||
|  |           {% for item in institution_users %} | ||||||
|  |           <tr> | ||||||
|  |               <td>{{item.id}}</td> | ||||||
|  |               <td>{{item.name}}</td> | ||||||
|  |               <td>{{item.email}}</td> | ||||||
|  |           </tr> | ||||||
|  |           {% endfor %} | ||||||
|  |       </table> | ||||||
|  |     </div> | ||||||
|  |     <br> | ||||||
|  |     <h3>Dodeli uporabnika instituciji</h3> | ||||||
|  |     <form action="/solar/addusertoinstitution" method="post"> | ||||||
|  |         <label for="user_id">ID uporabnika:</label> | ||||||
|  |         <input type="text" id="user_id" name="user_id"><br> | ||||||
|  |         <label for="role">Vloga v instituciji:</label> | ||||||
|  |         <select name="role" id="role"> | ||||||
|  |           <option value="moderator">Moderator</option> | ||||||
|  |           <option value="user">Uporabnik</option> | ||||||
|  |         </select> | ||||||
|  |         <input type="submit" value="Dodeli"> | ||||||
|  |     </form> | ||||||
|  |     <h3>Odstrani uporabnika iz institucije</h3> | ||||||
|  |     <form action="/solar/deluserfrominstitution" method="post"> | ||||||
|  |         <label for="user_id">ID uporabnika:</label> | ||||||
|  |         <input type="text" id="user_id" name="user_id"><br> | ||||||
|  |         <input type="submit" value="Odstrani"> | ||||||
|  |     </form> | ||||||
|  |     <div> </div> | ||||||
|  | </body> | ||||||
| @ -19,6 +19,12 @@ | |||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|     <a href="/solar/logout">Odjavi se</a> |     <a href="/solar/logout">Odjavi se</a> | ||||||
|  |     {% if is_institution_moderator %} | ||||||
|  |         <br><a href="/solar/manage-institution">Upravljaj z institucijo</a> | ||||||
|  |     {% endif %} | ||||||
|  |     {% if is_admin %} | ||||||
|  |         <br><a href="/solar/admin">Administracijski meni</a> | ||||||
|  |     {% endif %} | ||||||
|     <div class="bg"></div> |     <div class="bg"></div> | ||||||
|     <div id="main-window"> |     <div id="main-window"> | ||||||
|         <div id="rect1"> |         <div id="rect1"> | ||||||
|  | |||||||
| @ -7,6 +7,12 @@ | |||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|     <a href="/solar/logout">Odjavi se</a> |     <a href="/solar/logout">Odjavi se</a> | ||||||
|  |     {% if is_institution_moderator %} | ||||||
|  |         <br><a href="/solar/manage-institution">Upravljaj z institucijo</a> | ||||||
|  |     {% endif %} | ||||||
|  |     {% if is_admin %} | ||||||
|  |         <br><a href="/solar/admin">Administracijski meni</a> | ||||||
|  |     {% endif %} | ||||||
|     <div class="bg"></div> |     <div class="bg"></div> | ||||||
|     <div id="main-window"> |     <div id="main-window"> | ||||||
|         <div id="rect1"> |         <div id="rect1"> | ||||||
| @ -21,13 +27,13 @@ | |||||||
|                     <button onclick="window.location.replace('/solar/pogodbe');" class="selection-tab-button selected">POGODBE</button> |                     <button onclick="window.location.replace('/solar/pogodbe');" class="selection-tab-button selected">POGODBE</button> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|             <div id="conract-container" style="padding: 20px;"> |             <div id="contract-container"> | ||||||
|                 {% if contract_school %} |                 {% if contract_school %} | ||||||
|                 <div class="contract-item" style="background-color: #ccffcc;"> |                 <div class="contract-item" style="background-color: #ccffcc;"> | ||||||
|                     <div class="contract-item-icon"></div> |                     <div class="contract-item-icon"></div> | ||||||
|                     <div class="contract-item-title">Pogodba s šolo</div> |                     <div class="contract-item-title">Pogodba s šolo</div> | ||||||
|                     <div class="contract-item-date">DODANO {{contract_school.date}}</div> |                     <div class="contract-item-date">DODANO: {{contract_school.timestamp}}</div> | ||||||
|                     <a href="/solar/pogodbe/{{ contract_school.file_contract }}.pdf" class="contract-item-button">PRENESI</a> |                     <a href="/solar/pogodbe/{{ contract_school.file_contract }}.pdf" class="contract-item-button">Prenesi</a> | ||||||
|                 </div> |                 </div> | ||||||
|                 </br> |                 </br> | ||||||
|                 {% endif %} |                 {% endif %} | ||||||
| @ -35,8 +41,8 @@ | |||||||
|                     <div class="contract-item"> |                     <div class="contract-item"> | ||||||
|                         <div class="contract-item-icon"></div> |                         <div class="contract-item-icon"></div> | ||||||
|                         <div class="contract-item-title">Pogodba o prenosu lastništva</div> |                         <div class="contract-item-title">Pogodba o prenosu lastništva</div> | ||||||
|                         <div class="contract-item-date">DODANO {{item.date}}</div> |                         <div class="contract-item-date">DODANO: {{item.timestamp}}</div> | ||||||
|                         <a href="/solar/pogodbe/{{ item.file_contract }}.pdf" class="contract-item-button">PRENESI</a> |                         <a href="/solar/pogodbe/{{ item.file_contract }}.pdf" class="contract-item-button">Prenesi</a> | ||||||
|                     </div> |                     </div> | ||||||
|                     </br> |                     </br> | ||||||
|                 {% endfor %} |                 {% endfor %} | ||||||
| @ -69,6 +75,19 @@ | |||||||
|             {% endif %} |             {% endif %} | ||||||
|         </div> |         </div> | ||||||
|         <div id="rect2" class="mock-side"> |         <div id="rect2" class="mock-side"> | ||||||
|  |             <div id="collaborators-container"> | ||||||
|  |                 <div class="container-title">Sodelujoči</div> | ||||||
|  |                 <div style="overflow-y: auto;"> | ||||||
|  |                     {% for item in collaborators %} | ||||||
|  |                         <div class="collaborators-item"> | ||||||
|  |                             <div class="collaborators-item-name">{{item.name}}</div> | ||||||
|  |                         </div> | ||||||
|  |                     {% endfor %} | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |             <div id="awards-container"> | ||||||
|  |                 <div class="container-title">Nagrade</div> | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| </body> | </body> | ||||||
|  | |||||||
							
								
								
									
										50
									
								
								templates/solar-register.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								templates/solar-register.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | |||||||
|  | <!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;">Registracija - ŠOLAR</h3> | ||||||
|  |                 <div> | ||||||
|  |                     {% with messages = get_flashed_messages() %} | ||||||
|  |                     {% if messages %} | ||||||
|  |                         <div> | ||||||
|  |                             {{ messages[0] }} | ||||||
|  |                         </div> | ||||||
|  |                     {% endif %} | ||||||
|  |                     {% endwith %} | ||||||
|  |                     <form method="POST" action="/solar/register"> | ||||||
|  |                         <div> | ||||||
|  |                             <div> | ||||||
|  |                                 <input  type="name" name="name" placeholder="Ime in priimek" autofocus=""> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  | 
 | ||||||
|  |                         <div> | ||||||
|  |                             <div> | ||||||
|  |                                 <input  type="email" name="email" placeholder="Email" autofocus=""> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  | 
 | ||||||
|  |                         <div> | ||||||
|  |                             <div> | ||||||
|  |                                 <input  type="password" name="password" placeholder="Geslo"> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <button class="button-general" style="margin-top: 20px;">REGISTRACIJA</button> | ||||||
|  |                     </form> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div id="rect2" class="mock-side"> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </body> | ||||||
							
								
								
									
										49
									
								
								templates/solar-resetpass.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								templates/solar-resetpass.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | <!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;">Prijava - ŠOLAR</h3> | ||||||
|  |                 <div> | ||||||
|  |                     {% with messages = get_flashed_messages() %} | ||||||
|  |                     {% if messages %} | ||||||
|  |                         <div> | ||||||
|  |                             {{ messages[0] }} | ||||||
|  |                         </div> | ||||||
|  |                     {% endif %} | ||||||
|  |                     {% endwith %} | ||||||
|  |                     <form method="POST" action="/solar/login"> | ||||||
|  |                         <div> | ||||||
|  |                             <div> | ||||||
|  |                                 <input  type="email" name="email" placeholder="Email" autofocus=""> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  | 
 | ||||||
|  |                         <div> | ||||||
|  |                             <div> | ||||||
|  |                                 <input  type="password" name="password" placeholder="Geslo"> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <div style="display:flex; flex-direction: row; justify-content: left; align-items: center"> | ||||||
|  |                             <label>Zapomni prijavo</label> | ||||||
|  |                             <input style="width: 10%;" type="checkbox"> | ||||||
|  |                         </div> | ||||||
|  |                         <button class="button-general" style="margin-top: 20px;">PRIJAVA</button> | ||||||
|  |                     </form> | ||||||
|  |                     <a href="/solar/register" class="contract-item-button">Registracija</a> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div id="rect2" class="mock-side"> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </body> | ||||||
| @ -4,9 +4,16 @@ | |||||||
|     <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="/static/style.css" type="text/css"> | ||||||
|  |     <script src="/static/chart.js"></script> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|     <a href="/solar/logout">Odjavi se</a> |     <a href="/solar/logout">Odjavi se</a> | ||||||
|  |     {% if is_institution_moderator %} | ||||||
|  |         <br><a href="/solar/manage-institution">Upravljaj z institucijo</a> | ||||||
|  |     {% endif %} | ||||||
|  |     {% if is_admin %} | ||||||
|  |         <br><a href="/solar/admin">Administracijski meni</a> | ||||||
|  |     {% endif %} | ||||||
|     <div class="bg"></div> |     <div class="bg"></div> | ||||||
|     <div id="main-window"> |     <div id="main-window"> | ||||||
|         <div id="rect1"> |         <div id="rect1"> | ||||||
| @ -72,6 +79,40 @@ | |||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <div id="rect2" class="mock-side"> |         <div id="rect2" class="mock-side"> | ||||||
|  | <canvas id="myChart" width="400" height="400"></canvas> | ||||||
|  | <script> | ||||||
|  |     function drawChart(data) { | ||||||
|  |         var ctx = document.getElementById('myChart').getContext('2d'); | ||||||
|  |         var myChart = new Chart(ctx, { | ||||||
|  |             type: 'bar', | ||||||
|  |             data: { | ||||||
|  |                 labels: Object.keys(data), | ||||||
|  |                 datasets: [{ | ||||||
|  |                     label: 'št. naloženih datotek', | ||||||
|  |                     data: Object.values(data), | ||||||
|  |                     backgroundColor: 'rgba(54, 162, 235, 1.0)', | ||||||
|  |                     borderWidth: 1 | ||||||
|  |                 }] | ||||||
|  |             }, | ||||||
|  |             options: { | ||||||
|  |                 plugins: { | ||||||
|  |                     title: { | ||||||
|  |                         display: true, | ||||||
|  |                         text: '' | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 scales: { | ||||||
|  |                     y: { | ||||||
|  |                         beginAtZero: true | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 indexAxis: 'y' | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     fetch('/solar/topuploads').then(r => r.json()).then(j => drawChart(j)); | ||||||
|  | 
 | ||||||
|  | </script> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| </body> | </body> | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user