mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2025-07-30 15:25:19 +00:00
move blueprints in dedicated folder
This commit is contained in:
23
app/blueprints/contributions/__init__.py
Normal file
23
app/blueprints/contributions/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from flask import Blueprint
|
||||
from flask_login import login_required
|
||||
|
||||
|
||||
bp = Blueprint('contributions', __name__)
|
||||
|
||||
|
||||
@bp.before_request
|
||||
@login_required
|
||||
def before_request():
|
||||
'''
|
||||
Ensures that the routes in this package can only be visited by users that
|
||||
are logged in.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
from . import (
|
||||
routes,
|
||||
spacy_nlp_pipeline_models,
|
||||
tesseract_ocr_pipeline_models,
|
||||
transkribus_htr_pipeline_models
|
||||
)
|
47
app/blueprints/contributions/forms.py
Normal file
47
app/blueprints/contributions/forms.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import (
|
||||
StringField,
|
||||
SubmitField,
|
||||
SelectMultipleField,
|
||||
IntegerField
|
||||
)
|
||||
from wtforms.validators import InputRequired, Length
|
||||
|
||||
|
||||
class ContributionBaseForm(FlaskForm):
|
||||
title = StringField(
|
||||
'Title',
|
||||
validators=[InputRequired(), Length(max=64)]
|
||||
)
|
||||
description = StringField(
|
||||
'Description',
|
||||
validators=[InputRequired(), Length(max=255)]
|
||||
)
|
||||
version = StringField(
|
||||
'Version',
|
||||
validators=[InputRequired(), Length(max=16)]
|
||||
)
|
||||
publisher = StringField(
|
||||
'Publisher',
|
||||
validators=[InputRequired(), Length(max=128)]
|
||||
)
|
||||
publisher_url = StringField(
|
||||
'Publisher URL',
|
||||
validators=[InputRequired(), Length(max=512)]
|
||||
)
|
||||
publishing_url = StringField(
|
||||
'Publishing URL',
|
||||
validators=[InputRequired(), Length(max=512)]
|
||||
)
|
||||
publishing_year = IntegerField(
|
||||
'Publishing year',
|
||||
validators=[InputRequired()]
|
||||
)
|
||||
compatible_service_versions = SelectMultipleField(
|
||||
'Compatible service versions'
|
||||
)
|
||||
submit = SubmitField()
|
||||
|
||||
|
||||
class UpdateContributionBaseForm(ContributionBaseForm):
|
||||
pass
|
7
app/blueprints/contributions/routes.py
Normal file
7
app/blueprints/contributions/routes.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from flask import redirect, url_for
|
||||
from . import bp
|
||||
|
||||
|
||||
@bp.route('')
|
||||
def contributions():
|
||||
return redirect(url_for('main.dashboard', _anchor='contributions'))
|
@@ -0,0 +1,2 @@
|
||||
from .. import bp
|
||||
from . import json_routes, routes
|
@@ -0,0 +1,48 @@
|
||||
from flask_wtf.file import FileField, FileRequired
|
||||
from wtforms import StringField, ValidationError
|
||||
from wtforms.validators import InputRequired, Length
|
||||
from app.blueprints.services import SERVICES
|
||||
from ..forms import ContributionBaseForm, UpdateContributionBaseForm
|
||||
|
||||
|
||||
class CreateSpaCyNLPPipelineModelForm(ContributionBaseForm):
|
||||
spacy_model_file = FileField(
|
||||
'File',
|
||||
validators=[FileRequired()]
|
||||
)
|
||||
pipeline_name = StringField(
|
||||
'Pipeline name',
|
||||
validators=[InputRequired(), Length(max=64)]
|
||||
)
|
||||
|
||||
def validate_spacy_model_file(self, field):
|
||||
if not field.data.filename.lower().endswith(('.tar.gz', ('.whl'))):
|
||||
raise ValidationError('.tar.gz or .whl files only!')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'prefix' not in kwargs:
|
||||
kwargs['prefix'] = 'create-spacy-nlp-pipeline-model-form'
|
||||
super().__init__(*args, **kwargs)
|
||||
service_manifest = SERVICES['spacy-nlp-pipeline']
|
||||
self.compatible_service_versions.choices = [('', 'Choose your option')]
|
||||
self.compatible_service_versions.choices += [
|
||||
(x, x) for x in service_manifest['versions'].keys()
|
||||
]
|
||||
self.compatible_service_versions.default = ''
|
||||
|
||||
|
||||
class UpdateSpaCyNLPPipelineModelForm(UpdateContributionBaseForm):
|
||||
pipeline_name = StringField(
|
||||
'Pipeline name',
|
||||
validators=[InputRequired(), Length(max=64)]
|
||||
)
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'prefix' not in kwargs:
|
||||
kwargs['prefix'] = 'edit-spacy-nlp-pipeline-model-form'
|
||||
super().__init__(*args, **kwargs)
|
||||
service_manifest = SERVICES['spacy-nlp-pipeline']
|
||||
self.compatible_service_versions.choices = [('', 'Choose your option')]
|
||||
self.compatible_service_versions.choices += [
|
||||
(x, x) for x in service_manifest['versions'].keys()
|
||||
]
|
||||
self.compatible_service_versions.default = ''
|
@@ -0,0 +1,52 @@
|
||||
from flask import abort, current_app, request
|
||||
from flask_login import current_user
|
||||
from threading import Thread
|
||||
from app import db
|
||||
from app.decorators import content_negotiation, permission_required
|
||||
from app.models import SpaCyNLPPipelineModel
|
||||
from . import bp
|
||||
|
||||
|
||||
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE'])
|
||||
@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_or_404(spacy_nlp_pipeline_model_id)
|
||||
if not (snpm.user == current_user or current_user.is_administrator):
|
||||
abort(403)
|
||||
thread = Thread(
|
||||
target=_delete_spacy_model,
|
||||
args=(current_app._get_current_object(), snpm.id)
|
||||
)
|
||||
thread.start()
|
||||
response_data = {
|
||||
'message': \
|
||||
f'SpaCy NLP Pipeline Model "{snpm.title}" marked for deletion'
|
||||
}
|
||||
return response_data, 202
|
||||
|
||||
|
||||
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>/is_public', methods=['PUT'])
|
||||
@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):
|
||||
abort(400)
|
||||
snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
|
||||
if not (snpm.user == current_user or current_user.is_administrator):
|
||||
abort(403)
|
||||
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"}'
|
||||
)
|
||||
}
|
||||
return response_data, 200
|
@@ -0,0 +1,70 @@
|
||||
from flask import abort, flash, redirect, render_template, url_for
|
||||
from flask_login import current_user
|
||||
from app import db
|
||||
from app.models import SpaCyNLPPipelineModel
|
||||
from . import bp
|
||||
from .forms import (
|
||||
CreateSpaCyNLPPipelineModelForm,
|
||||
UpdateSpaCyNLPPipelineModelForm
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/spacy-nlp-pipeline-models')
|
||||
def spacy_nlp_pipeline_models():
|
||||
return render_template(
|
||||
'contributions/spacy_nlp_pipeline_models/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()
|
||||
if form.is_submitted():
|
||||
if not form.validate():
|
||||
return {'errors': form.errors}, 400
|
||||
try:
|
||||
snpm = 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()
|
||||
flash(f'SpaCy NLP Pipeline model "{snpm.title}" created')
|
||||
return {}, 201, {'Location': url_for('.spacy_nlp_pipeline_models')}
|
||||
return render_template(
|
||||
'contributions/spacy_nlp_pipeline_models/create.html.j2',
|
||||
title='Create SpaCy NLP Pipeline Model',
|
||||
form=form
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST'])
|
||||
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):
|
||||
abort(403)
|
||||
form = UpdateSpaCyNLPPipelineModelForm(data=snpm.to_json_serializeable())
|
||||
if form.validate_on_submit():
|
||||
form.populate_obj(snpm)
|
||||
if db.session.is_modified(snpm):
|
||||
flash(f'SpaCy NLP Pipeline model "{snpm.title}" updated')
|
||||
db.session.commit()
|
||||
return redirect(url_for('.spacy_nlp_pipeline_models'))
|
||||
return render_template(
|
||||
'contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_model.html.j2',
|
||||
title=f'{snpm.title} {snpm.version}',
|
||||
form=form,
|
||||
spacy_nlp_pipeline_model=snpm
|
||||
)
|
@@ -0,0 +1,2 @@
|
||||
from .. import bp
|
||||
from . import json_routes, routes
|
@@ -0,0 +1,39 @@
|
||||
from flask_wtf.file import FileField, FileRequired
|
||||
from wtforms import ValidationError
|
||||
from app.blueprints.services import SERVICES
|
||||
from ..forms import ContributionBaseForm, UpdateContributionBaseForm
|
||||
|
||||
|
||||
class CreateTesseractOCRPipelineModelForm(ContributionBaseForm):
|
||||
tesseract_model_file = FileField(
|
||||
'File',
|
||||
validators=[FileRequired()]
|
||||
)
|
||||
|
||||
def validate_tesseract_model_file(self, field):
|
||||
if not field.data.filename.lower().endswith('.traineddata'):
|
||||
raise ValidationError('traineddata files only!')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'prefix' not in kwargs:
|
||||
kwargs['prefix'] = 'create-tesseract-ocr-pipeline-model-form'
|
||||
service_manifest = SERVICES['tesseract-ocr-pipeline']
|
||||
super().__init__(*args, **kwargs)
|
||||
self.compatible_service_versions.choices = [('', 'Choose your option')]
|
||||
self.compatible_service_versions.choices += [
|
||||
(x, x) for x in service_manifest['versions'].keys()
|
||||
]
|
||||
self.compatible_service_versions.default = ''
|
||||
|
||||
|
||||
class UpdateTesseractOCRPipelineModelForm(UpdateContributionBaseForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'prefix' not in kwargs:
|
||||
kwargs['prefix'] = 'edit-tesseract-ocr-pipeline-model-form'
|
||||
service_manifest = SERVICES['tesseract-ocr-pipeline']
|
||||
super().__init__(*args, **kwargs)
|
||||
self.compatible_service_versions.choices = [('', 'Choose your option')]
|
||||
self.compatible_service_versions.choices += [
|
||||
(x, x) for x in service_manifest['versions'].keys()
|
||||
]
|
||||
self.compatible_service_versions.default = ''
|
@@ -0,0 +1,52 @@
|
||||
from flask import abort, current_app, request
|
||||
from flask_login import current_user
|
||||
from threading import Thread
|
||||
from app import db
|
||||
from app.decorators import content_negotiation, permission_required
|
||||
from app.models import TesseractOCRPipelineModel
|
||||
from . import bp
|
||||
|
||||
|
||||
@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['DELETE'])
|
||||
@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_or_404(tesseract_ocr_pipeline_model_id)
|
||||
if not (topm.user == current_user or current_user.is_administrator):
|
||||
abort(403)
|
||||
thread = Thread(
|
||||
target=_delete_tesseract_ocr_pipeline_model,
|
||||
args=(current_app._get_current_object(), topm.id)
|
||||
)
|
||||
thread.start()
|
||||
response_data = {
|
||||
'message': \
|
||||
f'Tesseract OCR Pipeline Model "{topm.title}" marked for deletion'
|
||||
}
|
||||
return response_data, 202
|
||||
|
||||
|
||||
@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>/is_public', methods=['PUT'])
|
||||
@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):
|
||||
abort(400)
|
||||
topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
|
||||
if not (topm.user == current_user or current_user.is_administrator):
|
||||
abort(403)
|
||||
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"}'
|
||||
)
|
||||
}
|
||||
return response_data, 200
|
@@ -0,0 +1,69 @@
|
||||
from flask import abort, flash, redirect, render_template, url_for
|
||||
from flask_login import current_user
|
||||
from app import db
|
||||
from app.models import TesseractOCRPipelineModel
|
||||
from . import bp
|
||||
from .forms import (
|
||||
CreateTesseractOCRPipelineModelForm,
|
||||
UpdateTesseractOCRPipelineModelForm
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/tesseract-ocr-pipeline-models')
|
||||
def tesseract_ocr_pipeline_models():
|
||||
return render_template(
|
||||
'contributions/tesseract_ocr_pipeline_models/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()
|
||||
if form.is_submitted():
|
||||
if not form.validate():
|
||||
return {'errors': form.errors}, 400
|
||||
try:
|
||||
topm = 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()
|
||||
flash(f'Tesseract OCR Pipeline model "{topm.title}" created')
|
||||
return {}, 201, {'Location': url_for('.tesseract_ocr_pipeline_models')}
|
||||
return render_template(
|
||||
'contributions/tesseract_ocr_pipeline_models/create.html.j2',
|
||||
title='Create Tesseract OCR Pipeline Model',
|
||||
form=form
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST'])
|
||||
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):
|
||||
abort(403)
|
||||
form = UpdateTesseractOCRPipelineModelForm(data=topm.to_json_serializeable())
|
||||
if form.validate_on_submit():
|
||||
form.populate_obj(topm)
|
||||
if db.session.is_modified(topm):
|
||||
flash(f'Tesseract OCR Pipeline model "{topm.title}" updated')
|
||||
db.session.commit()
|
||||
return redirect(url_for('.tesseract_ocr_pipeline_models'))
|
||||
return render_template(
|
||||
'contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_model.html.j2',
|
||||
title=f'{topm.title} {topm.version}',
|
||||
form=form,
|
||||
tesseract_ocr_pipeline_model=topm
|
||||
)
|
@@ -0,0 +1,2 @@
|
||||
from .. import bp
|
||||
from . import routes
|
@@ -0,0 +1,7 @@
|
||||
from flask import abort
|
||||
from . import bp
|
||||
|
||||
|
||||
@bp.route('/transkribus_htr_pipeline_models')
|
||||
def transkribus_htr_pipeline_models():
|
||||
return abort(503)
|
Reference in New Issue
Block a user