solar update
This commit is contained in:
		
							parent
							
								
									31ce97cb44
								
							
						
					
					
						commit
						6697c60c7f
					
				
							
								
								
									
										171
									
								
								app.py
									
									
									
									
									
								
							
							
						
						
									
										171
									
								
								app.py
									
									
									
									
									
								
							@ -9,7 +9,7 @@ from flask import Flask, render_template, request, redirect, flash, safe_join, s
 | 
			
		||||
from flask_dropzone import Dropzone
 | 
			
		||||
from flask_migrate import Migrate, MigrateCommand
 | 
			
		||||
from flask_script import Manager
 | 
			
		||||
from flask_login import LoginManager, login_required, login_user, current_user
 | 
			
		||||
from flask_login import LoginManager, login_required, login_user, current_user, logout_user
 | 
			
		||||
from portal.model import db, RegisteredUser
 | 
			
		||||
 | 
			
		||||
import portal.base
 | 
			
		||||
@ -193,7 +193,8 @@ def index_corpus(corpus_name):
 | 
			
		||||
 | 
			
		||||
@login_manager.user_loader
 | 
			
		||||
def load_user(user_id):
 | 
			
		||||
    return RegisteredUser.query.get(int(user_id))
 | 
			
		||||
    user = RegisteredUser.query.get(int(user_id))
 | 
			
		||||
    return user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/solar/login')
 | 
			
		||||
@ -204,7 +205,7 @@ def login_get():
 | 
			
		||||
@app.route('/<corpus_name>/login', methods=['POST'])
 | 
			
		||||
def login_post(corpus_name):
 | 
			
		||||
    if corpus_name not in ENABLED_CORPUSES or corpus_name not in CORPUSES_LOGIN_REQUIRED:
 | 
			
		||||
        return 404
 | 
			
		||||
        return '', 404
 | 
			
		||||
 | 
			
		||||
    email = request.form.get('email')
 | 
			
		||||
    password = request.form.get('password')
 | 
			
		||||
@ -222,23 +223,32 @@ def login_post(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.')
 | 
			
		||||
        flash('Nimate dostopa do tega korpusa.')
 | 
			
		||||
        return redirect('/{}/login'.format(corpus_name))
 | 
			
		||||
 | 
			
		||||
    #portal.base.add_user_session(user.id)
 | 
			
		||||
    login_user(user, remember=remember)
 | 
			
		||||
 | 
			
		||||
    if corpus_name == 'solar':
 | 
			
		||||
        return redirect('/solar/oddaja')
 | 
			
		||||
    return 404
 | 
			
		||||
    return '', 404
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# TODO: Move solar stuff to seperate file using Flask blueprints.
 | 
			
		||||
# TODO: Better routing logic.
 | 
			
		||||
 | 
			
		||||
@app.route('/solar/logout')
 | 
			
		||||
@login_required
 | 
			
		||||
def logout():
 | 
			
		||||
    logout_user()
 | 
			
		||||
    return redirect('/solar/login')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/solar/<path:text>')
 | 
			
		||||
@login_required
 | 
			
		||||
def solar(text):
 | 
			
		||||
    if not portal.base.has_user_corpus_access(current_user.id, 'solar'):
 | 
			
		||||
        return 404
 | 
			
		||||
        return '', 404
 | 
			
		||||
    if text.startswith('oddaja/') or text == 'oddaja':
 | 
			
		||||
        return render_template('solar-oddaja.html')
 | 
			
		||||
    elif text.startswith('zgodovina/') or text == 'zgodovina':
 | 
			
		||||
@ -256,51 +266,162 @@ def solar(text):
 | 
			
		||||
                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)
 | 
			
		||||
        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)
 | 
			
		||||
            if len(filename) < 10:
 | 
			
		||||
                return '', 404
 | 
			
		||||
            prefix = filename[:2]
 | 
			
		||||
            suffix = filename[2:]
 | 
			
		||||
 | 
			
		||||
            safe_path = safe_join(str(upload_handler_solar.get_uploads_subdir('contracts')), prefix, suffix)
 | 
			
		||||
            try:
 | 
			
		||||
                return send_file(safe_path, as_attachment=True)
 | 
			
		||||
            except FileNotFoundError:
 | 
			
		||||
                return 404
 | 
			
		||||
                return '', 404
 | 
			
		||||
 | 
			
		||||
        user_obj = portal.base.get_user_obj(current_user.get_id())
 | 
			
		||||
        institution_id = user_obj.institution
 | 
			
		||||
 | 
			
		||||
        institutions = portal.base.get_user_institutions(user_obj.id)
 | 
			
		||||
        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
 | 
			
		||||
        contract_school = []
 | 
			
		||||
        enable_upload_school_contract = False
 | 
			
		||||
        show_upload_form = False
 | 
			
		||||
        if len(institutions) > 0:
 | 
			
		||||
            show_upload_form = True
 | 
			
		||||
            institution = portal.base.get_user_institutions(user_obj.id)[0]
 | 
			
		||||
            contracts_students = portal.solar.get_institution_student_contracts(institution.id)
 | 
			
		||||
            contract_school = portal.solar.get_institution_contract(institution.id)
 | 
			
		||||
 | 
			
		||||
            if portal.base.is_institution_moderator(user_obj.id, institution.id):
 | 
			
		||||
                enable_upload_school_contract = True
 | 
			
		||||
 | 
			
		||||
        return render_template('solar-pogodbe.html', contracts_students=contracts_students,
 | 
			
		||||
                contract_school=contract_school, show_upload_form=show_upload_form)
 | 
			
		||||
                contract_school=contract_school, 
 | 
			
		||||
                enable_upload_school_contract=enable_upload_school_contract,
 | 
			
		||||
                show_upload_form=show_upload_form)
 | 
			
		||||
    elif text.startswith('admin/') or text == 'admin':
 | 
			
		||||
        solar_users = portal.base.get_all_active_users()
 | 
			
		||||
        solar_institutions = portal.solar.get_all_institutions()
 | 
			
		||||
        if current_user.role == 'admin':
 | 
			
		||||
            return render_template('solar-admin.html')
 | 
			
		||||
    return 404
 | 
			
		||||
            return render_template('solar-admin.html', users=solar_users, institutions=solar_institutions)
 | 
			
		||||
    return '', 404
 | 
			
		||||
 | 
			
		||||
