update predavanja, solar progress
This commit is contained in:
parent
e840e0b504
commit
3e59662396
106
app.py
106
app.py
|
@ -1,10 +1,11 @@
|
|||
import logging
|
||||
import os
|
||||
import re
|
||||
import configparser
|
||||
from pathlib import Path
|
||||
from werkzeug.security import check_password_hash
|
||||
|
||||
from flask import Flask, render_template, request, redirect, flash
|
||||
from flask import Flask, render_template, request, redirect, flash, safe_join, send_file
|
||||
from flask_dropzone import Dropzone
|
||||
from flask_migrate import Migrate, MigrateCommand
|
||||
from flask_script import Manager
|
||||
|
@ -103,6 +104,7 @@ app.config.update(
|
|||
SQLALCHEMY_DATABASE_URI = SQL_CONN_STR,
|
||||
SQLALCHEMY_ECHO = True
|
||||
)
|
||||
app.url_map.strict_slashes = False
|
||||
|
||||
# Run "python app.py db -?" to see more info about DB migrations.
|
||||
manager = Manager(app)
|
||||
|
@ -158,11 +160,6 @@ login_manager = LoginManager(app)
|
|||
login_manager.init_app(app)
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return User.get(user_id)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
@ -193,11 +190,9 @@ def load_user(user_id):
|
|||
return RegisteredUser.query.get(int(user_id))
|
||||
|
||||
|
||||
@app.route('/<corpus_name>/login')
|
||||
def login_get(corpus_name):
|
||||
if corpus_name == 'solar':
|
||||
return render_template('login.html', corpus_name=corpus_name, title='ŠOLAR')
|
||||
return 404
|
||||
@app.route('/solar/login')
|
||||
def login_get():
|
||||
return render_template('login.html', corpus_name='solar', title='ŠOLAR')
|
||||
|
||||
|
||||
@app.route('/<corpus_name>/login', methods=['POST'])
|
||||
|
@ -211,8 +206,6 @@ def login_post(corpus_name):
|
|||
|
||||
user = RegisteredUser.query.filter_by(email=email).first()
|
||||
|
||||
# TODO: Check if user is authorized to login to this corpus.
|
||||
|
||||
if not user or not check_password_hash(user.pass_hash, password):
|
||||
flash('Napačni podatki za prijavo. Poskusite ponovno.')
|
||||
return redirect('/{}/login'.format(corpus_name))
|
||||
|
@ -221,6 +214,11 @@ def login_post(corpus_name):
|
|||
flash('Vaš uporabniški račun še ni bil aktiviran.')
|
||||
return redirect('/{}/login'.format(corpus_name))
|
||||
|
||||
# Check if user is authorized to log into this corpus. Admins are an exception.
|
||||
if not portal.base.has_user_corpus_access(user.id, corpus_name):
|
||||
flash('Nimate dostop do tega korpusa.')
|
||||
return redirect('/{}/login'.format(corpus_name))
|
||||
|
||||
login_user(user, remember=remember)
|
||||
|
||||
if corpus_name == 'solar':
|
||||
|
@ -229,30 +227,64 @@ def login_post(corpus_name):
|
|||
|
||||
|
||||
# TODO: Move solar stuff to seperate file using Flask blueprints.
|
||||
@app.route('/solar/oddaja')
|
||||
# TODO: Better routing logic.
|
||||
@app.route('/solar/<path:text>')
|
||||
@login_required
|
||||
def solar_oddaja():
|
||||
return render_template('solar-oddaja.html')
|
||||
def solar(text):
|
||||
if not portal.base.has_user_corpus_access(current_user.id, 'solar'):
|
||||
return 404
|
||||
if text.startswith('oddaja/') or text == 'oddaja':
|
||||
return render_template('solar-oddaja.html')
|
||||
elif text.startswith('zgodovina/') or text == 'zgodovina':
|
||||
upload_items = portal.solar.get_upload_history(current_user.id)
|
||||
uploader_names = []
|
||||
institution_names = []
|
||||
for item in upload_items:
|
||||
uploader_names.append(portal.base.get_user_obj(current_user.id).name)
|
||||
institution = portal.base.get_institution_obj(item.institution)
|
||||
if not institution:
|
||||
institution_names.append(None)
|
||||
else:
|
||||
institution_names.append(institution.name)
|
||||
return render_template('solar-zgodovina.html', upload_history=upload_items, uploader_names=uploader_names,
|
||||
institution_names=institution_names)
|
||||
elif text.startswith('pogodbe/') or text == 'pogodbe':
|
||||
# Check for ownload contract request.
|
||||
match = re.match('^pogodbe/[a-z0-9_]+\.pdf$', text)
|
||||
if match:
|
||||
filename = match.group(1)
|
||||
safe_path = safe_join(str(upload_handler_solar.get_uploads_subdir('contracts')), filename)
|
||||
try:
|
||||
return send_file(safe_path, as_attachment=True)
|
||||
except FileNotFoundError:
|
||||
return 404
|
||||
|
||||
user_obj = portal.base.get_user_obj(current_user.get_id())
|
||||
institution_id = user_obj.institution
|
||||
|
||||
@app.route('/solar/zgodvina')
|
||||
contracts_students = []
|
||||
contract_school = None
|
||||
show_upload_form = True
|
||||
if institution_id:
|
||||
contracts_students = portal.solar.get_institution_student_contracts(institution_id)
|
||||
contract_school = portal.solar.get_institution_contract(institution_id)
|
||||
else:
|
||||
show_upload_form = False
|
||||
|
||||
return render_template('solar-pogodbe.html', contracts_students=contracts_students,
|
||||
contract_school=contract_school, show_upload_form=show_upload_form)
|
||||
elif text.startswith('admin/') or text == 'admin':
|
||||
if current_user.role == 'admin':
|
||||
return render_template('solar-admin.html')
|
||||
return 404
|
||||
|
||||
@app.route('/solar/pogodbe', methods=['POST'])
|
||||
@login_required
|
||||
def solar_zgodovina():
|
||||
return render_template('solar-zgodovina.html')
|
||||
|
||||
|
||||
@app.route('/solar/pogodbe')
|
||||
@login_required
|
||||
def solar_pogodbe():
|
||||
return render_template('solar-pogodbe.html')
|
||||
|
||||
|
||||
@app.route('/solar/admin')
|
||||
@login_required
|
||||
def solar_admin():
|
||||
# TODO: check if user is admin
|
||||
return render_template('solar-admin.html')
|
||||
|
||||
def solar_upload_contract():
|
||||
logging.info('TESTTTTTT')
|
||||
if not portal.base.has_user_corpus_access(current_user.id, 'solar'):
|
||||
return 404
|
||||
return upload_handler_solar.handle_contract_upload(request, current_user.get_id())
|
||||
|
||||
@app.route('/<corpus_name>/upload', methods=['POST'])
|
||||
def handle_upload(corpus_name):
|
||||
|
@ -260,9 +292,11 @@ def handle_upload(corpus_name):
|
|||
return 404
|
||||
|
||||
if corpus_name == 'solar':
|
||||
if current_user.is_authenticated:
|
||||
return upload_handler_solar.handle_upload(request, current_user.get_id())
|
||||
return 404
|
||||
if not current_user.is_authenticated:
|
||||
return 404
|
||||
if not portal.base.has_user_corpus_access(current_user.id, corpus_name):
|
||||
return 404
|
||||
return upload_handler_solar.handle_upload(request, current_user.get_id())
|
||||
elif corpus_name == 'predavanja':
|
||||
return upload_handler_predavanja.handle_upload(request)
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
"""permissions and solar stuff
|
||||
|
||||
Revision ID: 7d6db184b8fc
|
||||
Revises: c6edf87b8bff
|
||||
Create Date: 2021-05-18 13:49:37.642465
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '7d6db184b8fc'
|
||||
down_revision = 'c6edf87b8bff'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.rename_table('stamps', 'stamps_solar')
|
||||
op.drop_column('upload_solar', 'corpus_name')
|
||||
op.create_table('corpus_access',
|
||||
sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('corpus_access_id_seq'::regclass)"), autoincrement=True, nullable=False),
|
||||
sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False),
|
||||
sa.Column('corpus', sa.TEXT(), autoincrement=False, nullable=False),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['registered_user.id'], name='user_id_fkey'),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('contracts_solar',
|
||||
sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('contracts_solar_id_seq'::regclass)"), autoincrement=True, nullable=False),
|
||||
sa.Column('institution', sa.INTEGER(), autoincrement=False, nullable=False),
|
||||
sa.Column('upload_user', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.Column('timestamp', sa.DateTime(), nullable=False),
|
||||
sa.Column('file_contract', sa.TEXT(), autoincrement=False, nullable=False),
|
||||
sa.Column('contract_type', sa.TEXT(), autoincrement=False, nullable=False),
|
||||
sa.ForeignKeyConstraint(['institution'], ['institution.id'], name='institution_fkey'),
|
||||
sa.ForeignKeyConstraint(['upload_user'], ['registered_user.id'], name='upload_user_fkey'),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.add_column('registered_user', sa.Column('institution_moderator', sa.BOOLEAN(), autoincrement=False, default=False))
|
||||
op.add_column('upload_predavanja', sa.Column('agree_publish_future', sa.TEXT(), nullable=False))
|
||||
op.add_column('upload_predavanja', sa.Column('agree_machine_translation', sa.BOOLEAN(), nullable=False))
|
||||
op.add_column('upload_predavanja', sa.Column('agree_news_cjvt', sa.BOOLEAN(), nullable=False))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('upload_solar', sa.Column('corpus_name', sa.TEXT(), autoincrement=False, nullable=False))
|
||||
op.rename_table('stamps_solar', 'stamps')
|
||||
op.drop_table('corpus_access')
|
||||
op.drop_table('contracts_solar')
|
||||
op.drop_column('registered_user', 'institution_moderator')
|
||||
# ### end Alembic commands ###
|
|
@ -18,11 +18,12 @@ depends_on = None
|
|||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('upload_regular', 'corpus_name')
|
||||
op.drop_table('upload_solar')
|
||||
op.drop_table('upload_predavanja')
|
||||
op.drop_table('institution')
|
||||
op.drop_table('stamps')
|
||||
op.drop_table('registered_user')
|
||||
op.drop_column('upload_regular', 'corpus_name')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ from email.mime.application import MIMEApplication
|
|||
import pdfkit
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
from . model import db, UploadRegular, UploadSolar, RegisteredUser
|
||||
from . model import db, UploadRegular, UploadSolar, RegisteredUser, CorpusAccess, Institution
|
||||
|
||||
|
||||
ENABLED_FILETYPES = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'xml', 'mxliff', 'tmx']
|
||||
|
@ -233,3 +233,15 @@ class UploadHandler:
|
|||
match = db.session.query(RegisteredUser).filter(RegisteredUser.id == user_id).one()
|
||||
return match.institution
|
||||
|
||||
|
||||
def has_user_corpus_access(user_id, corpus_name):
|
||||
user = RegisteredUser.query.filter_by(id=user_id).first()
|
||||
if user.role == 'admin':
|
||||
return True
|
||||
return CorpusAccess.query.filter_by(user_id=user.id, corpus=corpus_name).first() is not None
|
||||
|
||||
def get_user_obj(user_id):
|
||||
return RegisteredUser.query.filter_by(id=user_id).first()
|
||||
|
||||
def get_institution_obj(institution_id):
|
||||
return Institution.query.filter_by(id=institution_id).first()
|
||||
|
|
121
portal/model.py
121
portal/model.py
|
@ -16,70 +16,99 @@ db = SQLAlchemy()
|
|||
class UploadRegular(db.Model):
|
||||
__tablename__ = 'upload_regular'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
upload_hash = db.Column(db.String)
|
||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
name = db.Column(db.String)
|
||||
org = db.Column(db.String)
|
||||
address = db.Column(db.String)
|
||||
zipcode = db.Column(db.String)
|
||||
email = db.Column(db.String)
|
||||
file_contract = db.Column(db.String)
|
||||
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String))
|
||||
corpus_name = db.Column(db.String)
|
||||
upload_hash = db.Column(db.String, nullable=False)
|
||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||
name = db.Column(db.String, nullable=False)
|
||||
org = db.Column(db.String, nullable=True)
|
||||
address = db.Column(db.String, nullable=True)
|
||||
zipcode = db.Column(db.String, nullable=True)
|
||||
email = db.Column(db.String, nullable=False)
|
||||
file_contract = db.Column(db.String, nullable=True)
|
||||
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String), nullable=True)
|
||||
corpus_name = db.Column(db.String, nullable=False)
|
||||
|
||||
|
||||
class UploadPredavanja(db.Model):
|
||||
__tablename__ = 'upload_predavanja'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
upload_hash = db.Column(db.String)
|
||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
name = db.Column(db.String)
|
||||
address = db.Column(db.String)
|
||||
subject = db.Column(db.String)
|
||||
faculty = db.Column(db.String)
|
||||
email = db.Column(db.String)
|
||||
phone = db.Column(db.String)
|
||||
keywords = db.Column(db.String)
|
||||
agree_publish = db.Column(db.Boolean)
|
||||
file_contract = db.Column(db.String)
|
||||
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String))
|
||||
upload_hash = db.Column(db.String, nullable=False)
|
||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||
name = db.Column(db.String, nullable=False)
|
||||
address = db.Column(db.String, nullable=False)
|
||||
subject = db.Column(db.String, nullable=False)
|
||||
faculty = db.Column(db.String, nullable=False)
|
||||
email = db.Column(db.String, nullable=False)
|
||||
phone = db.Column(db.String, nullable=True)
|
||||
keywords = db.Column(db.String, nullable=False)
|
||||
agree_publish = db.Column(db.Boolean, nullable=False)
|
||||
agree_publish_future = db.Column(db.String, nullable=False)
|
||||
agree_machine_translation = db.Column(db.Boolean, default=False, nullable=False)
|
||||
agree_news_cjvt = db.Column(db.Boolean, default=False, nullable=False)
|
||||
file_contract = db.Column(db.String, nullable=True)
|
||||
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String), nullable=True)
|
||||
|
||||
|
||||
class UploadSolar(db.Model):
|
||||
__tablename__ = 'upload_solar'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
upload_user = db.Column(db.Integer, sqlalchemy.ForeignKey('registered_user.id'))
|
||||
institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'))
|
||||
upload_hash = db.Column(db.String)
|
||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
program = db.Column(db.String)
|
||||
subject = db.Column(db.String)
|
||||
subject_custom = db.Column(db.String)
|
||||
grade = db.Column(db.Integer)
|
||||
text_type = db.Column(db.String)
|
||||
text_type_custom = db.Column(db.String)
|
||||
school_year = db.Column(db.String)
|
||||
grammar_corrections = db.Column(db.String)
|
||||
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String))
|
||||
upload_user = db.Column(db.Integer, sqlalchemy.ForeignKey('registered_user.id'), nullable=True)
|
||||
institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=True)
|
||||
upload_hash = db.Column(db.String, nullable=False)
|
||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||
program = db.Column(db.String, nullable=True)
|
||||
subject = db.Column(db.String, nullable=True)
|
||||
subject_custom = db.Column(db.String, nullable=True)
|
||||
grade = db.Column(db.Integer, nullable=True)
|
||||
text_type = db.Column(db.String, nullable=True)
|
||||
text_type_custom = db.Column(db.String, nullable=True)
|
||||
school_year = db.Column(db.String, nullable=True)
|
||||
grammar_corrections = db.Column(db.String, nullable=True)
|
||||
upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String), nullable=True)
|
||||
|
||||
|
||||
class StampsSolar(db.Model):
|
||||
__tablename__ = 'stamps_solar'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=True)
|
||||
name = db.Column(db.String, nullable=False)
|
||||
file_logo = db.Column(db.String, nullable=True)
|
||||
|
||||
|
||||
class ContractsSolar(db.Model):
|
||||
__tablename__ = 'contracts_solar'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=False)
|
||||
upload_user = db.Column(db.Integer, sqlalchemy.ForeignKey('registered_user.id'), nullable=True)
|
||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||
file_contract = db.Column(db.String, nullable=False)
|
||||
contract_type = db.Column(db.String, nullable=False)
|
||||
|
||||
|
||||
class CorpusAccess(db.Model):
|
||||
__tablename__ = 'corpus_access'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(db.Integer, sqlalchemy.ForeignKey('registered_user.id'), nullable=False)
|
||||
corpus = db.Column(db.String, nullable=False)
|
||||
|
||||
|
||||
class RegisteredUser(UserMixin, db.Model):
|
||||
__tablename__ = 'registered_user'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String)
|
||||
email = db.Column(db.String)
|
||||
role = db.Column(db.String)
|
||||
pass_hash = db.Column(db.String)
|
||||
active = db.Column(db.Boolean)
|
||||
last_login = db.Column(db.DateTime)
|
||||
registered = db.Column(db.DateTime)
|
||||
institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'))
|
||||
name = db.Column(db.String, nullable=False)
|
||||
email = db.Column(db.String, nullable=False)
|
||||
role = db.Column(db.String, nullable=False)
|
||||
pass_hash = db.Column(db.String, nullable=False)
|
||||
active = db.Column(db.Boolean, nullable=True)
|
||||
last_login = db.Column(db.DateTime, nullable=True)
|
||||
registered = db.Column(db.DateTime, nullable=True)
|
||||
institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=True)
|
||||
institution_moderator = db.Column(db.Boolean, default=False)
|
||||
|
||||
|
||||
class Institution(db.Model):
|
||||
__tablename__ = 'institution'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String)
|
||||
region = db.Column(db.String)
|
||||
file_contract = db.Column(db.String)
|
||||
name = db.Column(db.String, nullable=False)
|
||||
region = db.Column(db.String, nullable=False)
|
||||
file_contract = db.Column(db.String, nullable=True)
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ class UploadHandlerPredavanja(UploadHandler):
|
|||
phone=form_data.get('phone'),
|
||||
keywords=form_data['kljucne-besede'],
|
||||
agree_publish=True if 'kljucne-besde' in form_data else False,
|
||||
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,
|
||||
)
|
||||
|
|
110
portal/solar.py
110
portal/solar.py
|
@ -1,10 +1,12 @@
|
|||
import logging
|
||||
import re
|
||||
import traceback
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from sqlalchemy import desc
|
||||
|
||||
import portal.base
|
||||
from portal.base import UploadHandler
|
||||
from portal.model import UploadSolar
|
||||
from portal.model import db, UploadSolar, ContractsSolar, RegisteredUser, Institution
|
||||
|
||||
|
||||
VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'}
|
||||
|
@ -27,29 +29,25 @@ class UploadHandlerSolar(UploadHandler):
|
|||
|
||||
institution_id = UploadHandler.get_user_institution(user_id)
|
||||
|
||||
try:
|
||||
model_obj = UploadSolar(
|
||||
upload_user = user_id,
|
||||
institution = institution_id,
|
||||
upload_hash=upload_metadata['upload_id'],
|
||||
timestamp=timestamp,
|
||||
program=form_data['program'],
|
||||
subject=form_data['predmet'],
|
||||
subject_custom=form_data['predmet-custom'],
|
||||
grade=form_data['letnik'],
|
||||
text_type=form_data['vrsta'],
|
||||
text_type_custom=form_data['vrsta-custom'],
|
||||
school_year=form_data['solsko-leto'],
|
||||
grammar_corrections=form_data['jezikovni-popravki'],
|
||||
upload_file_hashes=sorted_f_hashes
|
||||
)
|
||||
db.session.add(model_obj)
|
||||
db.session.commit()
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
model_obj = UploadSolar(
|
||||
upload_user = user_id,
|
||||
institution = institution_id,
|
||||
upload_hash=upload_metadata['upload_id'],
|
||||
timestamp=timestamp,
|
||||
program=form_data['program'],
|
||||
subject=form_data['predmet'],
|
||||
subject_custom=form_data['predmet-custom'],
|
||||
grade=form_data['letnik'],
|
||||
text_type=form_data['vrsta'],
|
||||
text_type_custom=form_data['vrsta-custom'],
|
||||
school_year=form_data['solsko-leto'],
|
||||
grammar_corrections=form_data['jezikovni-popravki'],
|
||||
upload_file_hashes=sorted_f_hashes
|
||||
)
|
||||
self.store_model(model_obj)
|
||||
|
||||
def handle_upload(self, request, user_id):
|
||||
err = portal.base.check_upload_request(request, self)
|
||||
err = self.check_upload_request(request)
|
||||
if err:
|
||||
return err, 400
|
||||
|
||||
|
@ -74,6 +72,57 @@ class UploadHandlerSolar(UploadHandler):
|
|||
|
||||
return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(request.files))
|
||||
|
||||
def handle_contract_upload(self, request, user_id):
|
||||
contracts_type = request.form['tip-pogodbe']
|
||||
|
||||
if contracts_type not in ['sola', 'ucenci-starsi']:
|
||||
return 'Neveljaven tip pogodbe.'
|
||||
|
||||
f_obj = None
|
||||
for key, f in request.files.items():
|
||||
if key.startswith('file'):
|
||||
mimetype = f.content_type
|
||||
if mimetype != 'application/pdf':
|
||||
return 'Datoteka "{}" ni formata PDF.'.format(f.filename)
|
||||
else:
|
||||
f_obj = f
|
||||
break
|
||||
|
||||
if not f_obj:
|
||||
return 'Niste naložili nobene datoteke.'
|
||||
|
||||
base = self.get_uploads_subdir('contracts')
|
||||
f_hash = hashlib.md5(f_obj.read())
|
||||
|
||||
# First byte used for indexing, similarly like git does for example.
|
||||
sub_dir = base / f_hash[:2]
|
||||
if not sub_dir.exists():
|
||||
sub_dir.mkdir()
|
||||
|
||||
path = sub_dir / f_hash[2:] + '.pdf'
|
||||
f_obj.save(path)
|
||||
|
||||
user_obj = RegisteredUser.query.filter_by(id=user_id).one()
|
||||
institution_id = user_obj.institution
|
||||
is_institution_moderator = user_obj.institution_moderator
|
||||
|
||||
if institution_id is None:
|
||||
return 'Vaš uporabnik ni dodeljen nobeni inštituciji.'
|
||||
|
||||
if contracts_type == 'sola':
|
||||
if not is_institution_moderator:
|
||||
return 'Vaš uporabnik nima pravic za nalaganje pogodbe s šolo.'
|
||||
Institution.update().values(file_contract=f_hash).where(id=institution_id)
|
||||
|
||||
model_obj = ContractsSolar(
|
||||
institution=institution_id,
|
||||
upload_user=user_id,
|
||||
file_contract=f_hash,
|
||||
contracts_type=contracts_type,
|
||||
)
|
||||
self.store_model(model_obj)
|
||||
return 'Nalaganje pogodbe je bilo uspešno.'
|
||||
|
||||
@staticmethod
|
||||
def check_form(form):
|
||||
program = form['program']
|
||||
|
@ -99,3 +148,18 @@ class UploadHandlerSolar(UploadHandler):
|
|||
for key, val in form.items():
|
||||
if len(val) > MAXLEN_FORM:
|
||||
return 'Value in form field "{}" exceeds max len of {}'.format(key, MAXLEN_FORM)
|
||||
|
||||
|
||||
def get_upload_history(user_id, n=20):
|
||||
return UploadSolar.query.filter_by(upload_user=user_id).order_by(desc(UploadSolar.timestamp)).limit(n).all()
|
||||
|
||||
|
||||
def get_institution_student_contracts(institution_id):
|
||||
return ContractsSolar.query.filter_by(id=institution_id, contract_type='ucenci-starsi').all()
|
||||
|
||||
|
||||
def get_institution_contract(institution_id):
|
||||
return ContractsSolar.query.filter_by(id=institution_id, contract_type='sola').first()
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -456,3 +456,51 @@ select {
|
|||
top: 100% !important;
|
||||
left: 25% !important;
|
||||
}
|
||||
|
||||
.history-item-date {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 10px;
|
||||
line-height: 12px;
|
||||
/* identical to box height */
|
||||
text-transform: uppercase;
|
||||
color: #46535b;
|
||||
}
|
||||
|
||||
.history-item-uploader {
|
||||
height: 19px;
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
/* identical to box height */
|
||||
float: left;
|
||||
color: #46535B;
|
||||
}
|
||||
|
||||
.history-item-filecount {
|
||||
height: 19px;
|
||||
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
/* identical to box height */
|
||||
|
||||
text-align: right;
|
||||
|
||||
color: #006CB7;
|
||||
}
|
||||
|
||||
.history-item-desc {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
|
||||
color: #848C91;
|
||||
}
|
||||
|
|
|
@ -4,24 +4,24 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>Portal za oddajanje besedil</title>
|
||||
<!--{{ dropzone.load_css() }}-->
|
||||
<link rel="stylesheet" href="static/dropzone.css" type="text/css">
|
||||
<link rel="stylesheet" href="/static/dropzone.css" type="text/css">
|
||||
{{ dropzone.style('position: absolute;
|
||||
top: -0.5px;
|
||||
width: 388px;
|
||||
height: 732px;
|
||||
height: 1232px;
|
||||
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">
|
||||
<link rel="stylesheet" href="/static/style.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main-window">
|
||||
<div id="rect1">
|
||||
<div id="logo-container">
|
||||
<img src="static/image/logo.svg" alt="logo"/>
|
||||
<div id="rect1" style="height: 1231px;">
|
||||
<div id="logo-container" style="top: -5.4%;">
|
||||
<img src="/static/image/logo.svg" alt="logo"/>
|
||||
</div>
|
||||
|
||||
<form id="my-dropzone" class="dropzone">
|
||||
|
@ -55,9 +55,33 @@
|
|||
<input style="width: 10%;" type="checkbox" name="javna-objava" value="javna-objava" checked>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; flex-direction: row; justify-content: left; align-items: center; width: 310px;">
|
||||
<label>Ali bi se v prihodnosti strinjali z javno objavo posnetka? (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;" checked>
|
||||
<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%">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" checked>
|
||||
</div>
|
||||
<br>
|
||||
<div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
|
||||
<label style="width: 95%">Ž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" checked>
|
||||
</div>
|
||||
<br>
|
||||
<div class="form-text">Univerza v Ljubljani, Fakulteta za računalništvo in informatiko, Večna pot 113, 1000 Ljubljana, osebne podatke potrebuje zaradi izvedbe zgoraj navedenega projekta in komuniciranja v zvezi z njim (pravna podlaga je 6/1(b) člen GDPR). Podatke bomo hranili, dokler bo podano vaše soglasje za obveščanje. Če ste se strinjali, da vam pošiljamo obvestila, ste nam dali svojo osebno privolitev (6/1(a) člen GDPR). V tem primeru bomo vaše osebne podatke hranili do preklica privolitve. Privolitev lahko kadar koli prekličete s sporočilom na elektronski naslov info@cjvt.si. Preklic privolitve ne vpliva na zakonitost obdelave podatkov, ki se je izvajala do preklica. Obveščamo vas, da lahko kadar koli uveljavljate pravico do dostopa do svojih osebnih podatkov, popravek, izbris (v primeru osebne privolitve), pravico do omejitve obdelave (v primerih, določenih z GDPR) in pravico do prenosljivosti podatkov. Za vprašanja v zvezi z varstvom osebnih podatkov se lahko obrnete na pooblaščeno osebo za varstvo podatkov Univerze v Ljubljani na elektronski naslov dpo@uni-lj.si. Če boste menili, da vaših pravic ne uresničujemo ustrezno, se lahko pritožite Informacijskemu pooblaščencu RS (ip-rs.si).</div>
|
||||
|
||||
<div class="form-text">*Po kliku na gumb “Oddaj” se bo prikazala vsebina pogodobe o odstopu avtorskih pravic. Če se z vsebino strinjate, kliknite gumb “Pošlji”, da podatke posredujete v korpus, po e-pošti pa boste prejeli svoj izvod pogodbe.</div>
|
||||
|
||||
<button id="button-submit" type="submit">Oddaj</button>
|
||||
<button id="button-submit" type="submit" style="top: 1150px;">Oddaj</button>
|
||||
</div>
|
||||
|
||||
<div class="dropzone-previews"></div>
|
||||
|
@ -173,7 +197,7 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
|||
</div>
|
||||
|
||||
<!--{{ dropzone.load_js() }}-->
|
||||
<script src="static/dropzone.js"></script>
|
||||
<script src="/static/dropzone.js"></script>
|
||||
<script>
|
||||
/////////////////////////
|
||||
// Dropzone //
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>Portal za oddajanje besedil</title>
|
||||
<!--{{ dropzone.load_css() }}-->
|
||||
<link rel="stylesheet" href="static/dropzone.css" type="text/css">
|
||||
<link rel="stylesheet" href="/static/dropzone.css" type="text/css">
|
||||
{{ dropzone.style('position: absolute;
|
||||
top: -0.5px;
|
||||
width: 388px;
|
||||
|
@ -15,13 +15,13 @@
|
|||
backdrop-filter: blur(20px);
|
||||
border: 0px;
|
||||
border-radius: 0px 20px 20px 0px;') }}
|
||||
<link rel="stylesheet" href="static/style.css" type="text/css">
|
||||
<link rel="stylesheet" href="/static/style.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main-window">
|
||||
<div id="rect1">
|
||||
<div id="logo-container">
|
||||
<img src="static/image/logo.svg" alt="logo"/>
|
||||
<img src="/static/image/logo.svg" alt="logo"/>
|
||||
</div>
|
||||
|
||||
<form id="my-dropzone" class="dropzone">
|
||||
|
@ -165,7 +165,7 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
|||
</div>
|
||||
|
||||
<!--{{ dropzone.load_js() }}-->
|
||||
<script src="static/dropzone.js"></script>
|
||||
<script src="/static/dropzone.js"></script>
|
||||
<script>
|
||||
/////////////////////////
|
||||
// Dropzone //
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
<body>
|
||||
<a href="/prevodi">Korpus paralelnih besdil ANG-SLO</a><br>
|
||||
<a href="/gigafida">Korpus Gigafida</a>
|
||||
<a href="/predavanja">Korpus Predavanja</a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
<h1 id="title" style="font-size: 25px;">Korpus ŠOLAR</h1>
|
||||
|
||||
<div class="selection-tabs">
|
||||
<button class="selection-tab-button selected">ODDAJA</button>
|
||||
<button class="selection-tab-button">ZGODOVINA</button>
|
||||
<button class="selection-tab-button">POGODBE</button>
|
||||
<button id="button-oddaja" class="selection-tab-button selected">ODDAJA</button>
|
||||
<button id="button-zgodovina" class="selection-tab-button">ZGODOVINA</button>
|
||||
<button id="button-pogodbe" class="selection-tab-button">POGODBE</button>
|
||||
</div>
|
||||
|
||||
<label for="program">PROGRAM</label>
|
||||
|
@ -225,6 +225,8 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
|||
var btnSubmit = document.getElementById("button-submit");
|
||||
var btnSubmitFinal = document.getElementById("button-submit-final");
|
||||
var btnSubmitCancel = document.getElementById("button-submit-cancel");
|
||||
var btnZgodovina = document.getElementById("button-zgodovina");
|
||||
var btnPogodbe = document.getElementById("button-pogodbe");
|
||||
var elemTermsPopup = document.getElementById("popup-terms");
|
||||
var termsScrollbox = document.getElementById("popup-terms-text");
|
||||
var scrollboxTriggered = false;
|
||||
|
@ -302,12 +304,12 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
|||
btnSubmit.disabled = true;
|
||||
btnSubmitFinal.disabled = true;
|
||||
elemTermsPopup.style.display = "inline";
|
||||
scrollboxTriggered = false;
|
||||
scrollboxtriggered = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// First change the button to actually tell Dropzone to process the queue.
|
||||
// First change the button to actually tell dropzone to process the queue.
|
||||
btnSubmitFinal.addEventListener("click", function(e) {
|
||||
// Hand off data to dropzone
|
||||
dz.processQueue();
|
||||
|
@ -325,6 +327,18 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
|||
elemTermsPopup.style.display = "none";
|
||||
});
|
||||
|
||||
btnZgodovina.addEventListener("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
window.location.replace("/solar/zgodovina");
|
||||
});
|
||||
|
||||
btnPogodbe.addEventListener("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
window.location.replace("/solar/pogodbe");
|
||||
});
|
||||
|
||||
// Enable final submit button only if user scrolls to the end of the terms.
|
||||
function checkScrollboxTrigger(event) {
|
||||
var element = event.target;
|
||||
|
@ -362,11 +376,9 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
|||
// Gets triggered when there was an error sending the files.
|
||||
// Maybe show form again, and notify user of error
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
58
templates/solar-pogodbe.html
Normal file
58
templates/solar-pogodbe.html
Normal file
|
@ -0,0 +1,58 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Portal za oddajanje besedil</title>
|
||||
<link rel="stylesheet" href="/static/style.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg"></div>
|
||||
<div id="main-window">
|
||||
<div id="rect1">
|
||||
<div style="padding: 20px;">
|
||||
<div id="logo-container">
|
||||
<img src="/static/image/logo.svg" alt="logo"/>
|
||||
</div>
|
||||
<h1 id="title" style="font-size: 25px; position: relative;">Korpus ŠOLAR</h1>
|
||||
<div class="selection-tabs">
|
||||
<button onclick="window.location.replace('/solar/oddaja');" class="selection-tab-button">ODDAJA</button>
|
||||
<button onclick="window.location.replace('/solar/zgodovina');" class="selection-tab-button">ZGODOVINA</button>
|
||||
<button onclick="window.location.replace('/solar/pogodbe');" class="selection-tab-button selected">POGODBE</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="conract-container" style="padding: 20px;">
|
||||
{% if contract_school %}
|
||||
<div class="contract-item" style="background-color: #ccffcc;">
|
||||
<div class="contract-item-icon">...</div>
|
||||
<div class="contract-item-title">Pogodba o prenosu lastništva</div>
|
||||
<div class="contract-item-date">DODANO {{contract_school.date}}</div>
|
||||
<a href="/solar/pogodbe/{{ contract_school.file_hash }}.pdf" class="contract-item-button">PRENESI</div>
|
||||
</div>
|
||||
</br>
|
||||
{% endif %}
|
||||
{% for item in contracts_students %}
|
||||
<div class="contract-item">
|
||||
<div class="contract-item-icon">...</div>
|
||||
<div class="contract-item-title">Pogodba o prenosu lastništva</div>
|
||||
<div class="contract-item-date">DODANO {{item.date}}</div>
|
||||
<a href="/solar/pogodbe/{{ item.file_hash }}.pdf" class="contract-item-button">PRENESI</div>
|
||||
</div>
|
||||
</br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if show_upload_form %}
|
||||
<form action="/solar/pogodbe">
|
||||
<input type="radio" id="sola" name="tip-pogodbe" value="sola">
|
||||
<label for="sola">Pogodba s šolo</label><br>
|
||||
<input type="radio" id="ucenci-starsi" name="tip-pogodbe" value="ucenci-starsi">
|
||||
<label for="sola">Pogodba z učenci / starši</label><br>
|
||||
<input type="file" id="file-contract" name="filename">
|
||||
<input type="submit" text="Naloži pogodbo">
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="rect2" class="mock-side">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
77
templates/solar-zgodovina.html
Normal file
77
templates/solar-zgodovina.html
Normal file
|
@ -0,0 +1,77 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Portal za oddajanje besedil</title>
|
||||
<link rel="stylesheet" href="/static/style.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg"></div>
|
||||
<div id="main-window">
|
||||
<div id="rect1">
|
||||
<div style="padding: 20px;">
|
||||
<div id="logo-container">
|
||||
<img src="/static/image/logo.svg" alt="logo"/>
|
||||
</div>
|
||||
<h1 id="title" style="font-size: 25px; position: relative;">Korpus ŠOLAR</h1>
|
||||
<div class="selection-tabs">
|
||||
<button onclick="window.location.replace('/solar/oddaja');" class="selection-tab-button">ODDAJA</button>
|
||||
<button onclick="window.location.replace('/solar/zgodovina');" class="selection-tab-button selected">ZGODOVINA</button>
|
||||
<button onclick="window.location.replace('/solar/pogodbe');" class="selection-tab-button">POGODBE</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="history-container" style="padding: 20px;">
|
||||
{% for item in upload_history %}
|
||||
<div class="history-item">
|
||||
<div class="history-item-date">{{ item.timestamp }}</div>
|
||||
<div class="history-item-uploader">{{ uploader_names[loop.index - 1] }}</div>
|
||||
<div class="history-item-filecount">Št. datotek: {{ item.upload_file_hashes|length }}</div>
|
||||
<div class="history-item-desc">
|
||||
{% set began = False %}
|
||||
{% if institution_names[loop.index - 1] %}
|
||||
{% if began %}|{% endif %} {{ institution_names[loop.index - 1] }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.program %}
|
||||
{% if began %}|{% endif %} {{ item.program }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.subject %}
|
||||
{% if began %}|{% endif %} {{ item.subject }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.subject_custom %}
|
||||
{% if began %}|{% endif %} {{ item.subject_custom }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.grade %}
|
||||
{% if began %}|{% endif %} {{ item.grade }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.text_type %}
|
||||
{% if began %}|{% endif %} {{ item.text_type }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.text_type_custom %}
|
||||
{% if began %}|{% endif %} {{ item.text_type_custom }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.school_year %}
|
||||
{% if began %}|{% endif %} {{ item.school_year }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
{% if item.grammar_corrections %}
|
||||
{% if began %}|{% endif %} {{ item.grammar_corrections }}
|
||||
{% set began = True %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="rect2" class="mock-side">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user