Fix url issues and remove unused modules

This commit is contained in:
Patrick Jentsch 2022-11-16 14:15:52 +01:00
parent 1f896b9bff
commit f1677e2931
16 changed files with 114 additions and 374 deletions

View File

@ -32,6 +32,14 @@ def contributions():
)
@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/<hashid:tesseract_ocr_pipeline_model_id>', 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)
@ -127,6 +135,14 @@ def create_tesseract_ocr_pipeline_model():
)
@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/<hashid:spacy_nlp_pipeline_model_id>', 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)

View File

@ -1,21 +0,0 @@
from flask_wtf import FlaskForm
from werkzeug.utils import secure_filename
from wtforms import FileField, StringField, SubmitField, ValidationError
from wtforms.validators import DataRequired, Length
class AddQueryResultForm(FlaskForm):
'''
Form used to import one result json file.
'''
description = StringField('Description',
validators=[DataRequired(), Length(1, 255)])
file = FileField('File', validators=[DataRequired()])
title = StringField('Title', validators=[DataRequired(), Length(1, 32)])
submit = SubmitField()
def validate_file(self, field):
if not field.data.filename.lower().endswith('.json'):
raise ValidationError('File does not have an approved extension: '
'.json')
field.data.filename = secure_filename(field.data.filename)

View File

@ -1,135 +0,0 @@
from flask import (abort, current_app, flash, make_response, redirect, request,
render_template, url_for, send_from_directory)
from flask_login import current_user, login_required
from . import bp
from . import tasks
from .forms import (AddQueryResultForm, DisplayOptionsForm,
InspectDisplayOptionsForm)
from .. import db
from ..models import QueryResult
import json
import os
@bp.route('/result/add', methods=['GET', 'POST'])
@login_required
def add_query_result():
'''
View to import a result as a json file.
'''
abort(503)
form = AddQueryResultForm(prefix='add-query-result-form')
if form.is_submitted():
if not form.validate():
return make_response(form.errors, 400)
query_result = QueryResult(user=current_user,
description=form.description.data,
filename=form.file.data.filename,
title=form.title.data)
db.session.add(query_result)
db.session.flush()
db.session.refresh(query_result)
try:
os.makedirs(os.path.dirname(query_result.path))
except OSError:
current_app.logger.error(
f'Make dir {query_result.path} led to an OSError!')
db.session.rollback()
flash('Internal Server Error', 'error')
return make_response(
{'redirect_url': url_for('.add_query_result')}, 500)
# save the uploaded file
form.file.data.save(query_result.path)
# parse json from file
with open(query_result.path, 'r') as file:
query_result_file_content = json.load(file)
# parse json schema
# with open('app/static/json_schema/nopaque_cqi_py_results_schema.json', 'r') as file: # noqa
# schema = json.load(file)
# try:
# # validate imported json file
# validate(instance=query_result_file_content, schema=schema)
# except Exception:
# tasks.delete_query_result(query_result.id)
# flash('Uploaded file is invalid', 'result')
# return make_response(
# {'redirect_url': url_for('.add_query_result')}, 201)
query_result_file_content.pop('matches')
query_result_file_content.pop('cpos_lookup')
query_result.query_metadata = query_result_file_content
db.session.commit()
flash('Query result added', 'result')
return make_response({'redirect_url': url_for('.query_result', query_result_id=query_result.id)}, 201) # noqa
return render_template('corpora/query_results/add_query_result.html.j2',
form=form, title='Add query result')
@bp.route('/result/<hashid:query_result_id>')
@login_required
def query_result(query_result_id):
abort(503)
query_result = QueryResult.query.get_or_404(query_result_id)
if not (query_result.user == current_user
or current_user.is_administrator()):
abort(403)
return render_template('corpora/query_results/query_result.html.j2',
query_result=query_result, title='Query result')
@bp.route('/result/<hashid:query_result_id>/inspect')
@login_required
def inspect_query_result(query_result_id):
'''
View to inspect imported result file in a corpus analysis like interface
'''
abort(503)
query_result = QueryResult.query.get_or_404(query_result_id)
query_metadata = query_result.query_metadata
if not (query_result.user == current_user
or current_user.is_administrator()):
abort(403)
display_options_form = DisplayOptionsForm(
prefix='display-options-form',
results_per_page=request.args.get('results_per_page', 30),
result_context=request.args.get('context', 20)
)
inspect_display_options_form = InspectDisplayOptionsForm(
prefix='inspect-display-options-form'
)
with open(query_result.path, 'r') as query_result_file:
query_result_file_content = json.load(query_result_file)
return render_template(
'corpora/query_results/inspect.html.j2',
query_result=query_result,
display_options_form=display_options_form,
inspect_display_options_form=inspect_display_options_form, # noqa
query_result_file_content=query_result_file_content,
query_metadata=query_metadata,
title='Inspect query result'
)
@bp.route('/result/<hashid:query_result_id>/delete')
@login_required
def delete_query_result(query_result_id):
abort(503)
query_result = QueryResult.query.get_or_404(query_result_id)
if not (query_result.user == current_user
or current_user.is_administrator()):
abort(403)
flash(f'Query result "{query_result}" marked for deletion', 'result')
tasks.delete_query_result(query_result_id)
return redirect(url_for('services.service', service="corpus_analysis"))
@bp.route('/result/<hashid:query_result_id>/download')
@login_required
def download_query_result(query_result_id):
abort(503)
query_result = QueryResult.query.get_or_404(query_result_id)
if not (query_result.user == current_user
or current_user.is_administrator()):
abort(403)
return send_from_directory(as_attachment=True,
directory=os.path.dirname(query_result.path),
filename=query_result.filename)