@app.route('/solar/pogodbe', methods=['POST'])
 | 
			
		||||
@login_required
 | 
			
		||||
def solar_upload_contract():
 | 
			
		||||
    if not portal.base.has_user_corpus_access(current_user.id, 'solar'):
 | 
			
		||||
        return 404
 | 
			
		||||
        return '', 404
 | 
			
		||||
 | 
			
		||||
    return upload_handler_solar.handle_contract_upload(request, current_user.get_id())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/<corpus_name>/adduser', methods=['POST'])
 | 
			
		||||
@login_required
 | 
			
		||||
def solar_add_user(corpus_name):
 | 
			
		||||
    if not portal.base.is_admin(current_user.id):
 | 
			
		||||
        return '', 404
 | 
			
		||||
    if not corpus_name in ENABLED_CORPUSES:
 | 
			
		||||
        return '', 404
 | 
			
		||||
 | 
			
		||||
    name = request.form['name']
 | 
			
		||||
    email = request.form['email']
 | 
			
		||||
    password = request.form['password']
 | 
			
		||||
 | 
			
		||||
    if not name:
 | 
			
		||||
        return 'Prazno polje za ime.'
 | 
			
		||||
    if len(name) > 100:
 | 
			
		||||
        return 'Predolgo ime.'
 | 
			
		||||
 | 
			
		||||
    if not email:
 | 
			
		||||
        return 'Prazno polje za elektronsko pošto.'
 | 
			
		||||
    if len(email) > 100:
 | 
			
		||||
        return 'Predolgi email naslov'
 | 
			
		||||
    elif not re.search(portal.base.REGEX_EMAIL, email):
 | 
			
		||||
        return 'Email napačnega formata.'
 | 
			
		||||
 | 
			
		||||
    if not password:
 | 
			
		||||
        return 'Prazno polje za geslo.'
 | 
			
		||||
    if len(password) > 100:
 | 
			
		||||
        return 'Predolgo geslo.'
 | 
			
		||||
 | 
			
		||||
    portal.base.register_new_user(name, email, password)
 | 
			
		||||
 | 
			
		||||
    return 'Uporabnik je bil dodan.'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/solar/deluser', methods=['POST'])
 | 
			
		||||
@login_required
 | 
			
		||||
def solar_del_user():
 | 
			
		||||
    # TODO: check if user is institution moderator for the added users institution or is an admin
 | 
			
		||||
    # TODO: delete from "user", "user_institution_mapping", update "institution_contract" set user to NULL
 | 
			
		||||
    return '', 404
 | 
			
		||||
 | 
			
		||||
@app.route('/<corpus_name>/addinstitution', methods=['POST'])
 | 
			
		||||
@login_required
 | 
			
		||||
