update predavanja, solar progress

This commit is contained in:
msinkec 2021-05-24 10:15:54 +02:00
parent e840e0b504
commit 3e59662396
14 changed files with 545 additions and 127 deletions

106
app.py
View File

@ -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:

View File

@ -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 ###

View File

@ -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 ###

View File

@ -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()

View File

@ -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)

View File

@ -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,
)

View File

@ -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()

View File

@ -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;
}

View File

@ -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 //

View File

@ -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 //

View File

@ -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>

View File

@ -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>

View 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>

View 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>