From 788f3bc3eb797024fd80c750f113532e5ea47c41 Mon Sep 17 00:00:00 2001 From: msinkec Date: Thu, 2 Sep 2021 14:40:54 +0200 Subject: [PATCH] model changes, user institution history, style changes, forgot passowrd functionality, etc. --- Dockerfile | 2 +- app.py | 136 +++++++++++------- ...132220432f_added_usercooperationhistory.py | 37 +++++ ...dded_school_year_column_to_user_history.py | 28 ++++ ...661_dropped_out_predavanje_stuff_added_.py | 58 ++++++++ portal/base.py | 90 ++++++++++-- portal/model.py | 53 ++++--- portal/solar.py | 9 +- static/image/contract.png | Bin 0 -> 1315 bytes static/image/password.png | Bin 0 -> 1124 bytes static/image/register.png | Bin 0 -> 2252 bytes static/image/showpass.png | Bin 0 -> 1778 bytes static/image/star.png | Bin 0 -> 1966 bytes static/image/user.png | Bin 0 -> 1182 bytes static/style.css | 55 ++++++- templates/basic.html | 2 +- templates/solar-admin.html | 78 ++++++++-- templates/solar-forgotpass.html | 3 +- templates/solar-login.html | 36 +++-- templates/solar-manage-institution.html | 16 ++- templates/solar-oddaja.html | 19 ++- templates/solar-pogodbe.html | 41 ++++-- templates/solar-register.html | 20 ++- templates/solar-resetpass.html | 19 +-- templates/solar-zgodovina.html | 23 +-- 25 files changed, 550 insertions(+), 175 deletions(-) create mode 100644 migrations/versions/4c132220432f_added_usercooperationhistory.py create mode 100644 migrations/versions/c60b7bfaaf85_added_school_year_column_to_user_history.py create mode 100644 migrations/versions/ff356b1ef661_dropped_out_predavanje_stuff_added_.py create mode 100644 static/image/contract.png create mode 100644 static/image/password.png create mode 100644 static/image/register.png create mode 100644 static/image/showpass.png create mode 100644 static/image/star.png create mode 100644 static/image/user.png diff --git a/Dockerfile b/Dockerfile index a171a94..6198724 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,6 @@ WORKDIR /usr/src/portal-webapp RUN apt-get update && apt-get -y install wkhtmltopdf && \ rm -rf /var/lib/apt/lists/* -RUN pip3 install --no-cache-dir pdfkit flask==1.1.4 flask-dropzone flask-log-request-id flask-login Flask-SQLAlchemy alembic flask-migrate==2.7.0 Flask-script psycopg2 gunicorn pdfkit Werkzeug==1.0.1, PyJWT +RUN pip3 install --no-cache-dir pdfkit flask==1.1.4 flask-dropzone flask-log-request-id flask-login Flask-SQLAlchemy alembic flask-migrate==2.7.0 Flask-script psycopg2 gunicorn pdfkit Werkzeug==1.0.1 PyJWT ENTRYPOINT ["./entrypoint.sh"] diff --git a/app.py b/app.py index b0a2b6e..bd48562 100644 --- a/app.py +++ b/app.py @@ -123,7 +123,8 @@ upload_handler_regular = portal.regular.UploadHandlerRegular( MAIL_SUBJECT=MAIL_SUBJECT, MAIL_BODY=MAIL_BODY, CONTRACT_CLIENT_CONTACT=CONTRACT_CLIENT_CONTACT, - MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD + MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD, + APP_SECRET_KEY=APP_SECRET_KEY ) upload_handler_solar = portal.solar.UploadHandlerSolar( @@ -136,7 +137,8 @@ upload_handler_solar = portal.solar.UploadHandlerSolar( MAIL_SUBJECT=MAIL_SUBJECT, MAIL_BODY=MAIL_BODY, CONTRACT_CLIENT_CONTACT=CONTRACT_CLIENT_CONTACT, - MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD + MAX_FILES_PER_UPLOAD=MAX_FILES_PER_UPLOAD, + APP_SECRET_KEY=APP_SECRET_KEY ) @@ -217,6 +219,9 @@ def solar_register_post(): name = request.form.get('name') email = request.form.get('email') password = request.form.get('password') + institution_name = request.form.get('institution') + institution_role = request.form.get('role') + institution = portal.base.get_institution_obj_by_name(institution_name) user = RegisteredUser.query.filter_by(email=email).first() @@ -248,7 +253,17 @@ def solar_register_post(): flash('Predolgo geslo.') return redirect('/solar/register') - portal.base.register_new_user(name, email, password, active=False) + if not institution: + flash('Institucija ne obstaja.') + return redirect('/solar/register') + + if institution_role not in ['coordinator', 'mentor', 'other']: + flash('Neveljavna vloga v instituciji.') + return redirect('/solar/register') + + + user_id = portal.base.register_new_user(name, email, password, active=False) + portal.base.add_user_to_institution(user_id, institution.id, institution_role) flash('Uspešna registracija.') return redirect('/solar/login') @@ -270,13 +285,20 @@ def logout(): def solar(text): is_admin = current_user.role == 'admin' current_user_institution = portal.base.get_user_institution(current_user.id) + current_user_obj = portal.base.get_user_obj(current_user.get_id()) + institution_contract = None if current_user_institution: - current_user_institution_moderator = portal.base.is_institution_moderator(current_user.id, current_user_institution.id) + current_user_institution_coordinator = portal.base.is_institution_coordinator(current_user.id, current_user_institution.id) + institution_contract = portal.base.get_institution_contract(current_user_institution.id) else: - current_user_institution_moderator = False + current_user_institution_coordinator = False if text.startswith('oddaja/') or text == 'oddaja': - return render_template('solar-oddaja.html', is_admin=is_admin, is_institution_moderator=current_user_institution_moderator) + return render_template('solar-oddaja.html', + is_admin=is_admin, + institution=current_user_institution, + institution_contract=institution_contract, + is_institution_coordinator=current_user_institution_coordinator) elif text.startswith('zgodovina/') or text == 'zgodovina': upload_items = portal.solar.get_upload_history(current_user.id) uploader_names = [] @@ -289,58 +311,66 @@ def solar(text): else: institution_names.append(institution.name) return render_template('solar-zgodovina.html', upload_history=upload_items, uploader_names=uploader_names, - institution_names=institution_names, is_admin=is_admin, is_institution_moderator=current_user_institution_moderator) - elif text.startswith('pogodbe/') or text == 'pogodbe': + institution_names=institution_names, is_admin=is_admin, is_institution_coordinator=current_user_institution_coordinator) + elif text.startswith('pogodbe-institucije/') or text.startswith('pogodbe-ucencistarsi/'): # Check for ownload contract request. - match = re.match('^pogodbe/([a-z0-9_]+\.pdf)$', text) + match = re.match('^pogodbe-(institucije|ucencistarsi)/([a-z0-9_]+\.pdf)$', text) if match: - filename = match.group(1) + contract_type = match.group(1) + filename = match.group(2) if len(filename) < 10: return '', 404 prefix = filename[:2] suffix = filename[2:] + f_hash = filename.split('.')[0] + + if contract_type == 'institucije': + actual_filename = portal.base.get_actual_institution_contract_filename(f_hash) + else: + actual_filename = portal.base.get_actual_studentparent_contract_filename(f_hash) safe_path = safe_join(str(upload_handler_solar.get_uploads_subdir('contracts')), prefix, suffix) try: - return send_file(safe_path, as_attachment=True) + return send_file(safe_path, attachment_filename=actual_filename, as_attachment=True) except FileNotFoundError: return '', 404 - - user_obj = portal.base.get_user_obj(current_user.get_id()) - institution = portal.base.get_user_institution(user_obj.id) + elif text.startswith('pogodbe/') or text == 'pogodbe': contracts_students = [] contract_school = [] enable_upload_school_contract = False show_upload_form = False collaborators = [] - if institution: - collaborators = portal.base.get_all_active_institution_users(institution.id) + cooperation_history = dict() + if current_user_institution: + collaborators = portal.base.get_all_active_institution_users(current_user_institution.id) show_upload_form = True - contract_school = portal.solar.get_institution_contract(institution.id) - if portal.base.is_institution_moderator(user_obj.id, institution.id): - contracts_students = portal.solar.get_institution_student_contracts(institution.id) + contract_school = portal.solar.get_institution_contract(current_user_institution.id) + cooperation_history = portal.base.get_institution_cooperation_history(current_user_institution.id) + if portal.base.is_institution_coordinator(current_user_obj.id, current_user_institution.id): + contracts_students = portal.solar.get_institution_student_contracts(current_user_institution.id) enable_upload_school_contract = True else: - contracts_students = portal.solar.get_institution_student_contracts(institution.id, user_obj.id) + contracts_students = portal.solar.get_institution_student_contracts(current_user_institution.id, current_user_obj.id) return render_template('solar-pogodbe.html', contracts_students=contracts_students, contract_school=contract_school, enable_upload_school_contract=enable_upload_school_contract, show_upload_form=show_upload_form, collaborators=collaborators, - is_admin=is_admin, is_institution_moderator=current_user_institution_moderator) + cooperation_history=cooperation_history, + is_admin=is_admin, is_institution_coordinator=current_user_institution_coordinator) elif text.startswith('admin/') or text == 'admin': - users = portal.base.get_all_active_users_join_institutions() - inactive_users = portal.base.get_all_inactive_users() + users = portal.base.get_all_users_join_institutions() + inactive_users = portal.base.get_all_users_join_institutions(active=False) solar_institutions = portal.solar.get_all_institutions() + cooperation_history = portal.base.get_cooperation_history() if is_admin: - return render_template('solar-admin.html', users=users, + return render_template('solar-admin.html', users=users, user_cooperation_history=cooperation_history, institutions=solar_institutions, inactive_users=inactive_users) elif text.startswith('manage-institution/') or text == 'manage-institution': - institution = portal.base.get_user_institution(current_user.id) - if portal.base.is_institution_moderator(current_user.id, institution.id): + if portal.base.is_institution_coordinator(current_user.id, current_user_institution.id): solar_users = portal.base.get_all_active_users() - institution_users = portal.base.get_all_active_institution_users(institution.id) + institution_users = portal.base.get_all_active_institution_users(current_user_institution.id) return render_template('solar-manage-institution.html', users=solar_users, institution_users=institution_users) return '', 404 @@ -420,7 +450,7 @@ def solar_forgotpass(): def solar_sendresetpass(): email = request.form.get('email') - portal.base.send_resetpass_mail(email, upload_handler_regular.config) + portal.base.send_resetpass_mail(email, upload_handler_solar.config) flash('Povezava za ponastavitev gesla je bila poslana na vpisan email naslov.') return redirect(redirect_url()) @@ -428,7 +458,7 @@ def solar_sendresetpass(): @app.route('/solar/resetpass/') def solar_resetpass(token): - user = portal.base.verify_reset_token(token) + user = portal.base.verify_reset_token(token, upload_handler_solar.config['APP_SECRET_KEY']) if not user: return '', 404 @@ -439,7 +469,7 @@ def solar_resetpass(token): @app.route('/solar/resetpass/', methods=['POST']) def solar_resetpass_post(token): new_password = request.form.get('new_password') - user = portal.base.verify_reset_token(token) + user = portal.base.verify_reset_token(token, upload_handler_solar.config['APP_SECRET_KEY']) if not user: return '', 404 @@ -448,7 +478,8 @@ def solar_resetpass_post(token): if rowcount == 0: return '', 404 - return 'Ponastavitev gesla uspešna.' + flash('Ponastavitev gesla je bila uspešna.') + return redirect('/solar/login') @app.route('/solar/topuploads') @@ -460,9 +491,12 @@ def solar_topuploads_srednje(): @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 + if not portal.base.is_admin(current_user.id): + return '', 404 + user_id = request.form.get('user_id') + portal.base.del_user(user_id) + flash('Uporabnik je bil odstranjen.') + return redirect(redirect_url()) @app.route('//addinstitution', methods=['POST']) @login_required @@ -482,11 +516,8 @@ def add_institution(corpus_name): flash('Predolgo ime.') return redirect(redirect_url()) - if not region: - flash('Prazno polje za regijo.') - return redirect(redirect_url()) - if len(region) > 100: - flash('Predolgi niz za regijo.') + if not region in portal.solar.VALID_REGIONS: + flash('Neveljavna vrednost za regijo.') return redirect(redirect_url()) institution_id = portal.base.add_institution(name, region) @@ -506,37 +537,34 @@ def add_user_institution_mapping(corpus_name): if institution: institution_id = institution.id - if not (portal.base.is_admin(current_user.id) or portal.base.is_institution_moderator(current_user.id, institution_id)): + if not (portal.base.is_admin(current_user.id) or portal.base.is_institution_coordinator(current_user.id, institution_id)): return '', 404 user_id = request.form['user_id'] role = request.form['role'] - if role not in ['moderator', 'user']: + if role not in ['coordinator', 'mentor', 'other']: return '', 404 if portal.base.get_user_institution(user_id): - flash('Uporabnik je že dodeljen instituciji. Dodeljevanje večim institucijam '\ - 'zaenkrat ni implementirano.') + flash('Uporabnik je že dodeljen instituciji.') return redirect(redirect_url()) portal.base.add_user_to_institution(user_id, institution_id, role) flash('Uporabnik je bil dodeljen instituciji.') return redirect(redirect_url()) -@app.route('//deluserfrominstitution', methods=['POST']) +@app.route('/solar/deluserfrominstitution', methods=['POST']) @login_required -def del_user_institution_mapping(corpus_name): - institution = portal.base.get_user_institution(current_user.id) - if not portal.base.is_admin(current_user.id) \ - and not portal.base.is_institution_moderator(current_user.id, institution.id): - return '', 404 - if not corpus_name in ENABLED_CORPUSES: - return '', 404 - +def del_user_institution_mapping(): user_id = request.form['user_id'] + institution = portal.base.get_user_institution(user_id) + if not institution: + flash('Uporabnik ni član nobene institucije.') + return redirect(redirect_url()) - if not portal.base.is_institution_member(user_id, institution.id): - flash('Uporabnik ni član vaše institucije.') + if not portal.base.is_admin(current_user.id) \ + and not portal.base.is_institution_coordinator(current_user.id, institution.id): + flash('Nimate ustreznih pravic za odstranitev uporabnika iz institucije.') return redirect(redirect_url()) portal.base.del_user_from_institution(user_id, institution.id) diff --git a/migrations/versions/4c132220432f_added_usercooperationhistory.py b/migrations/versions/4c132220432f_added_usercooperationhistory.py new file mode 100644 index 0000000..892a877 --- /dev/null +++ b/migrations/versions/4c132220432f_added_usercooperationhistory.py @@ -0,0 +1,37 @@ +"""Added UserCooperationHistory. + +Revision ID: 4c132220432f +Revises: ff356b1ef661 +Create Date: 2021-09-01 09:25:43.144096 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4c132220432f' +down_revision = 'ff356b1ef661' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('user_cooperation', + 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.Column('badge_text', sa.String(), nullable=True), + sa.ForeignKeyConstraint(['institution'], ['institution.id'], ), + sa.ForeignKeyConstraint(['user'], ['registered_user.id'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('user_cooperation') + # ### end Alembic commands ### diff --git a/migrations/versions/c60b7bfaaf85_added_school_year_column_to_user_history.py b/migrations/versions/c60b7bfaaf85_added_school_year_column_to_user_history.py new file mode 100644 index 0000000..2d1d29a --- /dev/null +++ b/migrations/versions/c60b7bfaaf85_added_school_year_column_to_user_history.py @@ -0,0 +1,28 @@ +"""Added school year column to user history. + +Revision ID: c60b7bfaaf85 +Revises: 4c132220432f +Create Date: 2021-09-02 08:36:41.711040 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'c60b7bfaaf85' +down_revision = '4c132220432f' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('user_cooperation', sa.Column('school_year', sa.String(), nullable=False)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('user_cooperation', 'school_year') + # ### end Alembic commands ### diff --git a/migrations/versions/ff356b1ef661_dropped_out_predavanje_stuff_added_.py b/migrations/versions/ff356b1ef661_dropped_out_predavanje_stuff_added_.py new file mode 100644 index 0000000..b679a08 --- /dev/null +++ b/migrations/versions/ff356b1ef661_dropped_out_predavanje_stuff_added_.py @@ -0,0 +1,58 @@ +"""Dropped out predavanje stuff, added contract initial file name. + +Revision ID: ff356b1ef661 +Revises: 5ba116fc7f06 +Create Date: 2021-08-26 12:45:56.036966 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'ff356b1ef661' +down_revision = '5ba116fc7f06' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('stamps_solar') + op.drop_table('upload_predavanja') + op.add_column('contracts_solar', sa.Column('original_filename', sa.String(), nullable=True)) + op.add_column('institution_contract', sa.Column('original_filename', sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('institution_contract', 'original_filename') + op.drop_column('contracts_solar', 'original_filename') + op.create_table('upload_predavanja', + sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column('upload_hash', sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column('timestamp', postgresql.TIMESTAMP(), autoincrement=False, nullable=False), + sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column('address', sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column('subject', sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column('faculty', sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column('email', sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column('phone', sa.VARCHAR(), autoincrement=False, nullable=True), + sa.Column('keywords', sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column('file_contract', sa.VARCHAR(), autoincrement=False, nullable=True), + sa.Column('upload_file_hashes', postgresql.ARRAY(sa.VARCHAR()), autoincrement=False, nullable=True), + sa.Column('agree_publish_future', sa.TEXT(), autoincrement=False, nullable=False), + sa.Column('agree_machine_translation', sa.BOOLEAN(), autoincrement=False, nullable=False), + sa.Column('agree_news_cjvt', sa.BOOLEAN(), autoincrement=False, nullable=False), + sa.PrimaryKeyConstraint('id', name='upload_predavanja_pkey') + ) + op.create_table('stamps_solar', + sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column('institution', sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column('name', sa.TEXT(), autoincrement=False, nullable=False), + sa.Column('file_logo', sa.TEXT(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint(['institution'], ['institution.id'], name='stamps_institution_fkey'), + sa.PrimaryKeyConstraint('id', name='stamps_pkey') + ) + # ### end Alembic commands ### diff --git a/portal/base.py b/portal/base.py index 8ef5de7..384dd59 100644 --- a/portal/base.py +++ b/portal/base.py @@ -25,7 +25,7 @@ import jwt from werkzeug.security import generate_password_hash -from . model import db, UploadRegular, UploadSolar, RegisteredUser, UserInstitutionMapping, Institution, InstitutionContract, CorpusAccess +from . model import * #REGEX_EMAIL = re.compile('^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$') @@ -248,6 +248,33 @@ def get_user_institution(user_id): return None +def get_institution_contract(institution_id): + return InstitutionContract.query.filter_by(institution=institution_id).first() + + +def get_institution_cooperation_history(institution_id): + #return CooperationToken.query.join(UserCooperationTokenMapping, +# UserCooperationTokenMapping.cooperation_token == CooperationToken.id).filter(UserCooperationTokenMapping.user == user_id).all() +# + res = dict() + + uch_rows = UserCooperationHistory.query.filter_by(institution=institution_id).order_by(UserCooperationHistory.school_year.desc()).all() + for row in uch_rows: + if row.user not in res: + res[row.user] = { + 'coordinator': [], + 'moderator': [], + 'other': [] + } + res[row.user][row.role].append(row.school_year) + + return res + + +def get_cooperation_history(): + return UserCooperationHistory.query.all() + + def has_user_corpus_access(user_id, corpus_name): user = RegisteredUser.query.filter_by(id=user_id).first() @@ -281,6 +308,10 @@ def get_institution_obj(institution_id): return Institution.query.filter_by(id=institution_id).first() +def get_institution_obj_by_name(institution_name): + return Institution.query.filter_by(name=institution_name).first() + + def register_new_user(name, email, password, active=True, admin=False): model_obj = RegisteredUser( name=name, @@ -334,11 +365,18 @@ def activate_user(user_id): def update_user_password(user_id, new_password): phash = generate_password_hash(new_password) - rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'pass_hash': pass_hash}) + rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'pass_hash': phash}) db.session.commit() return rowcount +def del_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() + + def del_user_from_institution(user_id, institution_id): db.session.query(UserInstitutionMapping).filter(UserInstitutionMapping.institution == institution_id).filter(UserInstitutionMapping.user == user_id).delete() db.session.commit() @@ -347,24 +385,28 @@ def del_user_from_institution(user_id, institution_id): def get_all_active_users(): return RegisteredUser.query.filter_by(active=True).order_by(RegisteredUser.id).all() + def get_all_inactive_users(): return RegisteredUser.query.filter_by(active=False).order_by(RegisteredUser.id).all() -def get_all_active_users_join_institutions(): + +def get_all_users_join_institutions(active=True): #return RegisteredUser.query.filter_by(active=True).order_by(RegisteredUser.id).all() return db.session.query(RegisteredUser, UserInstitutionMapping).outerjoin(UserInstitutionMapping, - RegisteredUser.id == UserInstitutionMapping.user).order_by(RegisteredUser.id).all() + RegisteredUser.id == UserInstitutionMapping.user).filter(RegisteredUser.active == active).order_by(RegisteredUser.id).all() + + def get_all_active_institution_users(institution_id): return RegisteredUser.query.filter_by(active=True).join(UserInstitutionMapping, RegisteredUser.id == UserInstitutionMapping.user).filter(UserInstitutionMapping.institution == institution_id).all() -def is_institution_moderator(user_id, institution_id): +def is_institution_coordinator(user_id, institution_id): user_inst_mapping = UserInstitutionMapping.query.filter_by(user=user_id).filter_by(institution=institution_id).first() if not user_inst_mapping: return False - if user_inst_mapping.role != 'moderator': + if user_inst_mapping.role != 'coordinator': return False return True @@ -376,15 +418,34 @@ def is_institution_member(user_id, institution_id): return True -def get_password_reset_token(email, expires=500): +def get_actual_institution_contract_filename(f_hash): + contract = InstitutionContract.query.filter_by(file_contract=f_hash).first() + if contract: + return contract.original_filename + return None + + +def get_actual_studentparent_contract_filename(f_hash): + contract = ContractsSolar.query.filter_by(file_contract=f_hash).first() + if contract: + return contract.original_filename + return None + + +def get_password_reset_token(email, key, expires=600): return jwt.encode({'reset_password': email, - 'exp': time() + expires}, - key=os.getenv('APP_SECRET_KEY'), algorithm='HS256') + 'exp': int(time.time()) + expires}, + key=key, algorithm='HS256') -def verify_reset_token(token): +def verify_reset_token(token, key): try: - email = jwt.decode(token, - key=os.getenv('APP_SECRET_KEY'), algorithms=["HS256"])['reset_password'] + message = jwt.decode(token, + key=key, algorithms=["HS256"]) + email = message['reset_password'] + exp = message['exp'] + if int(time.time()) >= exp: + # Token timed out + return None except Exception as e: logging.error(e) return @@ -392,13 +453,12 @@ def verify_reset_token(token): def send_resetpass_mail(email, config): - jwt_token = get_password_reset_token(email) + jwt_token = get_password_reset_token(email, config['APP_SECRET_KEY']) text = ''' Zahtevali ste ponastavitev gesla vašega uporabniškega računa. - Geslo lahko ponastavite na naslednji povezavi: https://zbiranje.slovenscina.eu/solar/resetpass/{}'''.format( - 'https://zbiranje.slovenscina.eu/solar/resetpass/{}'.format(jwt_token)) + Geslo lahko ponastavite na naslednji povezavi: https://zbiranje.slovenscina.eu/solar/resetpass/{}'''.format(jwt_token) # Create a secure SSL context context = ssl.create_default_context() diff --git a/portal/model.py b/portal/model.py index 0cae17d..30f7a11 100644 --- a/portal/model.py +++ b/portal/model.py @@ -28,25 +28,6 @@ class UploadRegular(db.Model): corpus_name = db.Column(db.String, nullable=False) -class UploadPredavanja(db.Model): - __tablename__ = 'upload_predavanja' - id = db.Column(db.Integer, primary_key=True) - upload_hash = db.Column(db.String, nullable=False) - timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) - name = db.Column(db.String, nullable=False) - address = db.Column(db.String, nullable=False) - subject = db.Column(db.String, nullable=False) - faculty = db.Column(db.String, nullable=False) - email = db.Column(db.String, nullable=False) - phone = db.Column(db.String, nullable=True) - keywords = db.Column(db.String, nullable=False) - agree_publish_future = db.Column(db.String, nullable=False) - agree_machine_translation = db.Column(db.Boolean, default=False, nullable=False) - agree_news_cjvt = db.Column(db.Boolean, default=False, nullable=False) - file_contract = db.Column(db.String, nullable=True) - upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String), nullable=True) - - class UploadSolar(db.Model): __tablename__ = 'upload_solar' id = db.Column(db.Integer, primary_key=True) @@ -65,14 +46,6 @@ class UploadSolar(db.Model): upload_file_hashes = db.Column(sqlalchemy.types.ARRAY(db.String), nullable=True) -class StampsSolar(db.Model): - __tablename__ = 'stamps_solar' - id = db.Column(db.Integer, primary_key=True) - institution = db.Column(db.Integer, sqlalchemy.ForeignKey('institution.id'), nullable=True) - name = db.Column(db.String, nullable=False) - file_logo = db.Column(db.String, nullable=True) - - class ContractsSolar(db.Model): __tablename__ = 'contracts_solar' id = db.Column(db.Integer, primary_key=True) @@ -80,6 +53,7 @@ class ContractsSolar(db.Model): upload_user = db.Column(db.Integer, sqlalchemy.ForeignKey('registered_user.id'), nullable=True) timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) file_contract = db.Column(db.String, nullable=False) + original_filename = db.Column(db.String, nullable=True) contract_type = db.Column(db.String, nullable=False) @@ -100,7 +74,29 @@ class UserInstitutionMapping(db.Model): 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) + role = db.Column(db.String, nullable=False) + + +#class CooperationToken(db.Model): +# __tablename__ = 'cooperation_token' +# id = db.Column(db.Integer, primary_key=True) +# name = db.Column(db.String, nullable=False) +# +# +#class UserCooperationTokenMapping(db.Model): +# __tablename__ = 'user_cooperation_token_mapping' +# id = db.Column(db.Integer, primary_key=True) +# user = db.Column(db.Integer, sqlalchemy.ForeignKey('registered_user.id'), nullable=False) +# cooperation_token = db.Column(db.Integer, sqlalchemy.ForeignKey('cooperation_token.id'), nullable=False) + +class UserCooperationHistory(db.Model): + __tablename__ = 'user_cooperation' + 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) + school_year = db.Column(db.String, nullable=False) + badge_text = db.Column(db.String, nullable=True) class Institution(db.Model): @@ -124,4 +120,5 @@ class InstitutionContract(db.Model): 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) + original_filename = db.Column(db.String, nullable=True) diff --git a/portal/solar.py b/portal/solar.py index 18afa54..5e92d07 100644 --- a/portal/solar.py +++ b/portal/solar.py @@ -13,6 +13,7 @@ VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'} VALID_SUBJECTS = {'slo', 'drug-jez', 'drug-druz', 'drug-narav', 'drug-strok', 'drug-izb'} VALID_TEXT_TYPES = {'esej-spis', 'prakticno', 'solski-test', 'delo-v-razredu'} VALID_GRAMMAR_CORRECTIONS = {'popr-ne', 'brez-popr', 'popr-da'} +VALID_REGIONS = {'CE', 'GO', 'KK', 'KP', 'KR', 'LJ', 'MB', 'MS', 'NM', 'PO', 'SG'} MAXLEN_FORM = 150 @@ -109,17 +110,18 @@ class UploadHandlerSolar(UploadHandler): 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 + is_institution_coordinator = True if user_institution_mapping.role == 'coordinator' else False if contract_type == 'sola': - if not is_institution_moderator: + 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 + file_contract=f_hash, + original_filename=f_obj.filename ) self.store_model(model_obj) else: @@ -129,6 +131,7 @@ class UploadHandlerSolar(UploadHandler): timestamp=timestamp, file_contract=f_hash, contract_type=contract_type, + original_filename=f_obj.filename ) self.store_model(model_obj) diff --git a/static/image/contract.png b/static/image/contract.png new file mode 100644 index 0000000000000000000000000000000000000000..4f33bbb1b74b04d22c7880090a9775ef3172e5ff GIT binary patch literal 1315 zcmV+;1>E|HP)EX>4Tx04R}tkv&MmKpe$iTct%R4(%Z7kfFM0K~%(1t5Adrp;l;o12rOib`7 zkz)Z>sE`~#_#gc4)+|g;xJlsz(EVcDAHzU!7iiXP`}^3on)G7y~0{WT*fD02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00R3-L_t(|+U=WPOH*MS$3M^6)D4$ON*hk?C@xS?v>OR3 zI^7k7?v?ZsbnjsAM7#2GML|dx8x1m2bcuy&vnkp(J=@cTI+mD9oo$ah&+qDR&e+c9 z^L)?qZydpyT1dQkED=+J^0bt~q!~((l8DqHo>ki4wxX7mGXPr4`?GF=KWX*xHdja&KZ|Zr#RpI?UU#0Z{Ha52$Y5j%@_#gQ6(&y`)09D`{B0wehx(iSZzODjP zgs+=`p@DuS;p-;A-{z|vs|4SWPEaLyC6>cif$s>kb8mFGCYvLM>hJ(}dcy>}yBHd9 zUO?SG-RzSW`ApL0>6-)mwpaoomYHjhT zEx@+zsxiCA@wvi{K%ml>DA@^q|B=P)I|d(#3^EcKtVwHaZttj>fSuef%QYU#vOjlg zGF&<~46dxLv$dV2ClsW`>+CbTliTI%=9c>NfW7?#_EuK)D4+#s0a}0-pap0FT7VXC zEd&T;#>M<8Lki~IN-w2M870I^w+c8kN-^WP_3#x!#@z;A7BU{Stc(Frq!a^Eu8BUR zj*gj+M}eqi<%+_#+>nH_knz*^hN0^1@zYvJBuvVl87ag#P4iBn%pjRZF#qhyqu13} ZegpiGl=h*h&}{$!002ovPDHLkV1h1iZczXL literal 0 HcmV?d00001 diff --git a/static/image/password.png b/static/image/password.png new file mode 100644 index 0000000000000000000000000000000000000000..3c52c25d2d6178f9c3ef7420c5ca6b2b784ecd27 GIT binary patch literal 1124 zcmV-q1e^PbP)EX>4Tx04R}tkv&MmKpe$iTct%R4(%Z7kfFM0K~%(1t5Adrp;l;o12rOib`7 zkz)Z>sE`~#_#gc4)+|g;xJlsz(EVcDAHzU!7iiXP`}^3on)G6$}P>2Xp`c02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00KNoL_t(&-tC!BZrVT;hrcmiu=EjpgyaN;O;p-N(-YL) zRU%QQCjg(IAQ6;Z(i4zu;_Si=aBsj7SVpSxWC2M2M@)<{Ry1#E;oqO=n&&0O{ET+ybqgKCifAiCYGUvA6i{lOzzc zoyD)V&B0VNx{va>8MyHJKyObCE~8Gr`V4fRl*M-Yam2!0~SDw*Cs znGnTmUd%vQk);+upV8;x+u)B9Vf5nfss({KE%KWvmVqU`l=#qS=ZXio{xTpm+H2s= z`xYj*)s&F*Y!pu7X`k_#zw;X7GanVYiKi{(#5z1cAigDz#Q9D;pOp!i#@B9MRZv3e zJhl7955fCX77h;}PU1Y_zry-W^^nM>T}1}sbvpj)7X}z4P90GRK)pf(XaEiHVI5i2 zT@|=s$_eG8#DMG0-}eDX&t}PUk&ERp9L!nL&gxc;E!}2)#BVOR2G3c|UK-%ib800% z3X#$5ndx+iD^SrF?`XXIX7GJcso>S1pbz{=G<$AN38{Fq_8+%$@tZ!$Y|6ZDHUAhb zafb7Lh<5JA>5EJQXaEhM0W^RH&;T0XLjx2Td6()53II&wexUh>U-=7_FMeXJ4NcUR z`T34)1<;B(G6xff3$I#$Aj{mVL4F3z=5WiOamSxbWQ literal 0 HcmV?d00001 diff --git a/static/image/register.png b/static/image/register.png new file mode 100644 index 0000000000000000000000000000000000000000..29538b1be7c8e2624f93c0438fc5d8dac514633f GIT binary patch literal 2252 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 AB>(^b literal 0 HcmV?d00001 diff --git a/static/image/user.png b/static/image/user.png new file mode 100644 index 0000000000000000000000000000000000000000..7d81b47c50903669c9342a35da34bea20348daab GIT binary patch literal 1182 zcmV;P1Y!G$P)EX>4Tx04R}tkv&MmKpe$iTct%R4(%Z7kfFM0K~%(1t5Adrp;l;o12rOib`7 zkz)Z>sE`~#_#gc4)+|g;xJlsz(EVcDAHzU!7iiXP`}^3on)G6eqLZ&vgI*02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00MSNL_t(&-tC!9ZrV^3g}-Nzn$B1P-2q)e$*fKXkQJ29 zst6Qk1tBYlqtL3ezzSfJIJ1x)u!DLD%&Mxvw*v!>?bLtI#i`;m1TOEM$Nf1zK!pk~ z8>-N6v!)FmUVj9yjZ!UyrvHX402fg+zL=BeNuYnz1>*{&5&Jp81%^ctF$zlF1~pAg z-oLUYiZOj>_&f;oogt{>9FeCCZqLglFmQUnY3PcVzz`*EMy6t9Dm?EkigC1@#PUn8 ztR5IR-~Tk~y1rNJ^UZXhZgQu|in~AzvZVg=4ff%3x4*!^=>-#k*yI6h)1}7#`d8ZA z;d*lIx`aeJq3JS?P5v*iNlA!OC4J?LW|FH%V^?xh>^u-C%Kj_r-{%DHSuis z1nRFQk$GO@E|$b*k%h&bhOpDy#QmGDFXAGKbBuTw+sWkjN88s-A;Bl~$|C?UxIIV2 z${9UmWS*6)Mlau=0NJIn5?eRJ_Z*7woolFc_VQYN3?_tCG3OukVv zf&9LYE>ihMDuwfK72Tv_qh!wI!F?gA9$mMn8OITs?bp;{+}2Jakj?keMGoJ{DAf1S z#ov6RUwfVGJ&@P;DS|}UH&W8g(ZpK5k1kUCM#ew!eRPq*H+sRoP(`33kVN3oEEe3| wrTelefon: -
*Po kliku na gumb “Oddaj” se bo prikazala vsebina pogodobe o odstopu avtorskih pravic. Če se z vsebino strinjate, kliknite gumb “Pošlji”, da podatke posredujete v korpus, po e-pošti pa boste prejeli svoj izvod pogodbe.
+
*Po kliku na gumb “Oddaj” se bo prikazala vsebina pogodbe o odstopu avtorskih pravic. Če se z vsebino strinjate, kliknite gumb “Pošlji”, da podatke posredujete v korpus, po e-pošti pa boste prejeli svoj izvod pogodbe.
diff --git a/templates/solar-admin.html b/templates/solar-admin.html index 737d9f2..e5185da 100644 --- a/templates/solar-admin.html +++ b/templates/solar-admin.html @@ -5,8 +5,8 @@ Admin panel - Šolar @@ -45,13 +48,13 @@
- -

Seznam vseh aktivnih uporabnikov

+ +

Aktivni uporabniki

@@ -60,6 +63,7 @@ + @@ -69,6 +73,7 @@ + {% endfor %}
Ime in priimek Email ID institucijeVloga v instituciji
{{item[0].name}} {{item[0].email}} {{item[1].institution}}{{item[1].role}}
@@ -80,11 +85,18 @@
+

Odstrani uporabnika iz institucije

+
+ +
+ +

Institucije

Dodaj institucijo

@@ -92,7 +104,19 @@
-
+

Seznam vseh instituticij

@@ -115,7 +139,7 @@ {% endfor %} -

Seznam uporabnikov, ki niso aktivirani

+

Čakajoči uporabniki

@@ -123,14 +147,18 @@ + + {% for item in inactive_users %} - - - + + + + + {% endfor %}
ID Ime in priimek EmailInstitucijaVloga v instituciji
{{item.id}}{{item.name}}{{item.email}}{{item[0].id}}{{item[0].name}}{{item[0].email}}{{item[1].institution}}{{item[1].role}}
@@ -141,4 +169,30 @@
+

Zgodovina sodelovanja

+
+ + + + + + + + + + + + + {% for item in user_cooperation_history %} + + + + + + + + + {% endfor %} +
IDID uporabnikaID institucijeVlogaŠolsko letoBesedilo značke
{{item.id}}{{item.user}}{{item.institution}}{{item.role}}{{item.school_year}}{{item.badge_text}}
+
diff --git a/templates/solar-forgotpass.html b/templates/solar-forgotpass.html index bf0eb4e..c9c4222 100644 --- a/templates/solar-forgotpass.html +++ b/templates/solar-forgotpass.html @@ -28,9 +28,8 @@
- + - Registracija diff --git a/templates/solar-login.html b/templates/solar-login.html index 37a38ae..8419109 100644 --- a/templates/solar-login.html +++ b/templates/solar-login.html @@ -8,11 +8,17 @@
-
+
logo
-

Prijava - ŠOLAR

+

Portal za oddajanje besedil

+

Korpus Šolar

+ +
Zbiranje besedil za korpus Šolar poteka po naslednjem postopku, ki prinaša tudi točke za napredovanje.
+ +

Prijava

+
{% with messages = get_flashed_messages() %} {% if messages %} @@ -24,22 +30,32 @@
- + user +
- + user +
-
- - -
- +
- Registracija + Pozabljeno geslo + user + Registracija
Še nimate uporabniškega računa? Registrirajte se!
diff --git a/templates/solar-manage-institution.html b/templates/solar-manage-institution.html index a8f2f9e..3adfc32 100644 --- a/templates/solar-manage-institution.html +++ b/templates/solar-manage-institution.html @@ -5,8 +5,8 @@ Upravljanje institucije - Šolar {% with messages = get_flashed_messages() %} {% if messages %} -
+
{{ messages[0] }}
{% endif %} @@ -76,14 +79,15 @@

-

Dodeli uporabnika instituciji

+

Dodaj uporabnika instituciji


diff --git a/templates/solar-oddaja.html b/templates/solar-oddaja.html index d330a76..a507840 100644 --- a/templates/solar-oddaja.html +++ b/templates/solar-oddaja.html @@ -19,12 +19,13 @@ Odjavi se - {% if is_institution_moderator %} + {% if is_institution_coordinator %}
Upravljaj z institucijo {% endif %} {% if is_admin %}
Administracijski meni {% endif %} +
Pomoč
@@ -41,6 +42,13 @@
+ {% if not institution %} +
Niste član nobene institucije!
+ {% elif not institution_contract %} +
Pogodba s šolo še ni naložena!
+ {% endif %} + +
+ +
+
+ +
+
+ + +
diff --git a/templates/solar-resetpass.html b/templates/solar-resetpass.html index 37a38ae..45f2256 100644 --- a/templates/solar-resetpass.html +++ b/templates/solar-resetpass.html @@ -12,7 +12,7 @@
logo
-

Prijava - ŠOLAR

+

Ponastavitev gesla - ŠOLAR

{% with messages = get_flashed_messages() %} {% if messages %} @@ -21,25 +21,14 @@
{% endif %} {% endwith %} -
+
- +
- -
-
- -
-
-
- - -
- +
- Registracija diff --git a/templates/solar-zgodovina.html b/templates/solar-zgodovina.html index e8a5771..73f6da4 100644 --- a/templates/solar-zgodovina.html +++ b/templates/solar-zgodovina.html @@ -8,12 +8,13 @@ Odjavi se - {% if is_institution_moderator %} + {% if is_institution_coordinator %}
Upravljaj z institucijo {% endif %} {% if is_admin %}
Administracijski meni {% endif %} +
Pomoč
@@ -35,43 +36,45 @@
{{ uploader_names[loop.index - 1] }}
Št. datotek: {{ item.upload_file_hashes|length }}
+ [ {% set began = False %} {% if institution_names[loop.index - 1] %} - {% if began %}|{% endif %} {{ institution_names[loop.index - 1] }} + {% if began %}, {% endif %} {{ institution_names[loop.index - 1] }} {% set began = True %} {% endif %} {% if item.program %} - {% if began %}|{% endif %} {{ item.program }} + {% if began %}, {% endif %} {{ item.program }} {% set began = True %} {% endif %} {% if item.subject %} - {% if began %}|{% endif %} {{ item.subject }} + {% if began %}, {% endif %} {{ item.subject }} {% set began = True %} {% endif %} {% if item.subject_custom %} - {% if began %}|{% endif %} {{ item.subject_custom }} + {% if began %}, {% endif %} {{ item.subject_custom }} {% set began = True %} {% endif %} {% if item.grade %} - {% if began %}|{% endif %} {{ item.grade }} + {% if began %}, {% endif %} {{ item.grade }} {% set began = True %} {% endif %} {% if item.text_type %} - {% if began %}|{% endif %} {{ item.text_type }} + {% if began %}, {% endif %} {{ item.text_type }} {% set began = True %} {% endif %} {% if item.text_type_custom %} - {% if began %}|{% endif %} {{ item.text_type_custom }} + {% if began %}, {% endif %} {{ item.text_type_custom }} {% set began = True %} {% endif %} {% if item.school_year %} - {% if began %}|{% endif %} {{ item.school_year }} + {% if began %}, {% endif %} {{ item.school_year }} {% set began = True %} {% endif %} {% if item.grammar_corrections %} - {% if began %}|{% endif %} {{ item.grammar_corrections }} + {% if began %}, {% endif %} {{ item.grammar_corrections }} {% set began = True %} {% endif %} + ]