registration, charts, contracts history

This commit is contained in:
msinkec
2021-08-22 19:07:19 +02:00
parent 540f54dd06
commit 7da73f7d6a
20 changed files with 13999 additions and 489 deletions

View File

@@ -1,3 +1,4 @@
import os
import hashlib
import time
import ssl
@@ -20,6 +21,8 @@ from email.mime.application import MIMEApplication
import pdfkit
from jinja2 import Environment, FileSystemLoader
import jwt
from werkzeug.security import generate_password_hash
from . model import db, UploadRegular, UploadSolar, RegisteredUser, UserInstitutionMapping, Institution, InstitutionContract, CorpusAccess
@@ -238,8 +241,11 @@ class UploadHandler:
return None
def get_user_institutions(user_id):
return UserInstitutionMapping.query.filter_by(user=user_id).all()
def get_user_institution(user_id):
mapping = UserInstitutionMapping.query.filter_by(user=user_id).first()
if mapping:
return Institution.query.filter_by(id=mapping.institution).first()
return None
def has_user_corpus_access(user_id, corpus_name):
@@ -252,13 +258,11 @@ def has_user_corpus_access(user_id, corpus_name):
return True
# Check if user belongs to an institution, that has access to this corpus.
institutions = get_user_institutions(user_id)
institution = get_user_institution(user_id)
has_access = False
for institution in institutions:
row = CorpusAccess.query.filter_by(institution=institution.id, corpus=corpus_name).first()
if row:
has_access = True
break
row = CorpusAccess.query.filter_by(institution=institution.id, corpus=corpus_name).first()
if row:
has_access = True
return has_access
@@ -322,15 +326,86 @@ def add_user_to_institution(user_id, institution_id, role):
return model_obj.id
def activate_user(user_id):
rowcount = db.session.query(RegisteredUser).filter_by(id=user_id).update({'active': True})
db.session.commit()
return rowcount
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})
db.session.commit()
return rowcount
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()
def get_all_active_users():
return RegisteredUser.query.filter_by(active=True).all()
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():
#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()
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):
user_inst_mapping = UserInstitutionMapping.query.filter_by(user=user_id).first()
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':
return False
return True
def is_institution_member(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
return True
def get_password_reset_token(email, expires=500):
return jwt.encode({'reset_password': email,
'exp': time() + expires},
key=os.getenv('APP_SECRET_KEY'), algorithm='HS256')
def verify_reset_token(token):
try:
email = jwt.decode(token,
key=os.getenv('APP_SECRET_KEY'), algorithms=["HS256"])['reset_password']
except Exception as e:
logging.error(e)
return
return RegisteredUser.query.filter_by(email=email).first()
def send_resetpass_mail(email, config):
jwt_token = get_password_reset_token(email)
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))
# 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'], email, text)
except Exception:
traceback.print_exc()

View File

@@ -1,140 +0,0 @@
import logging
import traceback
import re
from datetime import datetime
import portal.base
from portal.base import UploadHandler, ContractCreator, REGEX_EMAIL
from portal.model import db, UploadPredavanja
MAXLEN_FORM = 150
class UploadHandlerPredavanja(UploadHandler):
ENABLED_FILETYPES = None # None means all filetypes
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.contract_creator = ContractCreator(base_path=self.get_uploads_subdir('contracts'),
template_path='contract/predavanja.html')
def generate_upload_contract_pdf(self, upload_metadata):
form_data = upload_metadata['form_data']
files_table_str = []
for file_name in upload_metadata['file_names']:
files_table_str.append('<tr><td style="text-align: center;">')
files_table_str.append(file_name)
files_table_str.append('</td></tr>')
files_table_str = ''.join(files_table_str)
data = {
'ime_priimek': form_data['ime'],
'files_table_str': files_table_str
}
self.contract_creator.create_pdf(upload_metadata['contract_file'], data)
@staticmethod
def store_metadata(upload_metadata):
timestamp = datetime.fromtimestamp(upload_metadata['timestamp'])
form_data = upload_metadata['form_data']
file_hashes = upload_metadata['file_hashes_dict']
sorted_f_hashes = list(file_hashes.values())
sorted_f_hashes.sort()
# Normalize keywords list
keywords_list = []
for keyword in form_data['kljucne-besede'].split(','):
keyword = keyword.strip()
keywords_list.append(keyword)
keywords = ','.join(keywords_list)
try:
model_obj = UploadPredavanja(
upload_hash=upload_metadata['upload_id'],
timestamp=timestamp,
name=form_data['ime'],
address=form_data['naslov-predavanja'],
subject=form_data['predmet'],
faculty=form_data['fakulteta'],
email=form_data['email'],
phone=form_data.get('phone'),
keywords=keywords,
agree_publish_future=form_data['javna-objava-prihodnost'],
agree_machine_translation=True if 'strojno-prevajanje' in form_data else False,
agree_news_cjvt=True if 'obvestila' in form_data else False,
file_contract=upload_metadata['contract_file'],
upload_file_hashes=sorted_f_hashes,
)
db.session.add(model_obj)
db.session.commit()
except Exception:
traceback.print_exc()
def handle_upload(self, request):
err = self.check_upload_request(request)
if err:
return err, 400
err = self.check_form(request.form)
if err:
return err, 400
# Parse request.
upload_metadata = self.extract_upload_metadata('predavanja', request)
logging.info('Upload for "predavanja" with id "{}" supplied form data: {}'.format(
upload_metadata['upload_id'], str(upload_metadata['form_data'])))
# Store uploaded files to disk.
self.store_datafiles(request.files, upload_metadata)
# Store metadata to database.
self.store_metadata(upload_metadata)
# Send confirmation mail
self.send_confirm_mail(upload_metadata)
return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(request.files))
@staticmethod
def check_form(form):
name = form.get('ime')
address = form.get('naslov-predavanja')
subject = form.get('predmet')
faculty = form.get('fakulteta')
email = form.get('email')
phone = form.get('telefon')
keywords = form.get('kljucne-besede')
agree_publish_future = form.get('javna-objava-prihodnost')
if not agree_publish_future:
return 'Manjkajoča izbrana vrednost pri polju za javno objavo.'
if not name \
or not address \
or not subject \
or not faculty \
or not email \
or not keywords:
return 'Izpolnite vsa obvezna polja.'
#for keyword in keywords.split(','):
# keyword = keyword.strip()
# if keyword.isspace() or not keyword.replace(' ', '').isalpha():
# return 'Ključna beseda "{}" ni pravilnega formata.'.format(keyword)
if not re.search(REGEX_EMAIL, email):
return 'Email napačnega formata.'
for key, val in form.items():
if key == 'kljucne-besde':
if len(val) > 500:
return 'Polje "{}" presega dolžino {} znakov.'.format(key, 500)
else:
if len(val) > MAXLEN_FORM:
return 'Polje "{}" presega dolžino {} znakov.'.format(key, MAXLEN_FORM)

