from flask import ( abort, current_app, flash, jsonify, Markup, redirect, render_template, request, url_for ) from flask_login import login_required, current_user from threading import Thread from app import db from app.decorators import content_negotiation, permission_required from app.models import SpaCyNLPPipelineModel, TesseractOCRPipelineModel from . import bp from .forms import ( CreateSpaCyNLPPipelineModelForm, CreateTesseractOCRPipelineModelForm, EditSpaCyNLPPipelineModelForm, EditTesseractOCRPipelineModelForm ) @bp.before_request @login_required def before_request(): pass @bp.route('/') def contributions(): return render_template( 'contributions/contributions.html.j2', title='Contributions' ) ############################################################################## # SpaCy NLP Pipeline Models # ############################################################################## #region spacy-nlp-pipeline-models @bp.route('/spacy-nlp-pipeline-models') def spacy_nlp_pipeline_models(): return render_template( 'contributions/spacy_nlp_pipeline_models.html.j2', title='SpaCy NLP Pipeline Models' ) @bp.route('/spacy-nlp-pipeline-models/create', methods=['GET', 'POST']) def create_spacy_nlp_pipeline_model(): form = CreateSpaCyNLPPipelineModelForm(prefix='create-spacy-nlp-pipeline-model-form') if form.is_submitted(): if not form.validate(): response = {'errors': form.errors} return response, 400 try: spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.create( form.spacy_model_file.data, compatible_service_versions=form.compatible_service_versions.data, description=form.description.data, pipeline_name=form.pipeline_name.data, publisher=form.publisher.data, publisher_url=form.publisher_url.data, publishing_url=form.publishing_url.data, publishing_year=form.publishing_year.data, is_public=False, title=form.title.data, version=form.version.data, user=current_user ) except OSError: abort(500) db.session.commit() spacy_nlp_pipeline_model_url = url_for( '.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id ) message = Markup(f'SpaCy NLP Pipeline model "{spacy_nlp_pipeline_model.title}" created') flash(message) return {}, 201, {'Location': spacy_nlp_pipeline_model_url} return render_template( 'contributions/create_spacy_nlp_pipeline_model.html.j2', form=form, title='Create SpaCy NLP Pipeline Model' ) @bp.route('/spacy-nlp-pipeline-models/', methods=['GET', 'POST']) def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id): spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) form = EditSpaCyNLPPipelineModelForm( data=spacy_nlp_pipeline_model.to_json_serializeable(), prefix='edit-spacy-nlp-pipeline-model-form' ) if form.validate_on_submit(): form.populate_obj(spacy_nlp_pipeline_model) if db.session.is_modified(spacy_nlp_pipeline_model): message = Markup(f'SpaCy NLP Pipeline model "{spacy_nlp_pipeline_model.title}" updated') flash(message) db.session.commit() return redirect(url_for('.spacy_nlp_pipeline_models')) return render_template( 'contributions/spacy_nlp_pipeline_model.html.j2', form=form, spacy_nlp_pipeline_model=spacy_nlp_pipeline_model, title=f'{spacy_nlp_pipeline_model.title} {spacy_nlp_pipeline_model.version}' ) #region json-routes @bp.route('/spacy-nlp-pipeline-models/', methods=['DELETE']) @login_required @content_negotiation(produces='application/json') def delete_spacy_model(spacy_nlp_pipeline_model_id): def _delete_spacy_model(app, spacy_nlp_pipeline_model_id): with app.app_context(): snpm = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id) snpm.delete() db.session.commit() snpm = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id) if snpm is None: resonse_data = { 'message': ( 'SpaCy NLP Pipeline Model with id' f' "{spacy_nlp_pipeline_model_id}" not found' ), 'category': 'error' } response = jsonify(resonse_data) response.status_code = 404 return response if not (snpm.user == current_user or current_user.is_administrator()): resonse_data = { 'message': f'You are not allowed to delete "{snpm.title}"', 'category': 'error' } response = jsonify(resonse_data) response.status_code = 403 return response thread = Thread( target=_delete_spacy_model, args=(current_app._get_current_object(), snpm.id) ) thread.start() resonse_data = { 'message': \ f'SpaCy NLP Pipeline Model "{snpm.title}" marked for deletion' } response = jsonify(resonse_data) response.status_code = 202 return response @bp.route('/spacy-nlp-pipeline-models//is_public', methods=['PUT']) @login_required @permission_required('CONTRIBUTE') @content_negotiation(consumes='application/json', produces='application/json') def update_spacy_nlp_pipeline_model_is_public(spacy_nlp_pipeline_model_id): is_public = request.json if not isinstance(is_public, bool): resonse_data = { 'message': 'Request body must be a boolean', 'category': 'error' } response = jsonify(resonse_data) response.status_code = 400 return response snpm = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id) if snpm is None: resonse_data = { 'message': ( 'SpaCy NLP Pipeline Model with id' f' "{spacy_nlp_pipeline_model_id}" not found' ), 'category': 'error' } response = jsonify(resonse_data) response.status_code = 404 return response if not (snpm.user == current_user or current_user.is_administrator()): resonse_data = { 'message': f'You are not allowed to delete "{snpm.title}"', 'category': 'error' } response = jsonify(resonse_data) response.status_code = 403 return response snpm.is_public = is_public db.session.commit() response_data = { 'message': ( f'SpaCy NLP Pipeline Model "{snpm.title}"' f' is now {"public" if is_public else "private"}' ) } response = jsonify(response_data) response.status_code = 200 return response #endregion json-routes #endregion spacy-nlp-pipeline-models ############################################################################## # Tesseract OCR Pipeline Models # ############################################################################## #region tesseract-ocr-pipeline-models @bp.route('/tesseract-ocr-pipeline-models') def tesseract_ocr_pipeline_models(): return render_template( 'contributions/tesseract_ocr_pipeline_models.html.j2', title='Tesseract OCR Pipeline Models' ) @bp.route('/tesseract-ocr-pipeline-models/create', methods=['GET', 'POST']) def create_tesseract_ocr_pipeline_model(): form = CreateTesseractOCRPipelineModelForm(prefix='create-tesseract-ocr-pipeline-model-form') if form.is_submitted(): if not form.validate(): response = {'errors': form.errors} return response, 400 try: tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.create( form.tesseract_model_file.data, compatible_service_versions=form.compatible_service_versions.data, description=form.description.data, publisher=form.publisher.data, publisher_url=form.publisher_url.data, publishing_url=form.publishing_url.data, publishing_year=form.publishing_year.data, is_public=False, title=form.title.data, version=form.version.data, user=current_user ) except OSError: abort(500) db.session.commit() tesseract_ocr_pipeline_model_url = url_for( '.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id ) message = Markup(f'Tesseract OCR Pipeline model "{tesseract_ocr_pipeline_model.title}" created') flash(message) return {}, 201, {'Location': tesseract_ocr_pipeline_model_url} return render_template( 'contributions/create_tesseract_ocr_pipeline_model.html.j2', form=form, title='Create Tesseract OCR Pipeline Model' ) @bp.route('/tesseract-ocr-pipeline-models/', methods=['GET', 'POST']) def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id): tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) form = EditTesseractOCRPipelineModelForm( data=tesseract_ocr_pipeline_model.to_json_serializeable(), prefix='edit-tesseract-ocr-pipeline-model-form' ) if form.validate_on_submit(): form.populate_obj(tesseract_ocr_pipeline_model) if db.session.is_modified(tesseract_ocr_pipeline_model): message = Markup(f'Tesseract OCR Pipeline model "{tesseract_ocr_pipeline_model.title}" updated') flash(message) db.session.commit() return redirect(url_for('.tesseract_ocr_pipeline_models')) return render_template( 'contributions/tesseract_ocr_pipeline_model.html.j2', form=form, tesseract_ocr_pipeline_model=tesseract_ocr_pipeline_model, title=f'{tesseract_ocr_pipeline_model.title} {tesseract_ocr_pipeline_model.version}' ) #region json-routes @bp.route('/tesseract-ocr-pipeline-models/', methods=['DELETE']) @login_required @content_negotiation(produces='application/json') def delete_tesseract_model(tesseract_ocr_pipeline_model_id): def _delete_tesseract_ocr_pipeline_model(app, tesseract_ocr_pipeline_model_id): with app.app_context(): topm = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id) topm.delete() db.session.commit() topm = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id) if topm is None: resonse_data = { 'message': ( 'Tesseract OCR Pipeline Model with id' f' "{tesseract_ocr_pipeline_model_id}" not found' ), 'category': 'error' } response = jsonify(resonse_data) response.status_code = 404 return response if not (topm.user == current_user or current_user.is_administrator()): resonse_data = { 'message': f'You are not allowed to delete "{topm.title}"', 'category': 'error' } response = jsonify(resonse_data) response.status_code = 403 return response thread = Thread( target=_delete_tesseract_ocr_pipeline_model, args=(current_app._get_current_object(), topm.id) ) thread.start() resonse_data = { 'message': \ f'Tesseract OCR Pipeline Model "{topm.title}" marked for deletion' } response = jsonify(resonse_data) response.status_code = 202 return response @bp.route('/tesseract-ocr-pipeline-models//is_public', methods=['PUT']) @login_required @permission_required('CONTRIBUTE') @content_negotiation(consumes='application/json', produces='application/json') def update_tesseract_ocr_pipeline_model_is_public(tesseract_ocr_pipeline_model_id): is_public = request.json if not isinstance(is_public, bool): resonse_data = { 'message': 'Request body must be a boolean', 'category': 'error' } response = jsonify(resonse_data) response.status_code = 400 return response topm = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id) if topm is None: resonse_data = { 'message': ( 'Tesseract OCR Pipeline Model with id' f' "{tesseract_ocr_pipeline_model_id}" not found' ), 'category': 'error' } response = jsonify(resonse_data) response.status_code = 404 return response if not (topm.user == current_user or current_user.is_administrator()): resonse_data = { 'message': f'You are not allowed to delete "{topm.title}"', 'category': 'error' } response = jsonify(resonse_data) response.status_code = 403 return response topm.is_public = is_public db.session.commit() response_data = { 'message': ( f'Tesseract OCR Pipeline Model "{topm.title}"' f' is now {"public" if is_public else "private"}' ) } response = jsonify(response_data) response.status_code = 200 return response #endregion json-routes #endregion tesseract-ocr-pipeline-models