def add_institution(corpus_name):
 | 
			
		||||
    if not portal.base.is_admin(current_user.id):
 | 
			
		||||
        return '', 404
 | 
			
		||||
    if not corpus_name in ENABLED_CORPUSES:
 | 
			
		||||
        return '', 404
 | 
			
		||||
 | 
			
		||||
    name = request.form['name']
 | 
			
		||||
    region = request.form['region']
 | 
			
		||||
 | 
			
		||||
    if not name:
 | 
			
		||||
        return 'Prazno polje za ime.'
 | 
			
		||||
    if len(name) > 100:
 | 
			
		||||
        return 'Predolgo ime.'
 | 
			
		||||
 | 
			
		||||
    if not region:
 | 
			
		||||
        return 'Prazno polje za regijo.'
 | 
			
		||||
    if len(region) > 100:
 | 
			
		||||
        return 'Predolgi niz za regijo.'
 | 
			
		||||
 | 
			
		||||
    institution_id = portal.base.add_institution(name, region)
 | 
			
		||||
    portal.base.grant_institution_corpus_access(institution_id, corpus_name)
 | 
			
		||||
    return 'Institucija je bila dodana.'
 | 
			
		||||
 | 
			
		||||
@app.route('/<corpus_name>/addusertoinstitution', methods=['POST'])
 | 
			
		||||
@login_required
 | 
			
		||||
def add_user_institution_mapping(corpus_name):
 | 
			
		||||
    if not portal.base.is_admin(current_user.id):
 | 
			
		||||
        return '', 404
 | 
			
		||||
    if not corpus_name in ENABLED_CORPUSES:
 | 
			
		||||
        return '', 404
 | 
			
		||||
 | 
			
		||||
    user_id = request.form['user_id']
 | 
			
		||||
    institution_id = request.form['institution_id']
 | 
			
		||||
    role = request.form['role']
 | 
			
		||||
    if role not in ['moderator', 'user']:
 | 
			
		||||
        return '', 404
 | 
			
		||||
 | 
			
		||||
    # TODO: remove this restriction
 | 
			
		||||
    if len(portal.base.get_user_institutions(user_id)) > 0:
 | 
			
		||||
        return 'Uporabnik je že dodeljen instituciji. Dodeljevanje večim institucijam '\
 | 
			
		||||
                'zaenkrat ni implementirano.'
 | 
			
		||||
 | 
			
		||||
    portal.base.add_user_to_institution(user_id, institution_id, role)
 | 
			
		||||
    return 'Uporabnik je bil dodeljen instituciji.'
 | 
			
		||||
 | 
			
		||||
@app.route('/<corpus_name>/delinstitution', methods=['POST'])
 | 
			
		||||
@login_required
 | 
			
		||||
def del_institution(corpus_name):
 | 
			
		||||
    # TODO: check if valid corpus_name
 | 
			
		||||
    # TODO: check if user is admin
 | 
			
		||||
    # TODO: delete cascade - institution, user_institution_mapping, corpus_access, institution_contract
 | 
			
		||||
    return '', 404
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/<corpus_name>/upload', methods=['POST'])
 | 
			
		||||
def handle_upload(corpus_name):
 | 
			
		||||
    if corpus_name not in ENABLED_CORPUSES:
 | 
			
		||||
        return 404
 | 
			
		||||
        return '', 404
 | 
			
		||||
    
 | 
			
		||||
    if corpus_name == 'solar':
 | 
			
		||||
        if not current_user.is_authenticated:
 | 
			
		||||
            return 404
 | 
			
		||||
            return '', 404
 | 
			
		||||
        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())
 | 
			
		||||
    elif corpus_name == 'predavanja':
 | 
			
		||||
        return upload_handler_predavanja.handle_upload(request)
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,66 @@
 | 
			
		||||