View File

@ -1,13 +0,0 @@
from .. import db
from ..decorators import background
from ..models import QueryResult
@background
def delete_query_result(query_result_id, *args, **kwargs):
with kwargs['app'].app_context():
query_result = QueryResult.query.get(query_result_id)
if query_result is None:
raise Exception(f'QueryResult {query_result_id} not found')
query_result.delete()
db.session.commit()

View File

@ -1,134 +0,0 @@
class QueryResultList extends RessourceList {
static autoInit() {
for (let queryResultListElement of document.querySelectorAll('.query-result-list:not(.no-autoinit)')) {
new QueryResultList(queryResultListElement);
}
}
static options = {
item: `
<tr class="hoverable">
<td><b class="title"></b><br><i class="description"></i><br></td>
<td><span class="corpus-title"></span><br><span class="query"></span></td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: queryResult => {
return {
'id': queryResult.id,
'corpus-title': queryResult.corpus_title,
'creation-date': queryResult.creation_date,
'description': queryResult.description,
'query': queryResult.query,
'title': queryResult.title
};
},
sortArgs: ['creation-date', {order: 'desc'}],
valueNames: [
{data: ['id']},
{data: ['creation-date']},
'corpus-title',
'description',
'query',
'title'
]
};
constructor(listElement, options = {}) {
super(listElement, {...QueryResultList.options, ...options});
}
init(user) {
super._init(user.query_results);
}
onclick(event) {
let action;
let actionButtonElement;
let deleteModal;
let deleteModalElement;
let queryResultElement;
let queryResultId;
let tmp;
queryResultElement = event.target.closest('tr[data-id]');
if (queryResultElement === null) {return;}
queryResultId = queryResultElement.dataset.id;
actionButtonElement = event.target.closest('.action-button[data-action]');
action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
switch (action) {
case 'delete':
tmp = document.createElement('div');
tmp.innerHTML = `
<div class="modal">
<div class="modal-content">
<h4>Confirm query result deletion</h4>
<p>Do you really want to delete the query result <b>${app.users[this.userId].query_results[queryResultId].title}</b>? It will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="/query_results/${queryResultId}/delete"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
`.trim();
deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
deleteModal = M.Modal.init(
deleteModalElement,
{
onCloseEnd: () => {
deleteModal.destroy();
deleteModalElement.remove();
}
}
);
deleteModal.open();
break;
case 'view':
window.location.href = `/query_results/${queryResultId}`;
break;
default:
break;
}
}
onPATCH(patch) {
let filteredPatch;
let match;
let operation;
let queryResultId;
let re;
let valueName;
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)`);
filteredPatch = patch.filter(operation => re.test(operation.path));
for (operation of filteredPatch) {
switch(operation.op) {
case 'add':
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) {
this.add(operation.value);
}
break;
case 'remove':
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) {
[match, queryResultId] = operation.path.match(re);
this.remove(queryResultId);
}
break;
case 'replace':
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)/(corpus_title|description|query|title)$`);
if (re.test(operation.path)) {
[match, queryResultId, valueName] = operation.path.match(re);
this.replace(queryResultId, valueName.replace('_', '-'), operation.value);
}
break;
default:
break;
}
}
}
}

View File

@ -10,9 +10,8 @@ class RessourceList {
JobList.autoInit();
JobInputList.autoInit();
JobResultList.autoInit();
SpacyNLPPipelineModelList.autoInit();
SpaCyNLPPipelineModelList.autoInit();
TesseractOCRPipelineModelList.autoInit();
QueryResultList.autoInit();
UserList.autoInit();
}

View File

@ -1,7 +1,7 @@
class SpacyNLPPipelineModelList extends RessourceList {
class SpaCyNLPPipelineModelList extends RessourceList {
static autoInit() {
for (let spaCyNLPPipelineModelListElement of document.querySelectorAll('.spacy-nlp-pipeline-model-list:not(.no-autoinit)')) {
new SpacyNLPPipelineModelList(spaCyNLPPipelineModelListElement);
new SpaCyNLPPipelineModelList(spaCyNLPPipelineModelListElement);
}
}
@ -70,7 +70,7 @@ class SpacyNLPPipelineModelList extends RessourceList {
};
constructor(listElement, options = {}) {
super(listElement, {...SpacyNLPPipelineModelList.options, ...options});
super(listElement, {...SpaCyNLPPipelineModelList.options, ...options});
}
init (user) {

View File

@ -33,8 +33,8 @@ class Utils {
`
<div class="modal">
<div class="modal-content">
<h4>Confirm job deletion</h4>
<p>Do you really want to delete the job <b>${corpus.title}</b>? All files will be permanently deleted!</p>
<h4>Confirm Corpus deletion</h4>
<p>Do you really want to delete the Corpus <b>${corpus.title}</b>? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
@ -230,8 +230,8 @@ class Utils {
`
<div class="modal">
<div class="modal-content">
<h4>Confirm job deletion</h4>
<p>Do you really want to delete the job <b>${job.title}</b>? All files will be permanently deleted!</p>
<h4>Confirm Job deletion</h4>
<p>Do you really want to delete the Job <b>${job.title}</b>? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
@ -327,8 +327,8 @@ class Utils {
`
<div class="modal">
<div class="modal-content">
<h4>Confirm job restart</h4>
<p>Do you really want to restart the job <b>${job.title}</b>? All log and result files will be permanently deleted.</p>
<h4>Confirm Job restart</h4>
<p>Do you really want to restart the Job <b>${job.title}</b>? All Job Results will be permanently deleted.</p>
</div>
<div class="modal-footer">
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
@ -378,8 +378,8 @@ class Utils {
`
<div class="modal">
<div class="modal-content">
<h4>Confirm job deletion</h4>
<p>Do you really want to delete the user <b>${user.username}</b>? All files will be permanently deleted!</p>
<h4>Confirm User deletion</h4>
<p>Do you really want to delete the User <b>${user.username}</b>? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>

View File

@ -26,7 +26,6 @@
'js/RessourceLists/JobResultList.js',
'js/RessourceLists/SpacyNLPPipelineModelList.js',
'js/RessourceLists/TesseractOCRPipelineModelList.js',
'js/RessourceLists/QueryResultList.js',
'js/RessourceLists/UserList.js'
%}
<script src="{{ ASSET_URL }}"></script>

View File

@ -7,42 +7,34 @@
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
{# Tesseract OCR Models #}
<div>
<h3>My Tesseract OCR Pipeline Models</h3>
<p>Here you can see and edit the models that you have created. You can also create new models.</p>
<div class="row">
<div class="col s12">
<div class="card">
<div class="col s4">
<div class="card extension-selector hoverable service-color" data-service="tesseract-ocr-pipeline">
<a href="{{ url_for('.tesseract_ocr_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a>
<div class="card-content">
<div class="tesseract-ocr-pipeline-model-list" data-user-id="{{ current_user.hashid }}"></div>
</div>
<div class="card-action right-align">
<a href="{{ url_for('.create_tesseract_ocr_pipeline_model') }}" class="btn waves-effect waves-light"><i class="material-icons left">add</i>Create</a>
</div>
</div>
</div>
</div>
</div>
{# spaCy NLP Models #}
<div>
<h3>My spaCy NLP Pipeline Models</h3>
<span class="card-title" data-service="tesseract-ocr-pipeline"><i class="nopaque-icons service-icon" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline Models</span>
<p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<div class="card">
<div class="col s4">
<div class="card extension-selector hoverable service-color" data-service="spacy-nlp-pipeline">
<a href="{{ url_for('.spacy_nlp_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a>
<div class="card-content">
<div class="spacy-nlp-pipeline-model-list" data-user-id="{{ current_user.hashid }}"></div>
</div>
<div class="card-action right-align">
<a href="{{ url_for('.create_spacy_nlp_pipeline_model') }}" class="btn waves-effect waves-light"><i class="material-icons left">add</i>Create</a>
<span class="card-title"><i class="nopaque-icons service-icon" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline Models</span>
<p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div>
</div>
</div>
<div class="col s4">
<div class="card extension-selector hoverable service-color" data-service="transkribus-htr-pipeline">
<a href="" style="position: absolute; width: 100%; height: 100%;"></a>
<div class="card-content">
<span class="card-title"><i class="nopaque-icons service-icon" data-service="transkribus-htr-pipeline"></i>Transkribus HTR Pipeline Models</span>
<p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
{% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
<p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div>
<div class="col s12">
<div class="card">
<div class="card-content">
<div class="spacy-nlp-pipeline-model-list" data-user-id="{{ current_user.hashid }}"></div>
</div>
<div class="card-action right-align">
<a href="{{ url_for('.create_spacy_nlp_pipeline_model') }}" class="btn waves-effect waves-light"><i class="material-icons left">add</i>Create</a>
</div>
</div>
</div>
</div>
</div>
{% endblock page_content %}

View File

@ -0,0 +1,25 @@
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
{% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
<p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div>
<div class="col s12">
<div class="card">
<div class="card-content">
<div class="tesseract-ocr-pipeline-model-list" data-user-id="{{ current_user.hashid }}"></div>
</div>
<div class="card-action right-align">
<a href="{{ url_for('.create_tesseract_ocr_pipeline_model') }}" class="btn waves-effect waves-light"><i class="material-icons left">add</i>Create</a>
</div>
</div>
</div>
</div>
</div>
{% endblock page_content %}

View File

@ -1,9 +1,5 @@
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
<style>
a {color: #FFFFFF;}
</style>
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis" id="corpus-analysis-app-container"{% endblock main_attribs %}
{% block page_content %}

View File

@ -6,18 +6,11 @@
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
<h3>My Corpora and Query results</h3>
<p>Create a corpus to interactively perform linguistic analysis or import query results to save interesting passages.</p>
<div class="row">
<div class="col s12">
<ul class="tabs">
<li class="tab col s6"><a class="active" href="#corpora">Corpora</a></li>
<li class="tab col s6 disabled"><a href="#query-results">Query results</a></li>
</ul>
</div>
<div class="col s12" id="corpora">
<h3>My Corpora</h3>
<p>Create a corpus to interactively perform linguistic analysis.</p>
<div class="card">
<div class="card-content">
<div class="corpus-list" data-user-id="{{ current_user.hashid }}"></div>
@ -28,8 +21,6 @@
</div>
</div>
</div>
</div>
</div>
<div class="col s12" id="jobs">
<h3>My Jobs</h3>

View File

@ -77,7 +77,7 @@
{{ form.model.label }}
<span class="helper-text">
<a class="modal-trigger tooltipped" href="#models-modal" data-position="bottom" data-tooltip="See more information about models"><i class="material-icons" style="color:#0064A3;">help_outline</i></a>
<a class="tooltipped" href="{{ url_for('contributions.add_spacy_nlp_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own spaCy NLP models"><i class="material-icons" style="color:#0064A3">new_label</i></a>
<a class="tooltipped" href="{{ url_for('contributions.create_spacy_nlp_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own spaCy NLP models"><i class="material-icons" style="color:#0064A3">new_label</i></a>
</span>
</div>
</div>

View File

@ -59,7 +59,7 @@
{{ form.model.label }}
<span class="helper-text">
<a class="modal-trigger tooltipped" href="#models-modal" data-position="bottom" data-tooltip="See more information about models"><i class="material-icons" style="color:#00A58B;">help_outline</i></a>
<a class="tooltipped" href="{{ url_for('contributions.add_tesseract_ocr_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own Tesseract OCR models"><i class="material-icons" style="color:#00A58B">new_label</i></a>
<a class="tooltipped" href="{{ url_for('contributions.create_tesseract_ocr_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own Tesseract OCR models"><i class="material-icons" style="color:#00A58B">new_label</i></a>
</span>
{% for error in form.model.errors %}
<span class="helper-text error-color-text">{{ error }}</span>