View File

@@ -1,12 +1,12 @@
import logging
import re
import traceback
import hashlib
from datetime import datetime
from sqlalchemy import desc, exists
from sqlalchemy import desc
from collections import Counter
from portal.base import UploadHandler, get_user_institutions, has_user_corpus_access
from portal.model import db, UploadSolar, ContractsSolar, RegisteredUser, Institution, InstitutionContract, UserInstitutionMapping, CorpusAccess
from portal.base import UploadHandler, get_user_institution, has_user_corpus_access
from portal.model import UploadSolar, ContractsSolar, RegisteredUser, Institution, InstitutionContract, UserInstitutionMapping, CorpusAccess
VALID_PROGRAMS = {'OS', 'SSG', 'MGP', 'ZG', 'NPI', 'SPI', 'SSI', 'PTI'}
@@ -27,8 +27,7 @@ class UploadHandlerSolar(UploadHandler):
sorted_f_hashes = list(file_hashes.values())
sorted_f_hashes.sort()
# If user is mapped to multiple institutions, let him chose in name of which one he makes the upload.
institution_id = get_user_institutions(user_id)[0].id
institution_id = get_user_institution(user_id).id
model_obj = UploadSolar(
upload_user = user_id,
@@ -147,7 +146,7 @@ class UploadHandlerSolar(UploadHandler):
if program not in VALID_PROGRAMS:
return 'Invalid program "{}"'.format(program)
if predmet not in VALID_SUBJECTS:
return 'Invalid subject "{}"'.format(premdet)
return 'Invalid subject "{}"'.format(predmet)
if letnik < 1 or letnik > 9:
return 'Invalid grade: {}'.format(letnik)
if vrsta not in VALID_TEXT_TYPES:
@@ -176,14 +175,30 @@ def get_all_institutions():
return res
def get_institution_student_contracts(institution_id):
return ContractsSolar.query.filter_by(institution=institution_id, contract_type='ucenci-starsi').all()
def get_institution_student_contracts(institution_id, user_id=None):
if not user_id:
return ContractsSolar.query.filter_by(institution=institution_id, contract_type='ucenci-starsi').all()
return ContractsSolar.query.filter_by(institution=institution_id, contract_type='ucenci-starsi', upload_user=user_id).all()
def get_institution_contract(institution_id):
return InstitutionContract.query.filter_by(institution=institution_id, corpus='solar').order_by(desc(InstitutionContract.timestamp)).first()
def get_top_uploading_institutions():
res = dict()
institutions = get_all_institutions()
for institution in institutions:
uploads = UploadSolar.query.filter_by(institution=institution.id).all()
for upload in uploads:
if institution.name not in res:
res[institution.name] = 0
res[institution.name] += len(upload.upload_file_hashes)
if len(res) >= 5:
return dict(sorted(res.items(), key=lambda x:x[1], reverse=True)[:5])
return dict(sorted(res.items(), key=lambda x:x[1], reverse=True))
def get_all_active_users():
# TODO: do filtering purely within an SQL query
res = []