"""Changed user<->institution<->corpus relational mapping.
 | 
			
		||||
 | 
			
		||||
Revision ID: 5ba116fc7f06
 | 
			
		||||
Revises: 7d6db184b8fc
 | 
			
		||||
Create Date: 2021-06-07 13:02:42.900168
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from alembic import op
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# revision identifiers, used by Alembic.
 | 
			
		||||
revision = '5ba116fc7f06'
 | 
			
		||||
down_revision = '7d6db184b8fc'
 | 
			
		||||
branch_labels = None
 | 
			
		||||
depends_on = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgrade():
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.create_table('institution_contract',
 | 
			
		||||
    sa.Column('id', sa.Integer(), nullable=False),
 | 
			
		||||
    sa.Column('institution', sa.Integer(), nullable=False),
 | 
			
		||||
    sa.Column('corpus', sa.String(), nullable=False),
 | 
			
		||||
    sa.Column('timestamp', sa.DateTime(), nullable=False),
 | 
			
		||||
    sa.Column('file_contract', sa.String(), nullable=True),
 | 
			
		||||
    sa.ForeignKeyConstraint(['institution'], ['institution.id'], ),
 | 
			
		||||
    sa.PrimaryKeyConstraint('id')
 | 
			
		||||
    )
 | 
			
		||||
    op.create_table('user_institution_mapping',
 | 
			
		||||
    sa.Column('id', sa.Integer(), nullable=False),
 | 
			
		||||
    sa.Column('user', sa.Integer(), nullable=False),
 | 
			
		||||
    sa.Column('institution', sa.Integer(), nullable=False),
 | 
			
		||||
    sa.Column('role', sa.String(), nullable=False),
 | 
			
		||||
    sa.ForeignKeyConstraint(['institution'], ['institution.id'], ),
 | 
			
		||||
    sa.ForeignKeyConstraint(['user'], ['registered_user.id'], ),
 | 
			
		||||
    sa.PrimaryKeyConstraint('id')
 | 
			
		||||
    )
 | 
			
		||||
    op.add_column('corpus_access', sa.Column('institution', sa.Integer(), nullable=False))
 | 
			
		||||
    op.drop_constraint('user_id_fkey', 'corpus_access', type_='foreignkey')
 | 
			
		||||
    op.create_foreign_key(None, 'corpus_access', 'institution', ['institution'], ['id'])
 | 
			
		||||
    op.drop_column('corpus_access', 'user_id')
 | 
			
		||||
    op.create_unique_constraint(None, 'institution', ['name'])
 | 
			
		||||
    op.drop_column('institution', 'file_contract')
 | 
			
		||||
    op.create_unique_constraint(None, 'registered_user', ['email'])
 | 
			
		||||
    op.drop_constraint('registered_user_institution_fkey', 'registered_user', type_='foreignkey')
 | 
			
		||||
    op.drop_column('registered_user', 'institution_moderator')
 | 
			
		||||
    op.drop_column('registered_user', 'institution')
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def downgrade():
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.add_column('registered_user', sa.Column('institution', sa.INTEGER(), autoincrement=False, nullable=True))
 | 
			
		||||
    op.add_column('registered_user', sa.Column('institution_moderator', sa.BOOLEAN(), autoincrement=False, nullable=True))
 | 
			
		||||
    op.create_foreign_key('registered_user_institution_fkey', 'registered_user', 'institution', ['institution'], ['id'])
 | 
			
		||||
    op.drop_constraint(None, 'registered_user', type_='unique')
 | 
			
		||||
    op.add_column('institution', sa.Column('file_contract', sa.TEXT(), autoincrement=False, nullable=True))
 | 
			
		||||
    op.drop_constraint(None, 'institution', type_='unique')
 | 
			
		||||
    op.add_column('corpus_access', sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False))
 | 
			
		||||
    op.drop_constraint(None, 'corpus_access', type_='foreignkey')
 | 
			
		||||
    op.create_foreign_key('user_id_fkey', 'corpus_access', 'registered_user', ['user_id'], ['id'])
 | 
			
		||||
    op.drop_column('corpus_access', 'institution')
 | 
			
		||||
    op.drop_table('user_institution_mapping')
 | 
			
		||||
    op.drop_table('institution_contract')
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
@ -3,6 +3,7 @@ import time
 | 
			
		||||
import ssl
 | 
			
		||||
import traceback
 | 
			
		||||
import re
 | 
			
		||||
import logging
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
@ -19,7 +20,9 @@ from email.mime.application import MIMEApplication
 | 
			
		||||
import pdfkit
 | 
			
		||||
from jinja2 import Environment, FileSystemLoader
 | 
			
		||||
 | 
			
		||||
from . model import db, UploadRegular, UploadSolar, RegisteredUser, CorpusAccess, Institution
 | 
			
		||||
from werkzeug.security import generate_password_hash
 | 
			
		||||
 | 
			
		||||
from . model import db, UploadRegular, UploadSolar, RegisteredUser, UserInstitutionMapping, Institution, InstitutionContract, CorpusAccess
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#REGEX_EMAIL = re.compile('^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$')
 | 
			
		||||
@ -131,7 +134,7 @@ class UploadHandler:
 | 
			
		||||
        return res
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def store_model(self, model_obj):
 | 
			
		||||
    def store_model(model_obj):
 | 
			
		||||
        try:
 | 
			
		||||
            db.session.add(model_obj)
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
@ -234,20 +237,100 @@ class UploadHandler:
 | 
			
		||||
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_user_institution(user_id):
 | 
			
		||||
        match = db.session.query(RegisteredUser).filter(RegisteredUser.id == user_id).one()
 | 
			
		||||
        return match.institution
 | 
			
		||||
 | 
			
		||||
def get_user_institutions(user_id):
 | 
			
		||||
    return UserInstitutionMapping.query.filter_by(user=user_id).all()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def has_user_corpus_access(user_id, corpus_name):
 | 
			
		||||
    user = RegisteredUser.query.filter_by(id=user_id).first()
 | 
			
		||||
 | 
			
		||||
    # TODO: check if user even is active?
 | 
			
		||||
 | 
			
		||||
    # Admins always have access to everything.
 | 
			
		||||
    if user.role == 'admin':
 | 
			
		||||
        return True
 | 
			
		||||
    return CorpusAccess.query.filter_by(user_id=user.id, corpus=corpus_name).first() is not None
 | 
			
		||||
 | 
			
		||||
    # Check if user belongs to an institution, that has access to this corpus.
 | 
			
		||||
    institutions = get_user_institutions(user_id)
 | 
			
		||||
    has_access = False
 | 
			
		||||
    for institution in institutions:
 | 
			
		||||
        row = CorpusAccess.query.filter_by(institution=institution.id, corpus=corpus_name).first()
 | 
			
		||||
        if row:
 | 
			
		||||
            has_access = True
 | 
			
		||||
            break
 | 
			
		||||
    return has_access
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_admin(user_id):
 | 
			
		||||
    user = RegisteredUser.query.filter_by(id=user_id).first()
 | 
			
		||||
    if user.role == 'admin':
 | 
			
		||||
        return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def register_new_user(name, email, password, active=True, admin=False):
 | 
			
		||||
    model_obj = RegisteredUser(
 | 
			
		||||
                name=name,
 | 
			
		||||
                email=email,
 | 
			
		||||
                role='admin' if admin else 'user',
 | 
			
		||||
                pass_hash=generate_password_hash(password),
 | 
			
		||||
                active=active,
 | 
			
		||||
                registered=datetime.now()
 | 
			
		||||
           )
 | 
			
		||||
    db.session.add(model_obj)
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return model_obj.id
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_institution(name, region):
 | 
			
		||||
    model_obj = Institution(
 | 
			
		||||
                name=name,
 | 
			
		||||
                region=region
 | 
			
		||||
           )
 | 
			
		||||
    db.session.add(model_obj)
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return model_obj.id
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def grant_institution_corpus_access(institution_id, corpus_name):
 | 
			
		||||
    model_obj = CorpusAccess(
 | 
			
		||||
                institution=institution_id,
 | 
			
		||||
                corpus=corpus_name
 | 
			
		||||
           )
 | 
			
		||||
    db.session.add(model_obj)
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return model_obj.id
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_user_to_institution(user_id, institution_id, role):
 | 
			
		||||
    model_obj = UserInstitutionMapping(
 | 
			
		||||
                user=user_id,
 | 
			
		||||
                institution=institution_id,
 | 
			
		||||
                role=role
 | 
			
		||||
           )
 | 
			
		||||
    db.session.add(model_obj)
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return model_obj.id
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_all_active_users():
 | 
			
		||||
    return RegisteredUser.query.filter_by(active=True).all()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_institution_moderator(user_id, institution_id):
 | 
			
		||||
    user_inst_mapping = UserInstitutionMapping.query.filter_by(user=user_id).first()
 | 
			
		||||
    if not user_inst_mapping:
 | 
			
		||||
        return False
 | 
			
		||||
    if user_inst_mapping.role != 'moderator':
 | 
			
		||||
        return False
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -83,31 +83,45 @@ class ContractsSolar(db.Model):
 | 
			
		||||
    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, nullable=False)
 | 
			
		||||
    email = db.Column(db.String, nullable=False)
 | 
			
		||||
    email = db.Column(db.String, nullable=False, unique=True)
 | 
			
		||||
    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 UserInstitutionMapping(db.Model):
 | 
			
		||||
    __tablename__ = 'user_institution_mapping'
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)
 | 
			
		||||
    user = db.Column(db.Integer, sqlalchemy.ForeignKey('registered_user.id'), nullable=False)
 | 
			
		||||
    institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=False)
 | 
			
		||||
    role =db.Column(db.String, nullable=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Institution(db.Model):
 | 
			
		||||
    __tablename__ = 'institution'
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)
 | 
			
		||||
    name =  db.Column(db.String, nullable=False)
 | 
			
		||||
    name =  db.Column(db.String, nullable=False, unique=True)
 | 
			
		||||
    region =  db.Column(db.String, nullable=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CorpusAccess(db.Model):
 | 
			
		||||
    __tablename__ = 'corpus_access'
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)
 | 
			
		||||
    institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=False)
 | 
			
		||||
    corpus =  db.Column(db.String, nullable=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InstitutionContract(db.Model):
 | 
			
		||||
    __tablename__ = 'institution_contract'
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)
 | 
			
		||||
    institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=False)
 | 
			
		||||
    corpus =  db.Column(db.String, nullable=False)
 | 
			
		||||
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
 | 
			
		||||
    file_contract =  db.Column(db.String, nullable=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,10 +3,10 @@ import re
 | 
			
		||||
import traceback
 | 
			
		||||
import hashlib
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from sqlalchemy import desc
 | 
			
		||||
from sqlalchemy import desc, exists
 | 
			
		||||
 | 
			
		||||
from portal.base import UploadHandler
 | 
			
		||||
from portal.model import db, UploadSolar, ContractsSolar, RegisteredUser, Institution
 | 
			
		||||
from portal.base import UploadHandler, get_user_institutions, has_user_corpus_access
 | 
			
		||||
from portal.model import db, UploadSolar, ContractsSolar, RegisteredUser, Institution, InstitutionContract, UserInstitutionMapping, CorpusAccess
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'}
 | 
			
		||||
@ -27,7 +27,8 @@ class UploadHandlerSolar(UploadHandler):
 | 
			
		||||
        sorted_f_hashes = list(file_hashes.values())
 | 
			
		||||
        sorted_f_hashes.sort()
 | 
			
		||||
 | 
			
		||||
        institution_id = UploadHandler.get_user_institution(user_id)
 | 
			
		||||
        # If user is mapped to multiple institutions, let him chose in name of which one he makes the upload.
 | 
			
		||||
        institution_id = get_user_institutions(user_id)[0].id
 | 
			
		||||
 | 
			
		||||
        model_obj = UploadSolar(
 | 
			
		||||
                    upload_user = user_id,
 | 
			
		||||
@ -44,7 +45,7 @@ class UploadHandlerSolar(UploadHandler):
 | 
			
		||||
                    grammar_corrections=form_data['jezikovni-popravki'],
 | 
			
		||||
                    upload_file_hashes=sorted_f_hashes
 | 
			
		||||
               )
 | 
			
		||||
        self.store_model(model_obj)
 | 
			
		||||
        UploadHandler.store_model(model_obj)
 | 
			
		||||
 | 
			
		||||
    def handle_upload(self, request, user_id):
 | 
			
		||||
        err = self.check_upload_request(request)
 | 
			
		||||
@ -73,9 +74,9 @@ 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']
 | 
			
		||||
        contract_type = request.form['tip-pogodbe']
 | 
			
		||||
        
 | 
			
		||||
        if contracts_type not in ['sola', 'ucenci-starsi']:
 | 
			
		||||
        if contract_type not in ['sola', 'ucenci-starsi']:
 | 
			
		||||
            return 'Neveljaven tip pogodbe.'
 | 
			
		||||
 | 
			
		||||
        f_obj = None
 | 
			
		||||
@ -92,35 +93,46 @@ class UploadHandlerSolar(UploadHandler):
 | 
			
		||||
            return 'Niste naložili nobene datoteke.'
 | 
			
		||||
 | 
			
		||||
        base = self.get_uploads_subdir('contracts')
 | 
			
		||||
        f_hash = hashlib.md5(f_obj.read())
 | 
			
		||||
        f_hash = hashlib.md5(f_obj.read()).hexdigest()
 | 
			
		||||
        f_obj.seek(0, 0)
 | 
			
		||||
 | 
			
		||||
        # 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'
 | 
			
		||||
        path = sub_dir / (f_hash[2:] + '.pdf')
 | 
			
		||||
        f_obj.save(path)
 | 
			
		||||
 | 
			
		||||
        timestamp = datetime.now()
 | 
			
		||||
        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:
 | 
			
		||||
        user_institution_mapping = UserInstitutionMapping.query.filter_by(user=user_id).first()
 | 
			
		||||
        if user_institution_mapping is None:
 | 
			
		||||
            return 'Vaš uporabnik ni dodeljen nobeni inštituciji.'
 | 
			
		||||
        institution_id = user_institution_mapping.institution
 | 
			
		||||
        is_institution_moderator = True if user_institution_mapping.role == 'moderator' else False
 | 
			
		||||
 | 
			
		||||
        if contracts_type == 'sola':
 | 
			
		||||
        if contract_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)
 | 
			
		||||
            # TODO: insert institution contract
 | 
			
		||||
            model_obj = InstitutionContract(
 | 
			
		||||
                        institution=institution_id,
 | 
			
		||||
                        corpus='solar',
 | 
			
		||||
                        timestamp=timestamp,
 | 
			
		||||
                        file_contract=f_hash
 | 
			
		||||
                        )
 | 
			
		||||
            self.store_model(model_obj)
 | 
			
		||||
        else:
 | 
			
		||||
            model_obj = ContractsSolar(
 | 
			
		||||
                        institution=institution_id,
 | 
			
		||||
                        upload_user=user_id,
 | 
			
		||||
                        timestamp=timestamp,
 | 
			
		||||
                        file_contract=f_hash,
 | 
			
		||||
                        contract_type=contract_type,
 | 
			
		||||
                   )
 | 
			
		||||
 | 
			
		||||
        model_obj = ContractsSolar(
 | 
			
		||||
                    institution=institution_id,
 | 
			
		||||
                    upload_user=user_id,
 | 
			
		||||
                    file_contract=f_hash,
 | 
			
		||||
                    contracts_type=contracts_type,
 | 
			
		||||
               )
 | 
			
		||||
        self.store_model(model_obj)
 | 
			
		||||
            self.store_model(model_obj)
 | 
			
		||||
        return 'Nalaganje pogodbe je bilo uspešno.'
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
@ -154,12 +166,30 @@ 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_all_institutions():
 | 
			
		||||
    # TODO: do filtering purely within an SQL query
 | 
			
		||||
    res = []
 | 
			
		||||
    for institution in Institution.query.all():
 | 
			
		||||
        row = CorpusAccess.query.filter_by(institution=institution.id, corpus='solar').first()
 | 
			
		||||
        if row:
 | 
			
		||||
            res.append(institution)
 | 
			
		||||
    return res
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_institution_student_contracts(institution_id):
 | 
			
		||||
    return ContractsSolar.query.filter_by(id=institution_id, contract_type='ucenci-starsi').all()
 | 
			
		||||
    return ContractsSolar.query.filter_by(institution=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()
 | 
			
		||||
    
 | 
			
		||||
    return InstitutionContract.query.filter_by(institution=institution_id, corpus='solar').order_by(desc(InstitutionContract.timestamp)).first()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_all_active_users():
 | 
			
		||||
    # TODO: do filtering purely within an SQL query
 | 
			
		||||
    res = []
 | 
			
		||||
    active_users = RegisteredUser.query.filter_by(active=True).all()
 | 
			
		||||
    for user in active_users:
 | 
			
		||||
        if has_user_corpus_access(user.id, 'solar'):
 | 
			
		||||
            res.append(user)
 | 
			
		||||
    return res
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -84,6 +84,20 @@ html {
 | 
			
		||||
  color: #006cb7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.section-desc {
 | 
			
		||||
  font-family: Roboto;
 | 
			
		||||
  font-style: bold;
 | 
			
		||||
  font-weight: 320;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  line-height: 20px;
 | 
			
		||||
  margin-block-start: 0.4em;
 | 
			
		||||
  border-bottom: 3px solid #006cb7;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
  padding-bottom: 10px;
 | 
			
		||||
  color: #006cb7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
label {
 | 
			
		||||
  font-family: Roboto;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										110
									
								
								templates/solar-admin.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								templates/solar-admin.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,110 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <title>Admin panel - Šolar</title>
 | 
			
		||||
    <style>
 | 
			
		||||
          .tableFixHead {
 | 
			
		||||
            overflow-y: auto;
 | 
			
		||||
            height: 106px;
 | 
			
		||||
          }
 | 
			
		||||
          .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>
 | 
			
		||||
    <h2>Uporabniki</h2>
 | 
			
		||||
    <h3>Dodaj uporabnika</h3>
 | 
			
		||||
    <form action="/solar/adduser" method="post">
 | 
			
		||||
        <label for="name">Ime in priimek:</label><br>
 | 
			
		||||
        <input type="text" id="name" name="name"><br>
 | 
			
		||||
        <label for="email">Email:</label><br>
 | 
			
		||||
        <input type="text" id="email" name="email"><br>
 | 
			
		||||
        <label for="password">Geslo:</label><br>
 | 
			
		||||
        <input type="text" id="password" name="password"><br>
 | 
			
		||||
        <input type="submit" value="Dodaj">
 | 
			
		||||
    </form> 
 | 
			
		||||
    <!--<h3>Odstrani uporabnika</h3>
 | 
			
		||||
    <form action="/solar/deluser" method="post">
 | 
			
		||||
        <label for="user_id">ID uporabnika:</label><br>
 | 
			
		||||
        <input type="text" id="user_id" name="user_id"><br>
 | 
			
		||||
        <input type="submit" value="Odstrani">
 | 
			
		||||
    </form>-->
 | 
			
		||||
    <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>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="institution_id">ID institucije:</label>
 | 
			
		||||
        <input type="text" id="institution_id" name="institution_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>
 | 
			
		||||
    <div> </div>
 | 
			
		||||
    <h2>Institucije</h2>
 | 
			
		||||
    <h3>Dodaj institucijo</h3>
 | 
			
		||||
    <form action="/solar/addinstitution" method="post">
 | 
			
		||||
        <label for="name">Naziv:</label>
 | 
			
		||||
        <input type="text" id="name" name="name"><br>
 | 
			
		||||
        <label for="region">Regija:</label>
 | 
			
		||||
        <input type="text" id="region" name="region"><br>
 | 
			
		||||
        <input type="submit" value="Dodaj">
 | 
			
		||||
    </form>
 | 
			
		||||
    <h3>Seznam vseh instituticij</h3>
 | 
			
		||||
    <div class="tableFixHead">
 | 
			
		||||
      <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <th>ID</th>
 | 
			
		||||
                <th>Naziv</th>
 | 
			
		||||
                <th>Regija</th>
 | 
			
		||||
              </tr>
 | 
			
		||||
          </thead>
 | 
			
		||||
          <tbody>
 | 
			
		||||
          {% for item in institutions %}
 | 
			
		||||
          <tr>
 | 
			
		||||
              <td>{{item.id}}</td>
 | 
			
		||||
              <td>{{item.name}}</td>
 | 
			
		||||
              <td>{{item.region}}</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
      </table>
 | 
			
		||||
    </div>
 | 
			
		||||
</body>
 | 
			
		||||
							
								
								
									
										13
									
								
								templates/solar-institution-managment.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								templates/solar-institution-managment.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
<!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>
 | 
			
		||||
@ -18,6 +18,7 @@
 | 
			
		||||
    <link rel="stylesheet" href="/static/style.css" type="text/css">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <a href="/solar/logout">Odjavi se</a>
 | 
			
		||||
    <div class="bg"></div>
 | 
			
		||||
    <div id="main-window">
 | 
			
		||||
        <div id="rect1">
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
    <link rel="stylesheet" href="/static/style.css" type="text/css">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <a href="/solar/logout">Odjavi se</a>
 | 
			
		||||
    <div class="bg"></div>
 | 
			
		||||
    <div id="main-window">
 | 
			
		||||
        <div id="rect1">
 | 
			
		||||
@ -22,33 +23,49 @@
 | 
			
		||||
            </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>
 | 
			
		||||
                <div class="contract-item" style="background-color: #ccffcc;">
 | 
			
		||||
                    <div class="contract-item-icon"></div>
 | 
			
		||||
                    <div class="contract-item-title">Pogodba s šolo</div>
 | 
			
		||||
                    <div class="contract-item-date">DODANO {{contract_school.date}}</div>
 | 
			
		||||
                    <a href="/solar/pogodbe/{{ contract_school.file_contract }}.pdf" class="contract-item-button">PRENESI</a>
 | 
			
		||||
                </div>
 | 
			
		||||
                </br>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                {% for item in contracts_students %}
 | 
			
		||||
                    <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-date">DODANO {{item.date}}</div>
 | 
			
		||||
                        <a href="/solar/pogodbe/{{ item.file_hash }}.pdf" class="contract-item-button">PRENESI</div>
 | 
			
		||||
                        <a href="/solar/pogodbe/{{ item.file_contract }}.pdf" class="contract-item-button">PRENESI</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    </br>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
            </div>
 | 
			
		||||
            </br>
 | 
			
		||||
            </br>
 | 
			
		||||
            {% 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">
 | 
			
		||||
            <div style="padding: 20px; position: absolute; top: 500px; width: 89%;">
 | 
			
		||||
                <div class="section-desc">Oddaj pogodbo</div>
 | 
			
		||||
                <form action="/solar/pogodbe" method="post" enctype="multipart/form-data">
 | 
			
		||||
                    {% if enable_upload_school_contract %}
 | 
			
		||||
                    <div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
 | 
			
		||||
                        <label style="width: 80%; text-align: right;" for="sola">Pogodba s šolo</label>
 | 
			
		||||
                        <input style="width: 20%;" type="radio" id="sola" name="tip-pogodbe" value="sola">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                    <div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
 | 
			
		||||
                        <label style="width: 80%; text-align: right;" for="sola">Pogodba s šolo</label>
 | 
			
		||||
                        <input style="width: 20%;"type="radio" id="sola" name="tip-pogodbe" value="sola" disabled>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    <div style="display:flex; flex-direction: row; justify-content: left; align-items: center">
 | 
			
		||||
                        <label style="width: 80%; text-align: right;" for="ucenci-starsi">Pogodba z učenci / starši</label>
 | 
			
		||||
                        <input style="width: 20%;" type="radio" id="ucenci-starsi" name="tip-pogodbe" value="ucenci-starsi" checked>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <input style="font-size: 10px;" type="file" id="file-contract" name="filename">
 | 
			
		||||
                    <button style="float: right;" type="submit">Oddaj pogodbo</button>
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div id="rect2" class="mock-side">
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
    <link rel="stylesheet" href="/static/style.css" type="text/css">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <a href="/solar/logout">Odjavi se</a>
 | 
			
		||||
    <div class="bg"></div>
 | 
			
		||||
    <div id="main-window">
 | 
			
		||||
        <div id="rect1">
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user