mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-04 04:12:45 +00:00 
			
		
		
		
	make is_administrator a property, add back db events
This commit is contained in:
		@@ -77,7 +77,7 @@ def delete_job(job_id):
 | 
			
		||||
    job = Job.query.get(job_id)
 | 
			
		||||
    if job is None:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    try:
 | 
			
		||||
        job.delete()
 | 
			
		||||
@@ -97,6 +97,6 @@ def get_job(job_id):
 | 
			
		||||
    job = Job.query.get(job_id)
 | 
			
		||||
    if job is None:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return job
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ def delete_user(user_id):
 | 
			
		||||
    user = User.query.get(user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    user.delete()
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
@@ -78,7 +78,7 @@ def get_user(user_id):
 | 
			
		||||
    user = User.query.get(user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return user
 | 
			
		||||
 | 
			
		||||
@@ -94,6 +94,6 @@ def get_user_by_username(username):
 | 
			
		||||
    user = User.query.filter(User.username == username).first()
 | 
			
		||||
    if user is None:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return user
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ def delete_spacy_model(spacy_nlp_pipeline_model_id):
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
    
 | 
			
		||||
    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
			
		||||
    if not (snpm.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (snpm.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    thread = Thread(
 | 
			
		||||
        target=_delete_spacy_model,
 | 
			
		||||
@@ -39,7 +39,7 @@ def update_spacy_nlp_pipeline_model_is_public(spacy_nlp_pipeline_model_id):
 | 
			
		||||
    if not isinstance(is_public, bool):
 | 
			
		||||
        abort(400)
 | 
			
		||||
    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
			
		||||
    if not (snpm.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (snpm.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    snpm.is_public = is_public
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ def create_spacy_nlp_pipeline_model():
 | 
			
		||||
@register_breadcrumb(bp, '.spacy_nlp_pipeline_models.entity', '', dynamic_list_constructor=spacy_nlp_pipeline_model_dlc)
 | 
			
		||||
def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id):
 | 
			
		||||
    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
			
		||||
    if not (snpm.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (snpm.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    form = UpdateSpaCyNLPPipelineModelForm(data=snpm.to_json_serializeable())
 | 
			
		||||
    if form.validate_on_submit():
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ def delete_tesseract_model(tesseract_ocr_pipeline_model_id):
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
 | 
			
		||||
    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
			
		||||
    if not (topm.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (topm.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    thread = Thread(
 | 
			
		||||
        target=_delete_tesseract_ocr_pipeline_model,
 | 
			
		||||
@@ -39,7 +39,7 @@ def update_tesseract_ocr_pipeline_model_is_public(tesseract_ocr_pipeline_model_i
 | 
			
		||||
    if not isinstance(is_public, bool):
 | 
			
		||||
        abort(400)
 | 
			
		||||
    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
			
		||||
    if not (topm.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (topm.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    topm.is_public = is_public
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ def create_tesseract_ocr_pipeline_model():
 | 
			
		||||
@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models.entity', '', dynamic_list_constructor=tesseract_ocr_pipeline_model_dlc)
 | 
			
		||||
def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id):
 | 
			
		||||
    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
			
		||||
    if not (topm.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (topm.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    form = UpdateTesseractOCRPipelineModelForm(data=topm.to_json_serializeable())
 | 
			
		||||
    if form.validate_on_submit():
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ class CQiNamespace(Namespace):
 | 
			
		||||
            return {'code': 404, 'msg': 'Not Found'}
 | 
			
		||||
        if not (db_corpus.user == current_user
 | 
			
		||||
                or current_user.is_following_corpus(db_corpus)
 | 
			
		||||
                or current_user.is_administrator()):
 | 
			
		||||
                or current_user.is_administrator):
 | 
			
		||||
            return {'code': 403, 'msg': 'Forbidden'}
 | 
			
		||||
        if db_corpus.status not in [
 | 
			
		||||
            CorpusStatus.BUILT,
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ def corpus_follower_permission_required(*permissions):
 | 
			
		||||
        def decorated_function(*args, **kwargs):
 | 
			
		||||
            corpus_id = kwargs.get('corpus_id')
 | 
			
		||||
            corpus = Corpus.query.get_or_404(corpus_id)
 | 
			
		||||
            if not (corpus.user == current_user or current_user.is_administrator()):
 | 
			
		||||
            if not (corpus.user == current_user or current_user.is_administrator):
 | 
			
		||||
                cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
 | 
			
		||||
                if cfa is None:
 | 
			
		||||
                    abort(403)
 | 
			
		||||
@@ -26,7 +26,7 @@ def corpus_owner_or_admin_required(f):
 | 
			
		||||
    def decorated_function(*args, **kwargs):
 | 
			
		||||
        corpus_id = kwargs.get('corpus_id')
 | 
			
		||||
        corpus = Corpus.query.get_or_404(corpus_id)
 | 
			
		||||
        if not (corpus.user == current_user or current_user.is_administrator()):
 | 
			
		||||
        if not (corpus.user == current_user or current_user.is_administrator):
 | 
			
		||||
            abort(403)
 | 
			
		||||
        return f(*args, **kwargs)
 | 
			
		||||
    return decorated_function
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ def get_corpus(corpus_hashid):
 | 
			
		||||
    if not (
 | 
			
		||||
        corpus.is_public
 | 
			
		||||
        or corpus.user == current_user
 | 
			
		||||
        or current_user.is_administrator()
 | 
			
		||||
        or current_user.is_administrator
 | 
			
		||||
    ):
 | 
			
		||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
			
		||||
    return {
 | 
			
		||||
@@ -38,7 +38,7 @@ def subscribe_corpus(corpus_hashid):
 | 
			
		||||
    if not (
 | 
			
		||||
        corpus.is_public
 | 
			
		||||
        or corpus.user == current_user
 | 
			
		||||
        or current_user.is_administrator()
 | 
			
		||||
        or current_user.is_administrator
 | 
			
		||||
    ):
 | 
			
		||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
			
		||||
    join_room(f'/corpora/{corpus.hashid}')
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ def delete_corpus_follower(corpus_id, follower_id):
 | 
			
		||||
        current_user.id == follower_id
 | 
			
		||||
        or current_user == cfa.corpus.user 
 | 
			
		||||
        or CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first().role.has_permission('MANAGE_FOLLOWERS')
 | 
			
		||||
        or current_user.is_administrator()):
 | 
			
		||||
        or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    if current_user.id == follower_id:
 | 
			
		||||
        flash(f'You are no longer following "{cfa.corpus.title}"', 'corpus')
 | 
			
		||||
 
 | 
			
		||||
@@ -55,13 +55,13 @@ def corpus(corpus_id):
 | 
			
		||||
    users = User.query.filter(User.is_public == True, User.id != current_user.id, User.id != corpus.user.id, User.role_id < 4).all()
 | 
			
		||||
    cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
 | 
			
		||||
    if cfa is None:
 | 
			
		||||
        if corpus.user == current_user or current_user.is_administrator():
 | 
			
		||||
        if corpus.user == current_user or current_user.is_administrator:
 | 
			
		||||
            cfr = CorpusFollowerRole.query.filter_by(name='Administrator').first()
 | 
			
		||||
        else:
 | 
			
		||||
            cfr = CorpusFollowerRole.query.filter_by(name='Anonymous').first()
 | 
			
		||||
    else:
 | 
			
		||||
        cfr = cfa.role
 | 
			
		||||
    if corpus.user == current_user or current_user.is_administrator():
 | 
			
		||||
    if corpus.user == current_user or current_user.is_administrator:
 | 
			
		||||
        return render_template(
 | 
			
		||||
            'corpora/corpus.html.j2',
 | 
			
		||||
            title=corpus.title,
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ def delete_job(job_id):
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
 | 
			
		||||
    job = Job.query.get_or_404(job_id)
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    thread = Thread(
 | 
			
		||||
        target=_delete_job,
 | 
			
		||||
@@ -56,7 +56,7 @@ def restart_job(job_id):
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
 | 
			
		||||
    job = Job.query.get_or_404(job_id)
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    if job.status == JobStatus.FAILED:
 | 
			
		||||
        response = {'errors': {'message': 'Job status is not "failed"'}}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ def corpora():
 | 
			
		||||
@register_breadcrumb(bp, '.entity', '', dynamic_list_constructor=job_dlc)
 | 
			
		||||
def job(job_id):
 | 
			
		||||
    job = Job.query.get_or_404(job_id)
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (job.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return render_template(
 | 
			
		||||
        'jobs/job.html.j2',
 | 
			
		||||
@@ -34,7 +34,7 @@ def job(job_id):
 | 
			
		||||
@bp.route('/<hashid:job_id>/inputs/<hashid:job_input_id>/download')
 | 
			
		||||
def download_job_input(job_id, job_input_id):
 | 
			
		||||
    job_input = JobInput.query.filter_by(job_id=job_id, id=job_input_id).first_or_404()
 | 
			
		||||
    if not (job_input.job.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (job_input.job.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return send_from_directory(
 | 
			
		||||
        job_input.path.parent,
 | 
			
		||||
@@ -48,7 +48,7 @@ def download_job_input(job_id, job_input_id):
 | 
			
		||||
@bp.route('/<hashid:job_id>/results/<hashid:job_result_id>/download')
 | 
			
		||||
def download_job_result(job_id, job_result_id):
 | 
			
		||||
    job_result = JobResult.query.filter_by(job_id=job_id, id=job_result_id).first_or_404()
 | 
			
		||||
    if not (job_result.job.user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (job_result.job.user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return send_from_directory(
 | 
			
		||||
        job_result.path.parent,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,6 @@
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from app import db, login, mail, socketio
 | 
			
		||||
from app.email import create_message
 | 
			
		||||
from .avatar import *
 | 
			
		||||
from .corpus_file import *
 | 
			
		||||
from .corpus_follower_association import *
 | 
			
		||||
@@ -11,7 +14,132 @@ from .spacy_nlp_pipeline_model import *
 | 
			
		||||
from .tesseract_ocr_pipeline_model import *
 | 
			
		||||
from .token import *
 | 
			
		||||
from .user import *
 | 
			
		||||
from app import login
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@db.event.listens_for(Corpus, 'after_delete')
 | 
			
		||||
@db.event.listens_for(CorpusFile, 'after_delete')
 | 
			
		||||
@db.event.listens_for(Job, 'after_delete')
 | 
			
		||||
@db.event.listens_for(JobInput, 'after_delete')
 | 
			
		||||
@db.event.listens_for(JobResult, 'after_delete')
 | 
			
		||||
@db.event.listens_for(SpaCyNLPPipelineModel, 'after_delete')
 | 
			
		||||
@db.event.listens_for(TesseractOCRPipelineModel, 'after_delete')
 | 
			
		||||
def resource_after_delete(mapper, connection, resource):
 | 
			
		||||
    print('[START] resource_after_delete')
 | 
			
		||||
    jsonpatch = [
 | 
			
		||||
        {
 | 
			
		||||
            'op': 'remove',
 | 
			
		||||
            'path': resource.jsonpatch_path
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
    room = f'/users/{resource.user_hashid}'
 | 
			
		||||
    print('[EMIT] PATCH', jsonpatch)
 | 
			
		||||
    socketio.emit('PATCH', jsonpatch, room=room)
 | 
			
		||||
    print('[END] resource_after_delete')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@db.event.listens_for(CorpusFollowerAssociation, 'after_delete')
 | 
			
		||||
def cfa_after_delete_handler(mapper, connection, cfa):
 | 
			
		||||
    jsonpatch_path = f'/users/{cfa.corpus.user.hashid}/corpora/{cfa.corpus.hashid}/corpus_follower_associations/{cfa.hashid}'
 | 
			
		||||
    jsonpatch = [
 | 
			
		||||
        {
 | 
			
		||||
            'op': 'remove',
 | 
			
		||||
            'path': jsonpatch_path
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
    room = f'/users/{cfa.corpus.user.hashid}'
 | 
			
		||||
    socketio.emit('PATCH', jsonpatch, room=room)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@db.event.listens_for(Corpus, 'after_insert')
 | 
			
		||||
@db.event.listens_for(CorpusFile, 'after_insert')
 | 
			
		||||
@db.event.listens_for(Job, 'after_insert')
 | 
			
		||||
@db.event.listens_for(JobInput, 'after_insert')
 | 
			
		||||
@db.event.listens_for(JobResult, 'after_insert')
 | 
			
		||||
@db.event.listens_for(SpaCyNLPPipelineModel, 'after_insert')
 | 
			
		||||
@db.event.listens_for(TesseractOCRPipelineModel, 'after_insert')
 | 
			
		||||
def resource_after_insert_handler(mapper, connection, resource):
 | 
			
		||||
    jsonpatch_value = resource.to_json_serializeable()
 | 
			
		||||
    for attr in mapper.relationships:
 | 
			
		||||
        jsonpatch_value[attr.key] = {}
 | 
			
		||||
    jsonpatch = [
 | 
			
		||||
        {
 | 
			
		||||
            'op': 'add',
 | 
			
		||||
            'path': resource.jsonpatch_path,
 | 
			
		||||
            'value': jsonpatch_value
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
    room = f'/users/{resource.user_hashid}'
 | 
			
		||||
    socketio.emit('PATCH', jsonpatch, room=room)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@db.event.listens_for(CorpusFollowerAssociation, 'after_insert')
 | 
			
		||||
def cfa_after_insert_handler(mapper, connection, cfa):
 | 
			
		||||
    jsonpatch_value = cfa.to_json_serializeable()
 | 
			
		||||
    jsonpatch_path = f'/users/{cfa.corpus.user.hashid}/corpora/{cfa.corpus.hashid}/corpus_follower_associations/{cfa.hashid}'
 | 
			
		||||
    jsonpatch = [
 | 
			
		||||
        {
 | 
			
		||||
            'op': 'add',
 | 
			
		||||
            'path': jsonpatch_path,
 | 
			
		||||
            'value': jsonpatch_value
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
    room = f'/users/{cfa.corpus.user.hashid}'
 | 
			
		||||
    socketio.emit('PATCH', jsonpatch, room=room)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@db.event.listens_for(Corpus, 'after_update')
 | 
			
		||||
@db.event.listens_for(CorpusFile, 'after_update')
 | 
			
		||||
@db.event.listens_for(Job, 'after_update')
 | 
			
		||||
@db.event.listens_for(JobInput, 'after_update')
 | 
			
		||||
@db.event.listens_for(JobResult, 'after_update')
 | 
			
		||||
@db.event.listens_for(SpaCyNLPPipelineModel, 'after_update')
 | 
			
		||||
@db.event.listens_for(TesseractOCRPipelineModel, 'after_update')
 | 
			
		||||
def resource_after_update_handler(mapper, connection, resource):
 | 
			
		||||
    jsonpatch = []
 | 
			
		||||
    for attr in db.inspect(resource).attrs:
 | 
			
		||||
        if attr.key in mapper.relationships:
 | 
			
		||||
            continue
 | 
			
		||||
        if not attr.load_history().has_changes():
 | 
			
		||||
            continue
 | 
			
		||||
        jsonpatch_path = f'{resource.jsonpatch_path}/{attr.key}'
 | 
			
		||||
        if isinstance(attr.value, datetime):
 | 
			
		||||
            jsonpatch_value = f'{attr.value.isoformat()}Z'
 | 
			
		||||
        elif isinstance(attr.value, Enum):
 | 
			
		||||
            jsonpatch_value = attr.value.name
 | 
			
		||||
        else:
 | 
			
		||||
            jsonpatch_value = attr.value
 | 
			
		||||
        jsonpatch.append(
 | 
			
		||||
            {
 | 
			
		||||
                'op': 'replace',
 | 
			
		||||
                'path': jsonpatch_path,
 | 
			
		||||
                'value': jsonpatch_value
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    if jsonpatch:
 | 
			
		||||
        room = f'/users/{resource.user_hashid}'
 | 
			
		||||
        socketio.emit('PATCH', jsonpatch, room=room)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@db.event.listens_for(Job, 'after_update')
 | 
			
		||||
def job_after_update_handler(mapper, connection, job):
 | 
			
		||||
    for attr in db.inspect(job).attrs:
 | 
			
		||||
        if attr.key != 'status':
 | 
			
		||||
            continue
 | 
			
		||||
        if not attr.load_history().has_changes():
 | 
			
		||||
            return
 | 
			
		||||
        if job.user.setting_job_status_mail_notification_level == UserSettingJobStatusMailNotificationLevel.NONE:
 | 
			
		||||
            return
 | 
			
		||||
        if job.user.setting_job_status_mail_notification_level == UserSettingJobStatusMailNotificationLevel.END:
 | 
			
		||||
            if job.status not in [JobStatus.COMPLETED, JobStatus.FAILED]:
 | 
			
		||||
                return
 | 
			
		||||
        msg = create_message(
 | 
			
		||||
            job.user.email,
 | 
			
		||||
            f'Status update for your Job "{job.title}"',
 | 
			
		||||
            'tasks/email/notification',
 | 
			
		||||
            job=job
 | 
			
		||||
        )
 | 
			
		||||
        mail.send(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login.user_loader
 | 
			
		||||
 
 | 
			
		||||
@@ -132,6 +132,10 @@ class User(HashidMixin, UserMixin, db.Model):
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return f'<User {self.username}>'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def is_administrator(self):
 | 
			
		||||
        return self.can(Permission.ADMINISTRATE)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def jsonpatch_path(self):
 | 
			
		||||
        return f'/users/{self.hashid}'
 | 
			
		||||
@@ -294,9 +298,6 @@ class User(HashidMixin, UserMixin, db.Model):
 | 
			
		||||
            algorithm='HS256'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def is_administrator(self):
 | 
			
		||||
        return self.can(Permission.ADMINISTRATE)
 | 
			
		||||
 | 
			
		||||
    def ping(self):
 | 
			
		||||
        self.last_seen = datetime.utcnow()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,7 @@
 | 
			
		||||
{% block modals %}
 | 
			
		||||
{{ super() }}
 | 
			
		||||
 | 
			
		||||
{% if current_user == corpus.user or current_user.is_administrator() %}
 | 
			
		||||
{% if current_user == corpus.user or current_user.is_administrator %}
 | 
			
		||||
<div class="modal" id="publishing-modal">
 | 
			
		||||
  <div class="modal-content">
 | 
			
		||||
    <h4>Change your Corpus publishing status</h4>
 | 
			
		||||
@@ -247,7 +247,7 @@
 | 
			
		||||
  });
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{% if current_user == corpus.user or current_user.is_administrator() %}
 | 
			
		||||
{% if current_user == corpus.user or current_user.is_administrator %}
 | 
			
		||||
// #region Publishing
 | 
			
		||||
let publishingModalIsPublicSwitchElement = document.querySelector('#publishing-modal-is-public-switch');
 | 
			
		||||
publishingModalIsPublicSwitchElement.addEventListener('change', (event) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-action right-align">
 | 
			
		||||
          {% if current_user.is_administrator()  %}
 | 
			
		||||
          {% if current_user.is_administrator %}
 | 
			
		||||
          <a class="action-button btn disabled waves-effect waves-light modal-trigger" data-action="get-log-request" id="job-log-button" href="#job-log-modal"><i class="material-icons left">text_snippet</i>Log</a>
 | 
			
		||||
          {% endif %}
 | 
			
		||||
          <a class="btn disabled waves-effect waves-light modal-trigger" href="#restart-job-modal"><i class="material-icons left">repeat</i>Restart</a>
 | 
			
		||||
@@ -159,7 +159,7 @@
 | 
			
		||||
      nopaque.requests.jobs.entity.restart({{ job.hashid|tojson }});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if ({{ current_user.is_administrator()|tojson }}) {
 | 
			
		||||
  if ({{ current_user.is_administrator|tojson }}) {
 | 
			
		||||
    let jobLogButtonElement = document.querySelector('#job-log-button');
 | 
			
		||||
    jobLogButtonElement.addEventListener('click', (event) => {
 | 
			
		||||
      nopaque.requests.jobs.entity.log({{ job.hashid|tojson }})
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ def get_user(user_hashid):
 | 
			
		||||
    user = User.query.get(user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        return {'status': 404, 'statusText': 'Not found'}
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        return {'status': 403, 'statusText': 'Forbidden'}
 | 
			
		||||
    return {
 | 
			
		||||
        'body': user.to_json_serializeable(backrefs=True, relationships=True),
 | 
			
		||||
@@ -28,7 +28,7 @@ def subscribe_user(user_hashid):
 | 
			
		||||
    user = User.query.get(user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        return {'status': 404, 'statusText': 'Not found'}
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        return {'status': 403, 'statusText': 'Forbidden'}
 | 
			
		||||
    join_room(f'/users/{user.hashid}')
 | 
			
		||||
    return {'status': 200, 'statusText': 'OK'}
 | 
			
		||||
@@ -41,7 +41,7 @@ def unsubscribe_user(user_hashid):
 | 
			
		||||
    user = User.query.get(user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        return {'status': 404, 'statusText': 'Not found'}
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        return {'status': 403, 'statusText': 'Forbidden'}
 | 
			
		||||
    leave_room(f'/users/{user.hashid}')
 | 
			
		||||
    return {'status': 200, 'statusText': 'OK'}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ def delete_user(user_id):
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
 | 
			
		||||
    user = User.query.get_or_404(user_id)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    thread = Thread(
 | 
			
		||||
        target=_delete_user,
 | 
			
		||||
@@ -44,7 +44,7 @@ def delete_user_avatar(user_id):
 | 
			
		||||
    user = User.query.get_or_404(user_id)
 | 
			
		||||
    if user.avatar is None:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    thread = Thread(
 | 
			
		||||
        target=_delete_avatar,
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ def get_user(user_hashid):
 | 
			
		||||
    user = User.query.get(user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        return {'options': {'status': 404, 'statusText': 'Not found'}}
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
			
		||||
    return {
 | 
			
		||||
        'body': user.to_json_serializable(),
 | 
			
		||||
@@ -52,7 +52,7 @@ def subscribe_user(user_hashid):
 | 
			
		||||
    user = User.query.get(user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        return {'options': {'status': 404, 'statusText': 'Not found'}}
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
			
		||||
    join_room(f'/users/{user.hashid}')
 | 
			
		||||
    return {'options': {'status': 200, 'statusText': 'OK'}}
 | 
			
		||||
@@ -89,7 +89,7 @@ def get_user(user_hashid):
 | 
			
		||||
    user = User.query.filter_by(id=user_id, is_public=True).first()
 | 
			
		||||
    if user is None:
 | 
			
		||||
        return {'options': {'status': 404, 'statusText': 'Not found'}}
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
			
		||||
    return {
 | 
			
		||||
        'body': user.to_json_serializable(filter_by_privacy_settings=True),
 | 
			
		||||
@@ -108,7 +108,7 @@ def subscribe_user(user_hashid):
 | 
			
		||||
    user = User.query.filter_by(id=user_id, is_public=True).first()
 | 
			
		||||
    if user is None:
 | 
			
		||||
        return {'options': {'status': 404, 'statusText': 'Not found'}}
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
			
		||||
    join_room(f'/public_users/{user.hashid}')
 | 
			
		||||
    return {'options': {'status': 200, 'statusText': 'OK'}}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ def users():
 | 
			
		||||
@register_breadcrumb(bp, '.entity', '', dynamic_list_constructor=user_dlc)
 | 
			
		||||
def user(user_id):
 | 
			
		||||
    user = User.query.get_or_404(user_id)
 | 
			
		||||
    if not (user.is_public or user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user.is_public or user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return render_template(
 | 
			
		||||
        'users/user.html.j2',
 | 
			
		||||
@@ -34,7 +34,7 @@ def user(user_id):
 | 
			
		||||
@bp.route('/<hashid:user_id>/avatar')
 | 
			
		||||
def user_avatar(user_id):
 | 
			
		||||
    user = User.query.get_or_404(user_id)
 | 
			
		||||
    if not (user.is_public or user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user.is_public or user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    if user.avatar is None:
 | 
			
		||||
        return redirect(url_for('static', filename='images/user_avatar.png'))
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ from . import bp
 | 
			
		||||
@content_negotiation(consumes='application/json', produces='application/json')
 | 
			
		||||
def update_user_profile_privacy_setting_is_public(user_id):
 | 
			
		||||
    user = User.query.get_or_404(user_id)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    enabled = request.json
 | 
			
		||||
    if not isinstance(enabled, bool):
 | 
			
		||||
@@ -32,7 +32,7 @@ def update_user_profile_privacy_settings(user_id, profile_privacy_setting_name):
 | 
			
		||||
        profile_privacy_setting = ProfilePrivacySettings[profile_privacy_setting_name]
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    enabled = request.json
 | 
			
		||||
    if not isinstance(enabled, bool):
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ from .forms import (
 | 
			
		||||
@register_breadcrumb(bp, '.entity.settings', '<i class="material-icons left">settings</i>Settings', endpoint_arguments_constructor=user_eac)
 | 
			
		||||
def settings(user_id):
 | 
			
		||||
    user = User.query.get_or_404(user_id)
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator()):
 | 
			
		||||
    if not (user == current_user or current_user.is_administrator):
 | 
			
		||||
        abort(403)
 | 
			
		||||
 | 
			
		||||
    redirect_location_on_post = g.pop(
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								wsgi.py
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								wsgi.py
									
									
									
									
									
								
							@@ -3,23 +3,25 @@
 | 
			
		||||
import eventlet
 | 
			
		||||
eventlet.monkey_patch()
 | 
			
		||||
 | 
			
		||||
from app import create_app, db, scheduler, socketio  # noqa
 | 
			
		||||
from app.models import (
 | 
			
		||||
    Avatar,
 | 
			
		||||
    Corpus,
 | 
			
		||||
    CorpusFile,
 | 
			
		||||
    CorpusFollowerAssociation,
 | 
			
		||||
    CorpusFollowerRole,
 | 
			
		||||
    Job,
 | 
			
		||||
    JobInput,
 | 
			
		||||
    JobResult,
 | 
			
		||||
    Role,
 | 
			
		||||
    TesseractOCRPipelineModel,
 | 
			
		||||
    SpaCyNLPPipelineModel,
 | 
			
		||||
    User
 | 
			
		||||
)  # noqa
 | 
			
		||||
 | 
			
		||||
from flask import Flask  # noqa
 | 
			
		||||
from typing import Any, Dict  # noqa
 | 
			
		||||
from app import create_app, db, scheduler, socketio  # noqa
 | 
			
		||||
from app import models  # noqa
 | 
			
		||||
# from app.models import (
 | 
			
		||||
#     Avatar,
 | 
			
		||||
#     Corpus,
 | 
			
		||||
#     CorpusFile,
 | 
			
		||||
#     CorpusFollowerAssociation,
 | 
			
		||||
#     CorpusFollowerRole,
 | 
			
		||||
#     Job,
 | 
			
		||||
#     JobInput,
 | 
			
		||||
#     JobResult,
 | 
			
		||||
#     Role,
 | 
			
		||||
#     TesseractOCRPipelineModel,
 | 
			
		||||
#     SpaCyNLPPipelineModel,
 | 
			
		||||
#     User
 | 
			
		||||
# )  # noqa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
app: Flask = create_app()
 | 
			
		||||
@@ -30,25 +32,25 @@ def make_shell_context() -> Dict[str, Any]:
 | 
			
		||||
    ''' Adds variables to the shell context. '''
 | 
			
		||||
    return {
 | 
			
		||||
        'db': db,
 | 
			
		||||
        'Avatar': Avatar,
 | 
			
		||||
        'Corpus': Corpus,
 | 
			
		||||
        'CorpusFile': CorpusFile,
 | 
			
		||||
        'CorpusFollowerAssociation': CorpusFollowerAssociation,
 | 
			
		||||
        'CorpusFollowerRole': CorpusFollowerRole,
 | 
			
		||||
        'Job': Job,
 | 
			
		||||
        'JobInput': JobInput,
 | 
			
		||||
        'JobResult': JobResult,
 | 
			
		||||
        'Role': Role,
 | 
			
		||||
        'TesseractOCRPipelineModel': TesseractOCRPipelineModel,
 | 
			
		||||
        'SpaCyNLPPipelineModel': SpaCyNLPPipelineModel,
 | 
			
		||||
        'User': User
 | 
			
		||||
        'Avatar': models.Avatar,
 | 
			
		||||
        'Corpus': models.Corpus,
 | 
			
		||||
        'CorpusFile': models.CorpusFile,
 | 
			
		||||
        'CorpusFollowerAssociation': models.CorpusFollowerAssociation,
 | 
			
		||||
        'CorpusFollowerRole': models.CorpusFollowerRole,
 | 
			
		||||
        'Job': models.Job,
 | 
			
		||||
        'JobInput': models.JobInput,
 | 
			
		||||
        'JobResult': models.JobResult,
 | 
			
		||||
        'Role': models.Role,
 | 
			
		||||
        'TesseractOCRPipelineModel': models.TesseractOCRPipelineModel,
 | 
			
		||||
        'SpaCyNLPPipelineModel': models.SpaCyNLPPipelineModel,
 | 
			
		||||
        'User': models.User
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    with app.app_context():
 | 
			
		||||
        if app.config['NOPAQUE_IS_PRIMARY_INSTANCE']:
 | 
			
		||||
            for corpus in Corpus.query.filter(Corpus.num_analysis_sessions > 0).all():
 | 
			
		||||
            for corpus in models.Corpus.query.filter(models.Corpus.num_analysis_sessions > 0).all():
 | 
			
		||||
                corpus.num_analysis_sessions = 0
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
        scheduler.start()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user