Šolar update.
This commit is contained in:
parent
788f3bc3eb
commit
d60ef26741
179
app.py
179
app.py
|
@ -163,6 +163,7 @@ def index_corpus(corpus_name):
|
||||||
if corpus_name not in ENABLED_CORPUSES:
|
if corpus_name not in ENABLED_CORPUSES:
|
||||||
return 'Korpus "{}" ne obstaja.'.format(corpus_name), 404
|
return 'Korpus "{}" ne obstaja.'.format(corpus_name), 404
|
||||||
|
|
||||||
|
description = ""
|
||||||
if corpus_name == 'prevodi':
|
if corpus_name == 'prevodi':
|
||||||
description = DESC_PREVODI
|
description = DESC_PREVODI
|
||||||
elif corpus_name == 'gigafida':
|
elif corpus_name == 'gigafida':
|
||||||
|
@ -253,19 +254,22 @@ def solar_register_post():
|
||||||
flash('Predolgo geslo.')
|
flash('Predolgo geslo.')
|
||||||
return redirect('/solar/register')
|
return redirect('/solar/register')
|
||||||
|
|
||||||
if not institution:
|
|
||||||
flash('Institucija ne obstaja.')
|
|
||||||
return redirect('/solar/register')
|
|
||||||
|
|
||||||
if institution_role not in ['coordinator', 'mentor', 'other']:
|
if institution_role not in ['coordinator', 'mentor', 'other']:
|
||||||
flash('Neveljavna vloga v instituciji.')
|
flash('Neveljavna vloga v instituciji.')
|
||||||
return redirect('/solar/register')
|
return redirect('/solar/register')
|
||||||
|
|
||||||
|
if not institution:
|
||||||
|
institution_id = portal.base.add_institution(institution_name, "")
|
||||||
|
portal.base.grant_institution_corpus_access(institution_id, "solar")
|
||||||
|
else:
|
||||||
|
institution_id = institution.id
|
||||||
|
|
||||||
user_id = portal.base.register_new_user(name, email, password, active=False)
|
user_id = portal.base.register_new_user(name, email, password, active=False)
|
||||||
portal.base.add_user_to_institution(user_id, institution.id, institution_role)
|
portal.base.add_user_to_institution(user_id, institution_id, institution_role)
|
||||||
|
|
||||||
flash('Uspešna registracija.')
|
portal.base.send_admins_new_user_notification_mail(user_id, upload_handler_solar.config)
|
||||||
|
|
||||||
|
flash('Podatki so bili poslani v potrditev. Ko bo registracija potrjena, boste o tem obveščeni po e-mailu, ki ste ga posredovali zgoraj.')
|
||||||
return redirect('/solar/login')
|
return redirect('/solar/login')
|
||||||
|
|
||||||
|
|
||||||
|
@ -300,11 +304,13 @@ def solar(text):
|
||||||
institution_contract=institution_contract,
|
institution_contract=institution_contract,
|
||||||
is_institution_coordinator=current_user_institution_coordinator)
|
is_institution_coordinator=current_user_institution_coordinator)
|
||||||
elif text.startswith('zgodovina/') or text == 'zgodovina':
|
elif text.startswith('zgodovina/') or text == 'zgodovina':
|
||||||
upload_items = portal.solar.get_upload_history(current_user.id)
|
upload_items = []
|
||||||
|
if current_user_institution:
|
||||||
|
upload_items = portal.solar.get_institution_upload_history(current_user_institution.id, n=1000)
|
||||||
uploader_names = []
|
uploader_names = []
|
||||||
institution_names = []
|
institution_names = []
|
||||||
for item in upload_items:
|
for item in upload_items:
|
||||||
uploader_names.append(portal.base.get_user_obj(current_user.id).name)
|
uploader_names.append(portal.base.get_user_obj(item.upload_user).name)
|
||||||
institution = portal.base.get_institution_obj(item.institution)
|
institution = portal.base.get_institution_obj(item.institution)
|
||||||
if not institution:
|
if not institution:
|
||||||
institution_names.append(None)
|
institution_names.append(None)
|
||||||
|
@ -358,6 +364,7 @@ def solar(text):
|
||||||
show_upload_form=show_upload_form,
|
show_upload_form=show_upload_form,
|
||||||
collaborators=collaborators,
|
collaborators=collaborators,
|
||||||
cooperation_history=cooperation_history,
|
cooperation_history=cooperation_history,
|
||||||
|
user_id=current_user.id,
|
||||||
is_admin=is_admin, is_institution_coordinator=current_user_institution_coordinator)
|
is_admin=is_admin, is_institution_coordinator=current_user_institution_coordinator)
|
||||||
elif text.startswith('admin/') or text == 'admin':
|
elif text.startswith('admin/') or text == 'admin':
|
||||||
users = portal.base.get_all_users_join_institutions()
|
users = portal.base.get_all_users_join_institutions()
|
||||||
|
@ -378,7 +385,9 @@ def solar(text):
|
||||||
@app.route('/solar/pogodbe', methods=['POST'])
|
@app.route('/solar/pogodbe', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def solar_upload_contract():
|
def solar_upload_contract():
|
||||||
return upload_handler_solar.handle_contract_upload(request, current_user.get_id())
|
msg = upload_handler_solar.handle_contract_upload(request, current_user.get_id())
|
||||||
|
flash(msg)
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
|
||||||
@app.route('/solar/adduser', methods=['POST'])
|
@app.route('/solar/adduser', methods=['POST'])
|
||||||
|
@ -416,6 +425,12 @@ def solar_add_user():
|
||||||
flash('Predolgo geslo.')
|
flash('Predolgo geslo.')
|
||||||
return redirect(redirect_url())
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
user = portal.base.get_user_obj_by_email(email)
|
||||||
|
if user:
|
||||||
|
#portal.base.undo_remove_user(user.id)
|
||||||
|
flash('Uporabnik s tem emailom je že vnešen v sistem.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
portal.base.register_new_user(name, email, password)
|
portal.base.register_new_user(name, email, password)
|
||||||
|
|
||||||
flash('Uporabnik je bil uspešno dodan.')
|
flash('Uporabnik je bil uspešno dodan.')
|
||||||
|
@ -437,6 +452,8 @@ def solar_activate_user():
|
||||||
if rowcount == 0:
|
if rowcount == 0:
|
||||||
return '', 404
|
return '', 404
|
||||||
|
|
||||||
|
portal.base.send_user_activation_mail(user_id, upload_handler_solar.config)
|
||||||
|
|
||||||
flash('Uporabnik je bil aktiviran.')
|
flash('Uporabnik je bil aktiviran.')
|
||||||
return redirect(redirect_url())
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
@ -494,23 +511,21 @@ def solar_del_user():
|
||||||
if not portal.base.is_admin(current_user.id):
|
if not portal.base.is_admin(current_user.id):
|
||||||
return '', 404
|
return '', 404
|
||||||
user_id = request.form.get('user_id')
|
user_id = request.form.get('user_id')
|
||||||
portal.base.del_user(user_id)
|
portal.base.remove_user(user_id)
|
||||||
flash('Uporabnik je bil odstranjen.')
|
flash('Uporabnik je bil odstranjen.')
|
||||||
return redirect(redirect_url())
|
return redirect(redirect_url())
|
||||||
|
|
||||||
@app.route('/<corpus_name>/addinstitution', methods=['POST'])
|
@app.route('/solar/addinstitution', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def add_institution(corpus_name):
|
def add_institution():
|
||||||
if not portal.base.is_admin(current_user.id):
|
if not portal.base.is_admin(current_user.id):
|
||||||
return '', 404
|
return '', 404
|
||||||
if not corpus_name in ENABLED_CORPUSES:
|
|
||||||
return '', 404
|
|
||||||
|
|
||||||
name = request.form.get('name')
|
name = request.form.get('name')
|
||||||
region = request.form.get('region')
|
region = request.form.get('region')
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
flash('Prazno polje za ime.')
|
flash('Prazno polje za naziv.')
|
||||||
return redirect(redirect_url())
|
return redirect(redirect_url())
|
||||||
if len(name) > 100:
|
if len(name) > 100:
|
||||||
flash('Predolgo ime.')
|
flash('Predolgo ime.')
|
||||||
|
@ -521,10 +536,142 @@ def add_institution(corpus_name):
|
||||||
return redirect(redirect_url())
|
return redirect(redirect_url())
|
||||||
|
|
||||||
institution_id = portal.base.add_institution(name, region)
|
institution_id = portal.base.add_institution(name, region)
|
||||||
portal.base.grant_institution_corpus_access(institution_id, corpus_name)
|
portal.base.grant_institution_corpus_access(institution_id, "solar") # TODO: throw out
|
||||||
flash('Institucija je bila dodana.')
|
flash('Institucija je bila dodana.')
|
||||||
return redirect(redirect_url())
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
@app.route('/solar/mergeinstitutions', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def merge_institutions():
|
||||||
|
if not portal.base.is_admin(current_user.id):
|
||||||
|
return '', 404
|
||||||
|
|
||||||
|
id_from = request.form.get('id-from')
|
||||||
|
id_to = request.form.get('id-to')
|
||||||
|
|
||||||
|
if not id_from or not id_to:
|
||||||
|
flash('Prazno polje.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
institution_from = portal.base.get_institution_obj(id_from)
|
||||||
|
institution_to = portal.base.get_institution_obj(id_to)
|
||||||
|
|
||||||
|
if not institution_from:
|
||||||
|
flash('Institucija z ID "{}" ne obstaja.'.format(id_from))
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
if not institution_to:
|
||||||
|
flash('Institucija z ID "{}" ne obstaja.'.format(id_to))
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
|
||||||
|
portal.base.transfer_users_institution(institution_from.id, institution_to.id)
|
||||||
|
portal.base.transfer_uploads_institution(institution_from.id, institution_to.id)
|
||||||
|
portal.base.transfer_contracts_institution(institution_from.id, institution_to.id)
|
||||||
|
portal.base.remove_institution(institution_from.id)
|
||||||
|
|
||||||
|
flash('Instituciji uspešno združeni')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
@app.route('/solar/addcooperationhistoryitem', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def add_cooperation_history_item():
|
||||||
|
if not portal.base.is_admin(current_user.id):
|
||||||
|
return '', 404
|
||||||
|
|
||||||
|
user_id = request.form.get('user')
|
||||||
|
institution_id = request.form.get('institution')
|
||||||
|
role = request.form.get('role')
|
||||||
|
school_year = request.form.get('school-year')
|
||||||
|
badge_text = request.form.get('badge-text')
|
||||||
|
|
||||||
|
user = portal.base.get_user_obj(user_id)
|
||||||
|
institution = portal.base.get_institution_obj(institution_id)
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
flash('Uporabnik s tem ID-jem ne obstaja.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
if not institution:
|
||||||
|
flash('Institucija s tem ID-jem ne obstaja.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
if not role in ['coordinator', 'mentor', 'other']:
|
||||||
|
flash('Neveljavna vloga "{}".'.format(role))
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
if not school_year or not re.match('[0-9]{4}/[0-9]{2}', school_year):
|
||||||
|
flash('Šolsko leto mora biti formata "2021/22".')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
portal.base.add_cooperation_history_item(user_id, institution_id, role, school_year, badge_text)
|
||||||
|
|
||||||
|
flash('Vnos dodan.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
@app.route('/solar/delcooperationhistoryitem', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def del_cooperation_history_item():
|
||||||
|
if not portal.base.is_admin(current_user.id):
|
||||||
|
return '', 404
|
||||||
|
|
||||||
|
entry_id = request.form.get('entry-id')
|
||||||
|
portal.base.del_cooperation_history_item(entry_id)
|
||||||
|
|
||||||
|
flash('Vnos odstranjen.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
@app.route('/solar/changeuseremail', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def change_user_email():
|
||||||
|
if not portal.base.is_admin(current_user.id):
|
||||||
|
return '', 404
|
||||||
|
|
||||||
|
user_id = request.form.get('user-id')
|
||||||
|
email = request.form.get('email')
|
||||||
|
|
||||||
|
if not re.search(portal.base.REGEX_EMAIL, email):
|
||||||
|
flash('Email napačnega formata.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
portal.base.update_user_email(user_id, email)
|
||||||
|
|
||||||
|
flash('Email spremenjen.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/solar/changeuserrole', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def change_user_role():
|
||||||
|
if not portal.base.is_admin(current_user.id):
|
||||||
|
return '', 404
|
||||||
|
|
||||||
|
user_id = request.form.get('user-id')
|
||||||
|
role = request.form.get('role')
|
||||||
|
|
||||||
|
if not role in ['admin', 'user']:
|
||||||
|
flash('Neveljavna vloga.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
portal.base.update_user_role(user_id, role)
|
||||||
|
|
||||||
|
flash('Vloga spremenjena.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
|
@app.route('/solar/changeusername', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def change_user_name():
|
||||||
|
if not portal.base.is_admin(current_user.id):
|
||||||
|
return '', 404
|
||||||
|
|
||||||
|
user_id = request.form.get('user-id')
|
||||||
|
name = request.form.get('name')
|
||||||
|
|
||||||
|
portal.base.update_user_name(user_id, name)
|
||||||
|
|
||||||
|
flash('Ime in priimek spremenjena.')
|
||||||
|
return redirect(redirect_url())
|
||||||
|
|
||||||
@app.route('/<corpus_name>/addusertoinstitution', methods=['POST'])
|
@app.route('/<corpus_name>/addusertoinstitution', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def add_user_institution_mapping(corpus_name):
|
def add_user_institution_mapping(corpus_name):
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""Added is_removed column to users and institutions.
|
||||||
|
|
||||||
|
Revision ID: 84168f439c55
|
||||||
|
Revises: c60b7bfaaf85
|
||||||
|
Create Date: 2021-09-06 10:55:40.303790
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '84168f439c55'
|
||||||
|
down_revision = 'c60b7bfaaf85'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('institution', sa.Column('is_removed', sa.Boolean(), server_default='true', nullable=False))
|
||||||
|
op.add_column('registered_user', sa.Column('is_removed', sa.Boolean(), server_default='true', nullable=False))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('registered_user', 'is_removed')
|
||||||
|
op.drop_column('institution', 'is_removed')
|
||||||
|
# ### end Alembic commands ###
|
151
portal/base.py
151
portal/base.py
|
@ -68,7 +68,7 @@ class ContractCreator:
|
||||||
|
|
||||||
class UploadHandler:
|
class UploadHandler:
|
||||||
|
|
||||||
ENABLED_FILETYPES = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'xml', 'mxliff', 'tmx']
|
ENABLED_FILETYPES = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'xml', 'mxliff', 'tmx', 'jpg', 'jpeg', 'png']
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.config = kwargs
|
self.config = kwargs
|
||||||
|
@ -210,7 +210,7 @@ class UploadHandler:
|
||||||
for key, f in files.items():
|
for key, f in files.items():
|
||||||
if key.startswith('file'):
|
if key.startswith('file'):
|
||||||
suffix = f.filename.split('.')[-1]
|
suffix = f.filename.split('.')[-1]
|
||||||
if self.ENABLED_FILETYPES and suffix not in self.ENABLED_FILETYPES:
|
if self.ENABLED_FILETYPES and suffix.lower() not in self.ENABLED_FILETYPES:
|
||||||
return 'Datoteka "{}" ni pravilnega formata.'.format(f.filename)
|
return 'Datoteka "{}" ni pravilnega formata.'.format(f.filename)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -263,10 +263,10 @@ def get_institution_cooperation_history(institution_id):
|
||||||
if row.user not in res:
|
if row.user not in res:
|
||||||
res[row.user] = {
|
res[row.user] = {
|
||||||
'coordinator': [],
|
'coordinator': [],
|
||||||
'moderator': [],
|
'mentor': [],
|
||||||
'other': []
|
'other': []
|
||||||
}
|
}
|
||||||
res[row.user][row.role].append(row.school_year)
|
res[row.user][row.role].append((row.school_year, row.badge_text))
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@ -275,6 +275,22 @@ def get_cooperation_history():
|
||||||
return UserCooperationHistory.query.all()
|
return UserCooperationHistory.query.all()
|
||||||
|
|
||||||
|
|
||||||
|
def add_cooperation_history_item(user_id, institution_id, role, school_year, badge_text):
|
||||||
|
model_obj = UserCooperationHistory(
|
||||||
|
user=user_id,
|
||||||
|
institution=institution_id,
|
||||||
|
role=role,
|
||||||
|
school_year=school_year,
|
||||||
|
badge_text=badge_text
|
||||||
|
)
|
||||||
|
db.session.add(model_obj)
|
||||||
|
db.session.commit()
|
||||||
|
return model_obj.id
|
||||||
|
|
||||||
|
def del_cooperation_history_item(entry_id):
|
||||||
|
db.session.query(UserCooperationHistory).filter_by(id=entry_id).delete()
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
def has_user_corpus_access(user_id, corpus_name):
|
def has_user_corpus_access(user_id, corpus_name):
|
||||||
user = RegisteredUser.query.filter_by(id=user_id).first()
|
user = RegisteredUser.query.filter_by(id=user_id).first()
|
||||||
|
|
||||||
|
@ -303,6 +319,8 @@ def is_admin(user_id):
|
||||||
def get_user_obj(user_id):
|
def get_user_obj(user_id):
|
||||||
return RegisteredUser.query.filter_by(id=user_id).first()
|
return RegisteredUser.query.filter_by(id=user_id).first()
|
||||||
|
|
||||||
|
def get_user_obj_by_email(email):
|
||||||
|
return RegisteredUser.query.filter_by(email=email).first()
|
||||||
|
|
||||||
def get_institution_obj(institution_id):
|
def get_institution_obj(institution_id):
|
||||||
return Institution.query.filter_by(id=institution_id).first()
|
return Institution.query.filter_by(id=institution_id).first()
|
||||||
|
@ -370,10 +388,38 @@ def update_user_password(user_id, new_password):
|
||||||
return rowcount
|
return rowcount
|
||||||
|
|
||||||
|
|
||||||
def del_user(user_id):
|
def update_user_role(user_id, role):
|
||||||
db.session.query(UserCooperationHistory).filter(UserCooperationHistory.user == user_id).delete()
|
rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'role': role})
|
||||||
db.session.query(UserInstitutionMapping).filter(UserInstitutionMapping.user == user_id).delete()
|
db.session.commit()
|
||||||
db.session.query(RegisteredUser).filter(RegisteredUser.id == user_id).delete()
|
return rowcount
|
||||||
|
|
||||||
|
|
||||||
|
def update_user_email(user_id, new_email):
|
||||||
|
rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'email': new_email})
|
||||||
|
db.session.commit()
|
||||||
|
return rowcount
|
||||||
|
|
||||||
|
|
||||||
|
def update_user_name(user_id, new_name):
|
||||||
|
rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'name': new_name})
|
||||||
|
db.session.commit()
|
||||||
|
return rowcount
|
||||||
|
|
||||||
|
|
||||||
|
def remove_user(user_id):
|
||||||
|
#db.session.query(UserCooperationHistory).filter(UserCooperationHistory.user == user_id).delete()
|
||||||
|
#db.session.query(UserInstitutionMapping).filter(UserInstitutionMapping.user == user_id).delete()
|
||||||
|
#db.session.query(RegisteredUser).filter(RegisteredUser.id == user_id).delete()
|
||||||
|
#db.session.commit()
|
||||||
|
db.session.query(RegisteredUser).filter(RegisteredUser.id == user_id).update({'is_removed': True})
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
def undo_remove_user(user_id):
|
||||||
|
db.session.query(RegisteredUser).filter(RegisteredUser.id == user_id).update({'is_removed': False})
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
def remove_institution(institution_id):
|
||||||
|
db.session.query(Institution).filter(Institution.id == institution_id).update({'is_removed': True})
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@ -383,22 +429,22 @@ def del_user_from_institution(user_id, institution_id):
|
||||||
|
|
||||||
|
|
||||||
def get_all_active_users():
|
def get_all_active_users():
|
||||||
return RegisteredUser.query.filter_by(active=True).order_by(RegisteredUser.id).all()
|
return RegisteredUser.query.filter_by(is_removed=False).filter_by(active=True).order_by(RegisteredUser.id).all()
|
||||||
|
|
||||||
|
|
||||||
def get_all_inactive_users():
|
def get_all_inactive_users():
|
||||||
return RegisteredUser.query.filter_by(active=False).order_by(RegisteredUser.id).all()
|
return RegisteredUser.query.filter_by(is_removed=False).filter_by(active=False).order_by(RegisteredUser.id).all()
|
||||||
|
|
||||||
|
|
||||||
def get_all_users_join_institutions(active=True):
|
def get_all_users_join_institutions(active=True):
|
||||||
#return RegisteredUser.query.filter_by(active=True).order_by(RegisteredUser.id).all()
|
#return RegisteredUser.query.filter_by(active=True).order_by(RegisteredUser.id).all()
|
||||||
return db.session.query(RegisteredUser, UserInstitutionMapping).outerjoin(UserInstitutionMapping,
|
return db.session.query(RegisteredUser, UserInstitutionMapping).filter(RegisteredUser.is_removed==False).outerjoin(UserInstitutionMapping,
|
||||||
RegisteredUser.id == UserInstitutionMapping.user).filter(RegisteredUser.active == active).order_by(RegisteredUser.id).all()
|
RegisteredUser.id == UserInstitutionMapping.user).filter(RegisteredUser.active == active).order_by(RegisteredUser.id).all()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_active_institution_users(institution_id):
|
def get_all_active_institution_users(institution_id):
|
||||||
return RegisteredUser.query.filter_by(active=True).join(UserInstitutionMapping,
|
return RegisteredUser.query.filter_by(is_removed=False).filter_by(active=True).join(UserInstitutionMapping,
|
||||||
RegisteredUser.id == UserInstitutionMapping.user).filter(UserInstitutionMapping.institution == institution_id).all()
|
RegisteredUser.id == UserInstitutionMapping.user).filter(UserInstitutionMapping.institution == institution_id).all()
|
||||||
|
|
||||||
|
|
||||||
|
@ -437,6 +483,28 @@ def get_password_reset_token(email, key, expires=600):
|
||||||
'exp': int(time.time()) + expires},
|
'exp': int(time.time()) + expires},
|
||||||
key=key, algorithm='HS256')
|
key=key, algorithm='HS256')
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_users_institution(institution_id_from, institution_id_to):
|
||||||
|
rowcount = db.session.query(UserInstitutionMapping).filter_by(institution=institution_id_from).update(
|
||||||
|
{'institution': institution_id_to})
|
||||||
|
db.session.commit()
|
||||||
|
return rowcount
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_uploads_institution(institution_id_from, institution_id_to):
|
||||||
|
rowcount = db.session.query(UploadSolar).filter_by(institution=institution_id_from).update(
|
||||||
|
{'institution': institution_id_to})
|
||||||
|
db.session.commit()
|
||||||
|
return rowcount
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_contracts_institution(institution_id_from, institution_id_to):
|
||||||
|
rowcount = db.session.query(ContractsSolar).filter_by(institution=institution_id_from).update(
|
||||||
|
{'institution': institution_id_to})
|
||||||
|
db.session.commit()
|
||||||
|
return rowcount
|
||||||
|
|
||||||
|
|
||||||
def verify_reset_token(token, key):
|
def verify_reset_token(token, key):
|
||||||
try:
|
try:
|
||||||
message = jwt.decode(token,
|
message = jwt.decode(token,
|
||||||
|
@ -455,11 +523,18 @@ def verify_reset_token(token, key):
|
||||||
def send_resetpass_mail(email, config):
|
def send_resetpass_mail(email, config):
|
||||||
jwt_token = get_password_reset_token(email, config['APP_SECRET_KEY'])
|
jwt_token = get_password_reset_token(email, config['APP_SECRET_KEY'])
|
||||||
|
|
||||||
text = '''
|
body = '''
|
||||||
Zahtevali ste ponastavitev gesla vašega uporabniškega računa.
|
Zahtevali ste ponastavitev gesla vašega uporabniškega računa.
|
||||||
|
|
||||||
Geslo lahko ponastavite na naslednji povezavi: https://zbiranje.slovenscina.eu/solar/resetpass/{}'''.format(jwt_token)
|
Geslo lahko ponastavite na naslednji povezavi: https://zbiranje.slovenscina.eu/solar/resetpass/{}'''.format(jwt_token)
|
||||||
|
|
||||||
|
message = MIMEMultipart()
|
||||||
|
message['From'] = config['MAIL_LOGIN']
|
||||||
|
message['To'] = email
|
||||||
|
message['Subject'] = 'Ponastavitev gesla'
|
||||||
|
message.attach(MIMEText(body, "plain"))
|
||||||
|
text = message.as_string()
|
||||||
|
|
||||||
# Create a secure SSL context
|
# Create a secure SSL context
|
||||||
context = ssl.create_default_context()
|
context = ssl.create_default_context()
|
||||||
|
|
||||||
|
@ -469,3 +544,53 @@ def send_resetpass_mail(email, config):
|
||||||
server.sendmail(config['MAIL_LOGIN'], email, text)
|
server.sendmail(config['MAIL_LOGIN'], email, text)
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def send_admins_new_user_notification_mail(user_id, config):
|
||||||
|
user = RegisteredUser.query.filter_by(id=user_id).first()
|
||||||
|
body = '''
|
||||||
|
Nov uporabnik "{}" je ustvaril uporabniški račun na portalu za oddajanje besedil Šolar in čaka na odobritev.
|
||||||
|
'''.format(user.name)
|
||||||
|
|
||||||
|
message = MIMEMultipart()
|
||||||
|
message['From'] = config['MAIL_LOGIN']
|
||||||
|
message['To'] = email
|
||||||
|
message['Subject'] = 'Ponastavitev gesla'
|
||||||
|
message.attach(MIMEText(body, "plain"))
|
||||||
|
text = message.as_string()
|
||||||
|
|
||||||
|
admins = RegisteredUser.query.filter_by(role="admin").all()
|
||||||
|
|
||||||
|
# Create a secure SSL context
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
|
||||||
|
for admin in admins:
|
||||||
|
try:
|
||||||
|
with SMTP_SSL(config['MAIL_HOST'], config['SMTP_PORT'], context=context) as server:
|
||||||
|
server.login(config['MAIL_LOGIN'], config['MAIL_PASS'])
|
||||||
|
server.sendmail(config['MAIL_LOGIN'], admin.email, text)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def send_user_activation_mail(user_id, config):
|
||||||
|
user = RegisteredUser.query.filter_by(id=user_id).first()
|
||||||
|
body = '''Vaš uporabniški račun "{}" na portalu Šolar je bil odobren.'''.format(user.name)
|
||||||
|
|
||||||
|
message = MIMEMultipart()
|
||||||
|
message['From'] = config['MAIL_LOGIN']
|
||||||
|
message['To'] = email
|
||||||
|
message['Subject'] = 'Ponastavitev gesla'
|
||||||
|
message.attach(MIMEText(body, "plain"))
|
||||||
|
text = message.as_string()
|
||||||
|
|
||||||
|
# Create a secure SSL context
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with SMTP_SSL(config['MAIL_HOST'], config['SMTP_PORT'], context=context) as server:
|
||||||
|
server.login(config['MAIL_LOGIN'], config['MAIL_PASS'])
|
||||||
|
server.sendmail(config['MAIL_LOGIN'], user.email, text)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ class RegisteredUser(UserMixin, db.Model):
|
||||||
active = db.Column(db.Boolean, nullable=True)
|
active = db.Column(db.Boolean, nullable=True)
|
||||||
last_login = db.Column(db.DateTime, nullable=True)
|
last_login = db.Column(db.DateTime, nullable=True)
|
||||||
registered = db.Column(db.DateTime, nullable=True)
|
registered = db.Column(db.DateTime, nullable=True)
|
||||||
|
is_removed = db.Column(db.Boolean, nullable=False, default=False, server_default="false")
|
||||||
|
|
||||||
|
|
||||||
class UserInstitutionMapping(db.Model):
|
class UserInstitutionMapping(db.Model):
|
||||||
|
@ -104,6 +105,7 @@ class Institution(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
name = db.Column(db.String, nullable=False, unique=True)
|
name = db.Column(db.String, nullable=False, unique=True)
|
||||||
region = db.Column(db.String, nullable=False)
|
region = db.Column(db.String, nullable=False)
|
||||||
|
is_removed = db.Column(db.Boolean, nullable=False, default=False, server_default="false")
|
||||||
|
|
||||||
|
|
||||||
class CorpusAccess(db.Model):
|
class CorpusAccess(db.Model):
|
||||||
|
|
102
portal/solar.py
102
portal/solar.py
|
@ -79,62 +79,58 @@ class UploadHandlerSolar(UploadHandler):
|
||||||
if contract_type not in ['sola', 'ucenci-starsi']:
|
if contract_type not in ['sola', 'ucenci-starsi']:
|
||||||
return 'Neveljaven tip pogodbe.'
|
return 'Neveljaven tip pogodbe.'
|
||||||
|
|
||||||
f_obj = None
|
#for key, f in request.files.items():
|
||||||
for key, f in request.files.items():
|
for f in request.files.getlist("file[]"):
|
||||||
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')
|
mimetype = f.content_type
|
||||||
f_hash = hashlib.md5(f_obj.read()).hexdigest()
|
if mimetype != 'application/pdf':
|
||||||
f_obj.seek(0, 0)
|
return 'Datoteka "{}" ni formata PDF.'.format(f.filename)
|
||||||
|
|
||||||
|
if not f:
|
||||||
|
return 'Niste naložili nobene datoteke.'
|
||||||
|
|
||||||
# First byte used for indexing, similarly like git does for example.
|
base = self.get_uploads_subdir('contracts')
|
||||||
sub_dir = base / f_hash[:2]
|
f_hash = hashlib.md5(f.read()).hexdigest()
|
||||||
if not sub_dir.exists():
|
f.seek(0, 0)
|
||||||
sub_dir.mkdir()
|
|
||||||
|
|
||||||
path = sub_dir / (f_hash[2:] + '.pdf')
|
# First byte used for indexing, similarly like git does for example.
|
||||||
f_obj.save(path)
|
sub_dir = base / f_hash[:2]
|
||||||
|
if not sub_dir.exists():
|
||||||
|
sub_dir.mkdir()
|
||||||
|
|
||||||
timestamp = datetime.now()
|
path = sub_dir / (f_hash[2:] + '.pdf')
|
||||||
user_obj = RegisteredUser.query.filter_by(id=user_id).one()
|
f.save(path)
|
||||||
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_coordinator = True if user_institution_mapping.role == 'coordinator' else False
|
|
||||||
|
|
||||||
if contract_type == 'sola':
|
timestamp = datetime.now()
|
||||||
if not is_institution_coordinator:
|
user_institution_mapping = UserInstitutionMapping.query.filter_by(user=user_id).first()
|
||||||
return 'Vaš uporabnik nima pravic za nalaganje pogodbe s šolo.'
|
if user_institution_mapping is None:
|
||||||
# TODO: insert institution contract
|
return 'Vaš uporabnik ni dodeljen nobeni inštituciji.'
|
||||||
model_obj = InstitutionContract(
|
institution_id = user_institution_mapping.institution
|
||||||
institution=institution_id,
|
is_institution_coordinator = True if user_institution_mapping.role == 'coordinator' else False
|
||||||
corpus='solar',
|
|
||||||
timestamp=timestamp,
|
|
||||||
file_contract=f_hash,
|
|
||||||
original_filename=f_obj.filename
|
|
||||||
)
|
|
||||||
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,
|
|
||||||
original_filename=f_obj.filename
|
|
||||||
)
|
|
||||||
|
|
||||||
self.store_model(model_obj)
|
if contract_type == 'sola':
|
||||||
|
if not is_institution_coordinator:
|
||||||
|
return 'Vaš uporabnik nima pravic za nalaganje pogodbe s šolo.'
|
||||||
|
# TODO: insert institution contract
|
||||||
|
model_obj = InstitutionContract(
|
||||||
|
institution=institution_id,
|
||||||
|
corpus='solar',
|
||||||
|
timestamp=timestamp,
|
||||||
|
file_contract=f_hash,
|
||||||
|
original_filename=f.filename
|
||||||
|
)
|
||||||
|
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,
|
||||||
|
original_filename=f.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
self.store_model(model_obj)
|
||||||
return 'Nalaganje pogodbe je bilo uspešno.'
|
return 'Nalaganje pogodbe je bilo uspešno.'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -168,10 +164,14 @@ 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()
|
return UploadSolar.query.filter_by(upload_user=user_id).order_by(desc(UploadSolar.timestamp)).limit(n).all()
|
||||||
|
|
||||||
|
|
||||||
|
def get_institution_upload_history(institution_id, n=20):
|
||||||
|
return UploadSolar.query.filter_by(institution=institution_id).order_by(desc(UploadSolar.timestamp)).limit(n).all()
|
||||||
|
|
||||||
|
|
||||||
def get_all_institutions():
|
def get_all_institutions():
|
||||||
# TODO: do filtering purely within an SQL query
|
# TODO: do filtering purely within an SQL query
|
||||||
res = []
|
res = []
|
||||||
for institution in Institution.query.all():
|
for institution in Institution.query.filter_by(is_removed=False).all():
|
||||||
row = CorpusAccess.query.filter_by(institution=institution.id, corpus='solar').first()
|
row = CorpusAccess.query.filter_by(institution=institution.id, corpus='solar').first()
|
||||||
if row:
|
if row:
|
||||||
res.append(institution)
|
res.append(institution)
|
||||||
|
|
|
@ -197,10 +197,12 @@ label {
|
||||||
}
|
}
|
||||||
|
|
||||||
.collaborators-item {
|
.collaborators-item {
|
||||||
height: 30px;
|
height: fit-content;
|
||||||
|
width: 97%;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
border-bottom: 2px solid #c4c4c4;
|
border-bottom: 2px solid #c4c4c4;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.collaborators-item-name {
|
.collaborators-item-name {
|
||||||
|
@ -209,6 +211,17 @@ label {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #46535b;
|
color: #46535b;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collaborators-item-years {
|
||||||
|
font-family: Roboto;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 16px;
|
||||||
|
float: right;
|
||||||
|
width: 180px;
|
||||||
|
max-width: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#awards-container {
|
#awards-container {
|
||||||
|
|
|
@ -38,22 +38,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
<h2>Uporabniki</h2>
|
<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="password" 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>Aktivni uporabniki</h3>
|
<h3>Aktivni uporabniki</h3>
|
||||||
<div class="tableFixHead">
|
<div class="tableFixHead">
|
||||||
<table>
|
<table>
|
||||||
|
@ -62,6 +46,7 @@
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>Ime in priimek</th>
|
<th>Ime in priimek</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
|
<th>Vloga</th>
|
||||||
<th>ID institucije</th>
|
<th>ID institucije</th>
|
||||||
<th>Vloga v instituciji</th>
|
<th>Vloga v instituciji</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -72,11 +57,44 @@
|
||||||
<td>{{item[0].id}}</td>
|
<td>{{item[0].id}}</td>
|
||||||
<td>{{item[0].name}}</td>
|
<td>{{item[0].name}}</td>
|
||||||
<td>{{item[0].email}}</td>
|
<td>{{item[0].email}}</td>
|
||||||
|
<td>{{item[0].role}}</td>
|
||||||
<td>{{item[1].institution}}</td>
|
<td>{{item[1].institution}}</td>
|
||||||
<td>{{item[1].role}}</td>
|
<td>{{item[1].role}}</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<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="password" id="password" name="password"><br>
|
||||||
|
<input type="submit" value="Dodaj">
|
||||||
|
</form>
|
||||||
|
<h3>Spremeni email uporabnika</h3>
|
||||||
|
<form action="/solar/changeuseremail" method="post">
|
||||||
|
<label for="user-id">ID uporabnika:</label><br>
|
||||||
|
<input type="text" id="user-id" name="user-id"><br>
|
||||||
|
<label for="email">Nov email:</label><br>
|
||||||
|
<input type="text" id="email" name="email"><br>
|
||||||
|
<input type="submit" value="Spremeni">
|
||||||
|
</form>
|
||||||
|
<h3>Spremeni ime in priimek uporabnika</h3>
|
||||||
|
<form action="/solar/changeusername" method="post">
|
||||||
|
<label for="user-id">ID uporabnika:</label><br>
|
||||||
|
<input type="text" id="user-id" name="user-id"><br>
|
||||||
|
<label for="name">Ime in priimek:</label><br>
|
||||||
|
<input type="text" id="name" name="name"><br>
|
||||||
|
<input type="submit" value="Spremeni">
|
||||||
|
</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>Dodeli uporabnika instituciji</h3>
|
<h3>Dodeli uporabnika instituciji</h3>
|
||||||
<form action="/solar/addusertoinstitution" method="post">
|
<form action="/solar/addusertoinstitution" method="post">
|
||||||
<label for="user_id">ID uporabnika:</label>
|
<label for="user_id">ID uporabnika:</label>
|
||||||
|
@ -97,6 +115,47 @@
|
||||||
<input type="text" id="user_id" name="user_id"><br>
|
<input type="text" id="user_id" name="user_id"><br>
|
||||||
<input type="submit" value="Odstrani">
|
<input type="submit" value="Odstrani">
|
||||||
</form>
|
</form>
|
||||||
|
<h3>Spremeni vlogo uporabniškega računa</h3>
|
||||||
|
<form action="/solar/changeuserrole" method="post">
|
||||||
|
<label for="user-id">ID uporabnika:</label>
|
||||||
|
<input type="text" id="user-id" name="user-id"><br>
|
||||||
|
<label for="role">Vloga:</label>
|
||||||
|
<select name="role" id="role">
|
||||||
|
<option value="admin">Administrator/-ka</option>
|
||||||
|
<option value="user">Navaden uporabnik</option>
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="Spremeni">
|
||||||
|
</form>
|
||||||
|
<h3>Čakajoči uporabniki</h3>
|
||||||
|
<div class="tableFixHead">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Ime in priimek</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Institucija</th>
|
||||||
|
<th>Vloga v instituciji</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in inactive_users %}
|
||||||
|
<tr>
|
||||||
|
<td>{{item[0].id}}</td>
|
||||||
|
<td>{{item[0].name}}</td>
|
||||||
|
<td>{{item[0].email}}</td>
|
||||||
|
<td>{{item[1].institution}}</td>
|
||||||
|
<td>{{item[1].role}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<h3>Aktiviraj uporabnika</h3>
|
||||||
|
<form action="/solar/activateuser" method="post">
|
||||||
|
<label for="id">ID uporabnika:</label>
|
||||||
|
<input type="text" id="id" name="id"><br>
|
||||||
|
<input type="submit" value="Aktiviraj">
|
||||||
|
</form>
|
||||||
<div> </div>
|
<div> </div>
|
||||||
<h2>Institucije</h2>
|
<h2>Institucije</h2>
|
||||||
<h3>Dodaj institucijo</h3>
|
<h3>Dodaj institucijo</h3>
|
||||||
|
@ -139,35 +198,13 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<h3>Čakajoči uporabniki</h3>
|
<h3>Združi instituciji</h3>
|
||||||
<div class="tableFixHead">
|
<form action="/solar/mergeinstitutions" method="post">
|
||||||
<table>
|
<label for="id-from">Institucijo z ID</label>
|
||||||
<thead>
|
<input type="text" id="id-from" name="id-from">
|
||||||
<tr>
|
<label for="id-to">združi v institucijo z ID</label>
|
||||||
<th>ID</th>
|
<input type="text" id="id-to" name="id-to"><br>
|
||||||
<th>Ime in priimek</th>
|
<input type="submit" value="Združi">
|
||||||
<th>Email</th>
|
|
||||||
<th>Institucija</th>
|
|
||||||
<th>Vloga v instituciji</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for item in inactive_users %}
|
|
||||||
<tr>
|
|
||||||
<td>{{item[0].id}}</td>
|
|
||||||
<td>{{item[0].name}}</td>
|
|
||||||
<td>{{item[0].email}}</td>
|
|
||||||
<td>{{item[1].institution}}</td>
|
|
||||||
<td>{{item[1].role}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<h3>Aktiviraj uporabnika</h3>
|
|
||||||
<form action="/solar/activateuser" method="post">
|
|
||||||
<label for="id">ID uporabnika:</label>
|
|
||||||
<input type="text" id="id" name="id"><br>
|
|
||||||
<input type="submit" value="Aktiviraj">
|
|
||||||
</form>
|
</form>
|
||||||
<h2>Zgodovina sodelovanja</h2>
|
<h2>Zgodovina sodelovanja</h2>
|
||||||
<div class="tableFixHead">
|
<div class="tableFixHead">
|
||||||
|
@ -195,4 +232,28 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<h3>Dodaj vnos</h3>
|
||||||
|
<form action="/solar/addcooperationhistoryitem" method="post">
|
||||||
|
<label for="user">ID uporabnika</label>
|
||||||
|
<input type="text" id="user" name="user"><br>
|
||||||
|
<label for="institution">ID institucije</label>
|
||||||
|
<input type="text" id="institution" name="institution"><br>
|
||||||
|
<label for="role">Vloga</label>
|
||||||
|
<select name="role" id="role">
|
||||||
|
<option value="coordinator">Koordinator/-ka</option>
|
||||||
|
<option value="mentor">Mentor/-ica</option>
|
||||||
|
<option value="other">Druga vloga</option>
|
||||||
|
</select><br>
|
||||||
|
<label for="school-year">Šolsko leto (npr. "2021/22")</label>
|
||||||
|
<input type="text" id="school-year" name="school-year"><br>
|
||||||
|
<label for="badge-text">Besedilo značke</label>
|
||||||
|
<input type="text" id="badge-text" name="badge-text"><br>
|
||||||
|
<input type="submit" value="Dodaj">
|
||||||
|
</form>
|
||||||
|
<h3>Odstrani vnos</h3>
|
||||||
|
<form action="/solar/delcooperationhistoryitem" method="post">
|
||||||
|
<label for="entry-id">ID vnosa</label>
|
||||||
|
<input type="text" id="entry-id" name="entry-id"><br>
|
||||||
|
<input type="submit" value="Odstrani">
|
||||||
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -126,105 +126,6 @@
|
||||||
|
|
||||||
<div id="popup-terms" style="display: none">
|
<div id="popup-terms" style="display: none">
|
||||||
<div id="popup-terms-text">
|
<div id="popup-terms-text">
|
||||||
<h2>POGODBA O PRENOSU AVTORSKIH PRAVIC</h2>
|
|
||||||
|
|
||||||
<h3>UVODNE DOLOČBE</h3>
|
|
||||||
<h4><b>1. člen</b></h4>
|
|
||||||
|
|
||||||
<p>1.1. Stranki uvodoma ugotavljata, da naročnik izvaja projekt Razvoj slovenščine v digitalnem
|
|
||||||
okolju – RSDO (v nadaljevanju projekt RSDO), ki je bil na javnem razpisu Razvoj slovenščine v
|
|
||||||
digitalnem okolju – jezikovni viri in tehnologije (JR-ESRR-Razvoj slovenščine v digitalnem
|
|
||||||
okolju), objavljenem v Uradnem listu RS št. 70/19 dne 29. 11. 2019, sprejet v sofinanciranje
|
|
||||||
in katerega vsebina je razvidna s spletnih strani https://slovenscina.eu.</p>
|
|
||||||
|
|
||||||
<p>1.2. Stranki uvodoma ugotavljata, da bo naročnik v okviru projekta RSDO:
|
|
||||||
- izdelal osrednjo digitalno slovarsko bazo, ki združuje različne tipe jezikovnih podatkov o
|
|
||||||
slovenščini v odprtem dostopu,
|
|
||||||
- izdelal terminološki portal z integriranim iskalnikom po slovenskih terminoloških virih, zlasti
|
|
||||||
terminoloških slovarjih,
|
|
||||||
- izdelal korpus prevodov po različnih domenah za učenje strojnega prevajalnika za jezikovni
|
|
||||||
par angleščina-slovenščina in slovenščina-angleščina.</p>
|
|
||||||
<p>1.3. Stranki uvodoma ugotavljata, da bo naročnik pri projektu RSDO za vse zgoraj opisane
|
|
||||||
namene zbiral in uporabil besedilne vire, ki so navedeni v prilogi k tej pogodbi in ki so lahko
|
|
||||||
avtorska dela ali drugi predmeti varstva v skladu z Zakonom o avtorski in sorodnih pravicah
|
|
||||||
(Uradni list RS, št. 16/07 – uradno prečiščeno besedilo, 68/08, 110/13, 56/15, 63/16 – ZKUASP
|
|
||||||
in 59/19; ZASP) in na katerih ima imetnik pravic avtorske, avtorski sorodne ali druge pravice v
|
|
||||||
skladu z ZASP (v nadaljevanju avtorska dela).</p>
|
|
||||||
|
|
||||||
<p>1.4. Stranki ugotavljata, da bodo avtorska dela in vse njihove morebitne spremembe in
|
|
||||||
predelave, ter zbirke podatkov, ki bodo med izvajanjem projekta RSDO nastale, javno
|
|
||||||
dostopni pod pogoji prostih licenc (npr. CC BY-SA) in bodo na voljo za nekomercialen in
|
|
||||||
komercialen razvoj tehnologij, za raziskave in za druge raziskovalne namene
|
|
||||||
posameznikom, raziskovalnim in izobraževalnim institucijam, neprofitnim organizacijam,
|
|
||||||
državnim organom, organizacijam z javnimi pooblastili in gospodarskim družbam v Sloveniji
|
|
||||||
in tujini.</p>
|
|
||||||
|
|
||||||
<h3>PREDMET POGODBE</h3>
|
|
||||||
<h4><b>2. člen</b></h4>
|
|
||||||
|
|
||||||
<p>2.1. Predmet pogodbe so vsa avtorska dela imetnika pravic, ki so navedena v prilogi k tej
|
|
||||||
pogodbi.</p>
|
|
||||||
|
|
||||||
<p>2.2. S podpisom te pogodbe imetnik avtorskih pravic na naročnika prenaša avtorske pravice
|
|
||||||
na avtorskih delih na način in v obsegu, kakor je navedeno v 3. členu te pogodbe.</p>
|
|
||||||
|
|
||||||
<h3>PRENOS AVTORSKIH PRAVIC</h3>
|
|
||||||
<h4><b>3. člen</b></h4>
|
|
||||||
|
|
||||||
<p>3.1. S podpisom te pogodbe imetnik pravic na avtorskih delih, ki so predmet te pogodbe, na
|
|
||||||
naročnika neizključno, brez časovnih in teritorialnih omejitev prenaša vse materialne avtorske
|
|
||||||
pravice, avtorski sorodne pravice in druge pravice avtorja v skladu z ZASP, zlasti pravico
|
|
||||||
reproduciranja (23. člen ZASP), distribuiranja (24. člena ZASP), dajanja v najem (25. člen ZASP),
|
|
||||||
priobčitve javnosti (26. do 32.a člen ZASP), vključno s pravico dajanja na voljo javnosti (32.a
|
|
||||||
člen ZASP) in pravico predelave (33. člen ZASP).</p>
|
|
||||||
|
|
||||||
<p>3.2. S podpisom te pogodbe imetnik pravic izrecno soglaša, da naročnik pravice iz točke 3.1.
|
|
||||||
prenaša naprej na tretje osebe brez omejitev.</p>
|
|
||||||
|
|
||||||
<h3>JAMČEVANJE IMETNIKA PRAVIC</h3>
|
|
||||||
|
|
||||||
<h4><b>4. člen</b></h4>
|
|
||||||
|
|
||||||
<p>4.1. S podpisom te pogodbe imetnik pravic jamči, da je na avtorskih delih, ki so predmet te
|
|
||||||
pogodbe, imetnik vseh avtorskih pravic, avtorski sorodnih pravic in drugih pravic avtorja v
|
|
||||||
skladu z ZASP, ki so potrebne za prenos pravic po tej pogodbi, in da na avtorskih delih ne
|
|
||||||
obstajajo pravice tretjih oseb, ki bi naročniku preprečevale njihovo uporabo.</p>
|
|
||||||
|
|
||||||
<p>4.2. Določbe te pogodbe ne vplivajo na prenos moralnih avtorskih pravic, ki so v skladu z
|
|
||||||
določbami ZASP neprenosljive.</p>
|
|
||||||
|
|
||||||
<h3>OSEBNI PODATKI</h3>
|
|
||||||
<h4><b>5. člen</b></h4>
|
|
||||||
|
|
||||||
<p>6.1. Stranki se zavezujeta, da bosta vse morebitne osebne podatke, ki jih bosta obdelovali za
|
|
||||||
namene izvajanja te pogodbe, obdelovali na način, da bosta upoštevali vse veljavne predpise
|
|
||||||
o varstvu osebnih podatkov in da bosta posameznikom, na katere se osebni podatki nanašajo,
|
|
||||||
zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatkov.<p>
|
|
||||||
|
|
||||||
<h3>KONTAKTNE OSEBE</h3>
|
|
||||||
<h4><b>6. člen</b></h4>
|
|
||||||
|
|
||||||
<p>7.1 Kontaktna oseba za izvedbo te pogodbe na strani naročnika je [xxx].</p>
|
|
||||||
<p>7.2. Kontaktna oseba za izvedbo te pogodbe na strani imetnika pravic je [xxx].</p>
|
|
||||||
|
|
||||||
<h3>KONČNE DOLOČBE</h3>
|
|
||||||
<h4><b>7. člen</b></h4>
|
|
||||||
|
|
||||||
<p>8.1. Če je katerakoli določba te pogodbe nična, ostanejo druga določila te pogodbe v veljavi.</p>
|
|
||||||
|
|
||||||
<h4><b>8. člen</b></h4>
|
|
||||||
|
|
||||||
<p>9.1. Za razmerja v zvezi s to pogodbo se uporabljajo pravni predpisi Republike Slovenije.</p>
|
|
||||||
<p>9.2. Spore iz te pogodbe bosta stranki reševali po mirni poti. V primeru, da mirna rešitev ne
|
|
||||||
bo mogoča, je za vse spore v zvezi s to pogodbo pristojno sodišče v Ljubljani.</p>
|
|
||||||
|
|
||||||
<h4><b>9. člen</b></h4>
|
|
||||||
|
|
||||||
<p>10.1. Ta pogodba nadomešča vsa predhodna pogajanja, ponudbe in druge dogovore med
|
|
||||||
strankama.</p>
|
|
||||||
<p>10.2. Ta pogodba je sestavljena v [dveh] istovetnih izvodih, od katerih prejme vsaka stranka
|
|
||||||
po enega.</p>
|
|
||||||
<p>10.3. Pogodbeni stranki s podpisom potrjujeta veljavnost te pogodbe.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<button id="button-submit-cancel" class="button-terms" style="background: #ff2d2d;">Prekliči</button>
|
<button id="button-submit-cancel" class="button-terms" style="background: #ff2d2d;">Prekliči</button>
|
||||||
<button id="button-submit-final" class="button-terms">Oddaj</button>
|
<button id="button-submit-final" class="button-terms">Oddaj</button>
|
||||||
|
@ -249,6 +150,10 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
||||||
var scrollboxTriggered = false;
|
var scrollboxTriggered = false;
|
||||||
var form = document.forms["my-dropzone"];
|
var form = document.forms["my-dropzone"];
|
||||||
|
|
||||||
|
{% if not institution %}
|
||||||
|
btnSubmit.disabled = true;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
function isEmptyOrSpaces(str){
|
function isEmptyOrSpaces(str){
|
||||||
return str == null || str.match(/^ *$/) !== null;
|
return str == null || str.match(/^ *$/) !== null;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +168,7 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
||||||
paramName: "file", // The name that will be used to transfer the file
|
paramName: "file", // The name that will be used to transfer the file
|
||||||
maxFilesize: 1000, // MB
|
maxFilesize: 1000, // MB
|
||||||
timeout: 5000000, // milliseconds
|
timeout: 5000000, // milliseconds
|
||||||
acceptedFiles: ".txt, .csv, .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx",
|
acceptedFiles: ".txt, .csv, .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .jpg, .jpeg, .png",
|
||||||
maxFiles: 20,
|
maxFiles: 20,
|
||||||
dictDefaultMessage: `Kliknite ali odložite datoteke sem.`,
|
dictDefaultMessage: `Kliknite ali odložite datoteke sem.`,
|
||||||
dictFallbackMessage: "Vaš brskalnik ne podpira izbiranje datotek z odlaganjem (\"drag & drop\").",
|
dictFallbackMessage: "Vaš brskalnik ne podpira izbiranje datotek z odlaganjem (\"drag & drop\").",
|
||||||
|
@ -322,10 +227,18 @@ zagotovili vse potrebne informacije v skladu s predpisi o varstvu osebnih podatk
|
||||||
btnSubmit.textContent = "Potrdi";
|
btnSubmit.textContent = "Potrdi";
|
||||||
} else {
|
} else {
|
||||||
// Then make terms popup visible
|
// Then make terms popup visible
|
||||||
btnSubmit.disabled = true;
|
//btnSubmit.disabled = true;
|
||||||
btnSubmitFinal.disabled = true;
|
//btnSubmitFinal.disabled = true;
|
||||||
elemTermsPopup.style.display = "inline";
|
//elemTermsPopup.style.display = "inline";
|
||||||
scrollboxtriggered = false;
|
//scrollboxtriggered = false;
|
||||||
|
|
||||||
|
// Hand off data to dropzone
|
||||||
|
dz.processQueue();
|
||||||
|
|
||||||
|
// Clear fields and hide popup agian
|
||||||
|
dataConfirmNotification.style.display = "none";
|
||||||
|
btnSubmit.textContent = "Oddaj";
|
||||||
|
form.reset();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,17 @@
|
||||||
<button onclick="window.location.replace('/solar/pogodbe');" class="selection-tab-button selected">POGODBE</button>
|
<button onclick="window.location.replace('/solar/pogodbe');" class="selection-tab-button selected">POGODBE</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% with messages = get_flashed_messages() %}
|
||||||
|
{% if messages %}
|
||||||
|
<div class="message-notification">
|
||||||
|
{{ messages[0] }}
|
||||||
|
</div>
|
||||||
|
<div id="contract-container" style="height: 250px;">
|
||||||
|
{% else %}
|
||||||
<div id="contract-container">
|
<div id="contract-container">
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
{% if contract_school %}
|
{% if contract_school %}
|
||||||
<div class="contract-item">
|
<div class="contract-item">
|
||||||
<img src="/static/image/contract.png" alt="contract" class="contract-item-icon"/>
|
<img src="/static/image/contract.png" alt="contract" class="contract-item-icon"/>
|
||||||
|
@ -71,7 +81,7 @@
|
||||||
<label style="width: 80%; text-align: right;" for="ucenci-starsi">Pogodba z učenci / starši</label>
|
<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>
|
<input style="width: 20%;" type="radio" id="ucenci-starsi" name="tip-pogodbe" value="ucenci-starsi" checked>
|
||||||
</div>
|
</div>
|
||||||
<input style="font-size: 10px;" type="file" id="file-contract" name="filename">
|
<input style="font-size: 10px;" type="file" id="file-contract" name="file[]" multiple="">
|
||||||
<button style="float: right;" type="submit">Oddaj pogodbo</button>
|
<button style="float: right;" type="submit">Oddaj pogodbo</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -84,11 +94,26 @@
|
||||||
{% for collaborator in collaborators %}
|
{% for collaborator in collaborators %}
|
||||||
<div class="collaborators-item">
|
<div class="collaborators-item">
|
||||||
<div class="collaborators-item-name">{{collaborator.name}}</div>
|
<div class="collaborators-item-name">{{collaborator.name}}</div>
|
||||||
{% for history_item in cooperation_history %}
|
{% if collaborator.id in cooperation_history %}
|
||||||
{% if collaborator.id == history_item.user %}
|
{% if cooperation_history[collaborator.id]["coordinator"]|length > 0 %}
|
||||||
<div>{{history_item.badge_text}}</div>
|
<div class="collaborators-item-years"><b>Vodenje:</b> {% for item in cooperation_history[collaborator.id]["coordinator"] %}
|
||||||
{% endif %}
|
{% if loop.index != 1 %}, {% endif %}
|
||||||
{% endfor %}
|
{{item[0]}}
|
||||||
|
{% endfor %}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if cooperation_history[collaborator.id]["mentor"]|length > 0 %}
|
||||||
|
<div class="collaborators-item-years"><b>Mentorstvo:</b> {% for item in cooperation_history[collaborator.id]["mentor"] %}
|
||||||
|
{% if loop.index != 1 %}, {% endif %}
|
||||||
|
{{item[0]}}
|
||||||
|
{% endfor %}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if cooperation_history[collaborator.id]["other"]|length > 0 %}
|
||||||
|
<div class="collaborators-item-years"><b>Drugo:</b> {% for item in cooperation_history[collaborator.id]["other"] %}
|
||||||
|
{% if loop.index != 1 %}, {% endif %}
|
||||||
|
{{item[0]}}
|
||||||
|
{% endfor %}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,13 +121,49 @@
|
||||||
<div id="awards-container">
|
<div id="awards-container">
|
||||||
<div class="container-title">Sodelovanje v letih</div>
|
<div class="container-title">Sodelovanje v letih</div>
|
||||||
<div style="overflow-y: auto; margin: auto; width: 100%; height: 200px;">
|
<div style="overflow-y: auto; margin: auto; width: 100%; height: 200px;">
|
||||||
{% for item in cooperation_history %}
|
{% if cooperation_history.keys()|length > 0 %}
|
||||||
<div style="border-bottom: 2px solid #c4c4c4; min-height: 50px;">
|
{% if user_id in cooperation_history %}
|
||||||
<img src="/static/image/star.png" alt="star" style="float: left; width: 40px;"/>
|
{% for item in cooperation_history[user_id]['coordinator'] %}
|
||||||
<div class="collaborators-item-name"
|
<div style="border-bottom: 2px solid #c4c4c4; min-height: 50px; margin-bottom: 10px;">
|
||||||
style="float: right; width: 250px; margin-bottom: 20px; margin-top: 10px; text-align: left; margin-left: 20px;">{{item.badge_text}}</div>
|
<img src="/static/image/star.png" alt="star" style="float: left; width: 40px;"/>
|
||||||
</div>
|
<div class="collaborators-item-name"
|
||||||
{% endfor %}
|
style="float: right; width: 250px; text-align: left; margin-left: 20px;text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">
|
||||||
|
{{item[1]}}
|
||||||
|
</div>
|
||||||
|
<div class="collaborators-item-name"
|
||||||
|
style="float: right; width: 250px; text-align: left; margin-left: 20px;">
|
||||||
|
{{item[0]}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% for item in cooperation_history[user_id]['mentor'] %}
|
||||||
|
<div style="border-bottom: 2px solid #c4c4c4; min-height: 50px; margin-bottom: 10px;">
|
||||||
|
<img src="/static/image/star.png" alt="star" style="float: left; width: 40px;"/>
|
||||||
|
<div class="collaborators-item-name"
|
||||||
|
style="float: right; width: 250px; text-align: left; margin-left: 20px;text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">
|
||||||
|
{{item[1]}}
|
||||||
|
</div>
|
||||||
|
<div class="collaborators-item-name"
|
||||||
|
style="float: right; width: 250px; text-align: left; margin-left: 20px;">
|
||||||
|
{{item[0]}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% for item in cooperation_history[user_id]['other'] %}
|
||||||
|
<div style="border-bottom: 2px solid #c4c4c4; min-height: 50px; margin-bottom: 10px;">
|
||||||
|
<img src="/static/image/star.png" alt="star" style="float: left; width: 40px;"/>
|
||||||
|
<div class="collaborators-item-name"
|
||||||
|
style="float: right; width: 250px; text-align: left; margin-left: 20px;text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">
|
||||||
|
{{item[1]}}
|
||||||
|
</div>
|
||||||
|
<div class="collaborators-item-name"
|
||||||
|
style="float: right; width: 250px; text-align: left; margin-left: 20px;">
|
||||||
|
{{item[0]}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user