mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-03 20:02:47 +00:00 
			
		
		
		
	Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development
share toggle update in contributions
This commit is contained in:
		@@ -6,7 +6,6 @@ from app.decorators import admin_required
 | 
			
		||||
from app.models import Role, User, UserSettingJobStatusMailNotificationLevel
 | 
			
		||||
from app.settings.forms import (
 | 
			
		||||
    EditGeneralSettingsForm,
 | 
			
		||||
    EditInterfaceSettingsForm,
 | 
			
		||||
    EditNotificationSettingsForm
 | 
			
		||||
)
 | 
			
		||||
from . import bp
 | 
			
		||||
@@ -55,9 +54,6 @@ def edit_user(user_id):
 | 
			
		||||
        user,
 | 
			
		||||
        prefix='edit-general-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
    edit_interface_settings_form = EditInterfaceSettingsForm(
 | 
			
		||||
        prefix='edit-interface-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
    edit_notification_settings_form = EditNotificationSettingsForm(
 | 
			
		||||
        prefix='edit-notification-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
@@ -76,12 +72,6 @@ def edit_user(user_id):
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Your changes have been saved')
 | 
			
		||||
        return redirect(url_for('.edit_user', user_id=user.id))
 | 
			
		||||
    if (edit_interface_settings_form.submit.data
 | 
			
		||||
            and edit_interface_settings_form.validate()):
 | 
			
		||||
        user.setting_dark_mode = edit_interface_settings_form.dark_mode.data
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Your changes have been saved')
 | 
			
		||||
        return redirect(url_for('.edit_user', user_id=user.id))
 | 
			
		||||
    if (edit_notification_settings_form.submit.data
 | 
			
		||||
            and edit_notification_settings_form.validate()):
 | 
			
		||||
        user.setting_job_status_mail_notification_level = \
 | 
			
		||||
@@ -93,13 +83,11 @@ def edit_user(user_id):
 | 
			
		||||
        return redirect(url_for('.edit_user', user_id=user.id))
 | 
			
		||||
    admin_edit_user_form.prefill(user)
 | 
			
		||||
    edit_general_settings_form.prefill(user)
 | 
			
		||||
    edit_interface_settings_form.prefill(user)
 | 
			
		||||
    edit_notification_settings_form.prefill(user)
 | 
			
		||||
    return render_template(
 | 
			
		||||
        'admin/edit_user.html.j2',
 | 
			
		||||
        admin_edit_user_form=admin_edit_user_form,
 | 
			
		||||
        edit_general_settings_form=edit_general_settings_form,
 | 
			
		||||
        edit_interface_settings_form=edit_interface_settings_form,
 | 
			
		||||
        edit_notification_settings_form=edit_notification_settings_form,
 | 
			
		||||
        title='Edit user',
 | 
			
		||||
        user=user
 | 
			
		||||
 
 | 
			
		||||
@@ -150,7 +150,6 @@ class UserSchema(ma.SQLAlchemySchema):
 | 
			
		||||
    last_seen = ma.auto_field(dump_only=True)
 | 
			
		||||
    password = ma.String(load_only=True)
 | 
			
		||||
    last_seen = ma.auto_field(dump_only=True)
 | 
			
		||||
    setting_dark_mode = ma.auto_field()
 | 
			
		||||
    setting_job_status_mail_notification_level = ma.String(
 | 
			
		||||
        validate=validate.OneOf(list(UserSettingJobStatusMailNotificationLevel.__members__.keys()))
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ from wtforms.validators import InputRequired, Length
 | 
			
		||||
from app.services import SERVICES
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CreateContributionBaseForm(FlaskForm):
 | 
			
		||||
class ContributionBaseForm(FlaskForm):
 | 
			
		||||
    title = StringField(
 | 
			
		||||
        'Title',
 | 
			
		||||
        validators=[InputRequired(), Length(max=64)]
 | 
			
		||||
@@ -48,7 +48,7 @@ class CreateContributionBaseForm(FlaskForm):
 | 
			
		||||
    submit = SubmitField()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CreateTesseractOCRPipelineModelForm(CreateContributionBaseForm):
 | 
			
		||||
class CreateTesseractOCRPipelineModelForm(ContributionBaseForm):
 | 
			
		||||
    tesseract_model_file = FileField(
 | 
			
		||||
        'File',
 | 
			
		||||
        validators=[FileRequired()]
 | 
			
		||||
@@ -72,7 +72,7 @@ class CreateTesseractOCRPipelineModelForm(CreateContributionBaseForm):
 | 
			
		||||
        self.compatible_service_versions.default = ''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CreateSpaCyNLPPipelineModelForm(CreateContributionBaseForm):
 | 
			
		||||
class CreateSpaCyNLPPipelineModelForm(ContributionBaseForm):
 | 
			
		||||
    spacy_model_file = FileField(
 | 
			
		||||
        'File',
 | 
			
		||||
        validators=[FileRequired()]
 | 
			
		||||
@@ -100,17 +100,8 @@ class CreateSpaCyNLPPipelineModelForm(CreateContributionBaseForm):
 | 
			
		||||
        self.compatible_service_versions.default = ''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EditContributionBaseForm(CreateContributionBaseForm):
 | 
			
		||||
    def prefill(self, model_file):
 | 
			
		||||
        ''' Pre-fill the form with data of an exististing corpus file '''
 | 
			
		||||
        self.title.data = model_file.title
 | 
			
		||||
        self.description.data = model_file.description
 | 
			
		||||
        self.publisher.data = model_file.publisher
 | 
			
		||||
        self.publishing_year.data = model_file.publishing_year
 | 
			
		||||
        self.publisher_url.data = model_file.publisher_url
 | 
			
		||||
        self.publishing_url.data = model_file.publishing_url
 | 
			
		||||
        self.version.data = model_file.version
 | 
			
		||||
        self.shared.data = model_file.shared
 | 
			
		||||
class EditContributionBaseForm(ContributionBaseForm):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EditTesseractOCRPipelineModelForm(EditContributionBaseForm):
 | 
			
		||||
@@ -122,7 +113,3 @@ class EditSpaCyNLPPipelineModelForm(EditContributionBaseForm):
 | 
			
		||||
        'Pipeline name',
 | 
			
		||||
        validators=[InputRequired(), Length(max=64)]
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def prefill(self, model_file):
 | 
			
		||||
        super().prefill(model_file)
 | 
			
		||||
        self.pipeline_name.data = model_file.pipeline_name
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,12 @@
 | 
			
		||||
from flask import abort, current_app, flash, Markup, render_template, url_for
 | 
			
		||||
from flask import (
 | 
			
		||||
    abort,
 | 
			
		||||
    current_app,
 | 
			
		||||
    flash,
 | 
			
		||||
    Markup,
 | 
			
		||||
    redirect,
 | 
			
		||||
    render_template,
 | 
			
		||||
    url_for
 | 
			
		||||
)
 | 
			
		||||
from flask_login import login_required, current_user
 | 
			
		||||
from threading import Thread
 | 
			
		||||
from app import db
 | 
			
		||||
@@ -43,33 +51,17 @@ def 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)
 | 
			
		||||
    form = EditTesseractOCRPipelineModelForm(prefix='edit-tesseract-ocr-pipeline-model-form')
 | 
			
		||||
    form = EditTesseractOCRPipelineModelForm(
 | 
			
		||||
        obj=tesseract_ocr_pipeline_model,
 | 
			
		||||
        prefix='edit-tesseract-ocr-pipeline-model-form'
 | 
			
		||||
    )
 | 
			
		||||
    if form.validate_on_submit():
 | 
			
		||||
        if tesseract_ocr_pipeline_model.title != form.title.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.title = form.title.data
 | 
			
		||||
        if tesseract_ocr_pipeline_model.description != form.description.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.description = form.description.data
 | 
			
		||||
        if tesseract_ocr_pipeline_model.publisher != form.publisher.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.publisher = form.publisher.data
 | 
			
		||||
        if tesseract_ocr_pipeline_model.publishing_year != form.publishing_year.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.publishing_year = form.publishing_year.data
 | 
			
		||||
        if tesseract_ocr_pipeline_model.publisher_url != form.publisher_url.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.publisher_url = form.publisher_url.data
 | 
			
		||||
        if tesseract_ocr_pipeline_model.publishing_url != form.publishing_url.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.publishing_url = form.publishing_url.data
 | 
			
		||||
        if tesseract_ocr_pipeline_model.version != form.version.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.version = form.version.data
 | 
			
		||||
        if tesseract_ocr_pipeline_model.shared != form.shared.data:
 | 
			
		||||
            tesseract_ocr_pipeline_model.shared = form.shared.data
 | 
			
		||||
        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 "<a href="{tesseract_ocr_pipeline_model_url}">{tesseract_ocr_pipeline_model.title}</a>" updated')
 | 
			
		||||
        flash(message)
 | 
			
		||||
        return {}, 201, {'Location': tesseract_ocr_pipeline_model_url}
 | 
			
		||||
    form.prefill(tesseract_ocr_pipeline_model)
 | 
			
		||||
        form.populate_obj(tesseract_ocr_pipeline_model)
 | 
			
		||||
        if db.session.is_modified(tesseract_ocr_pipeline_model):
 | 
			
		||||
            message = Markup(f'Tesseract OCR Pipeline model "<a href="{tesseract_ocr_pipeline_model.url}">{tesseract_ocr_pipeline_model.title}</a>" 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,
 | 
			
		||||
@@ -155,36 +147,17 @@ def 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)
 | 
			
		||||
    form = EditSpaCyNLPPipelineModelForm(prefix='edit-spacy-nlp-pipeline-model-form')
 | 
			
		||||
    form = EditSpaCyNLPPipelineModelForm(
 | 
			
		||||
        obj=spacy_nlp_pipeline_model,
 | 
			
		||||
        prefix='edit-spacy-nlp-pipeline-model-form'
 | 
			
		||||
    )
 | 
			
		||||
    if form.validate_on_submit():
 | 
			
		||||
        if spacy_nlp_pipeline_model.title != form.title.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.title = form.title.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.description != form.description.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.description = form.description.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.pipeline_name != form.pipeline_name.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.pipeline_name = form.pipeline_name.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.publisher != form.publisher.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.publisher = form.publisher.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.publishing_year != form.publishing_year.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.publishing_year = form.publishing_year.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.publisher_url != form.publisher_url.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.publisher_url = form.publisher_url.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.publishing_url != form.publishing_url.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.publishing_url = form.publishing_url.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.version != form.version.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.version = form.version.data
 | 
			
		||||
        if spacy_nlp_pipeline_model.shared != form.shared.data:
 | 
			
		||||
            spacy_nlp_pipeline_model.shared = form.shared.data
 | 
			
		||||
        current_app.logger.warning(db.session.dirty)
 | 
			
		||||
        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 "<a href="{spacy_nlp_pipeline_model_url}">{spacy_nlp_pipeline_model.title}</a>" updated')
 | 
			
		||||
        flash(message)
 | 
			
		||||
        return {}, 201, {'Location': url_for('.contributions')}
 | 
			
		||||
    form.prefill(spacy_nlp_pipeline_model)
 | 
			
		||||
        form.populate_obj(spacy_nlp_pipeline_model)
 | 
			
		||||
        if db.session.is_modified(spacy_nlp_pipeline_model):
 | 
			
		||||
            message = Markup(f'SpaCy NLP Pipeline model "<a href="{spacy_nlp_pipeline_model.url}">{spacy_nlp_pipeline_model.title}</a>" 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,
 | 
			
		||||
 
 | 
			
		||||
@@ -47,20 +47,7 @@ class CreateCorpusFileForm(CorpusFileBaseForm):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EditCorpusFileForm(CorpusFileBaseForm):
 | 
			
		||||
    def prefill(self, corpus_file):
 | 
			
		||||
        ''' Pre-fill the form with data of an exististing corpus file '''
 | 
			
		||||
        self.address.data = corpus_file.address
 | 
			
		||||
        self.author.data = corpus_file.author
 | 
			
		||||
        self.booktitle.data = corpus_file.booktitle
 | 
			
		||||
        self.chapter.data = corpus_file.chapter
 | 
			
		||||
        self.editor.data = corpus_file.editor
 | 
			
		||||
        self.institution.data = corpus_file.institution
 | 
			
		||||
        self.journal.data = corpus_file.journal
 | 
			
		||||
        self.pages.data = corpus_file.pages
 | 
			
		||||
        self.publisher.data = corpus_file.publisher
 | 
			
		||||
        self.publishing_year.data = corpus_file.publishing_year
 | 
			
		||||
        self.school.data = corpus_file.school
 | 
			
		||||
        self.title.data = corpus_file.title
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ImportCorpusForm(FlaskForm):
 | 
			
		||||
 
 | 
			
		||||
@@ -176,52 +176,15 @@ def corpus_file(corpus_id, corpus_file_id):
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if not (corpus_file.corpus.user == current_user or current_user.is_administrator()):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    form = EditCorpusFileForm(prefix='edit-corpus-file-form')
 | 
			
		||||
    form = EditCorpusFileForm(obj=corpus_file, prefix='edit-corpus-file-form')
 | 
			
		||||
    if form.validate_on_submit():
 | 
			
		||||
        has_changes = False
 | 
			
		||||
        if corpus_file.address != form.address.data:
 | 
			
		||||
            corpus_file.address = form.address.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.author != form.author.data:
 | 
			
		||||
            corpus_file.author = form.author.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.booktitle != form.booktitle.data:
 | 
			
		||||
            corpus_file.booktitle = form.booktitle.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.chapter != form.chapter.data:
 | 
			
		||||
            corpus_file.chapter = form.chapter.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.editor != form.editor.data:
 | 
			
		||||
            corpus_file.editor = form.editor.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.institution != form.institution.data:
 | 
			
		||||
            corpus_file.institution = form.institution.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.journal != form.journal.data:
 | 
			
		||||
            corpus_file.journal = form.journal.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.pages != form.pages.data:
 | 
			
		||||
            corpus_file.pages = form.pages.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.publisher != form.publisher.data:
 | 
			
		||||
            corpus_file.publisher = form.publisher.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.publishing_year != form.publishing_year.data:
 | 
			
		||||
            corpus_file.publishing_year = form.publishing_year.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.school != form.school.data:
 | 
			
		||||
            corpus_file.school = form.school.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if corpus_file.title != form.title.data:
 | 
			
		||||
            corpus_file.title = form.title.data
 | 
			
		||||
            has_changes = True
 | 
			
		||||
        if has_changes:
 | 
			
		||||
        form.populate_obj(corpus_file)
 | 
			
		||||
        if db.session.is_modified(corpus_file):
 | 
			
		||||
            corpus_file.corpus.status = CorpusStatus.UNPREPARED
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        message = Markup(f'Corpus file "<a href="{corpus_file.url}">{corpus_file.filename}</a>" updated')
 | 
			
		||||
        flash(message, category='corpus')
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
            message = Markup(f'Corpus file "<a href="{corpus_file.url}">{corpus_file.filename}</a>" updated')
 | 
			
		||||
            flash(message, category='corpus')
 | 
			
		||||
        return redirect(corpus_file.corpus.url)
 | 
			
		||||
    form.prefill(corpus_file)
 | 
			
		||||
    return render_template(
 | 
			
		||||
        'corpora/corpus_file.html.j2',
 | 
			
		||||
        corpus=corpus_file.corpus,
 | 
			
		||||
 
 | 
			
		||||
@@ -263,7 +263,6 @@ class User(HashidMixin, UserMixin, db.Model):
 | 
			
		||||
    password_hash = db.Column(db.String(128))
 | 
			
		||||
    confirmed = db.Column(db.Boolean, default=False)
 | 
			
		||||
    member_since = db.Column(db.DateTime(), default=datetime.utcnow)
 | 
			
		||||
    setting_dark_mode = db.Column(db.Boolean, default=False)
 | 
			
		||||
    setting_job_status_mail_notification_level = db.Column(
 | 
			
		||||
        IntEnumColumn(UserSettingJobStatusMailNotificationLevel),
 | 
			
		||||
        default=UserSettingJobStatusMailNotificationLevel.END
 | 
			
		||||
@@ -500,7 +499,6 @@ class User(HashidMixin, UserMixin, db.Model):
 | 
			
		||||
            'member_since': f'{self.member_since.isoformat()}Z',
 | 
			
		||||
            'username': self.username,
 | 
			
		||||
            'settings': {
 | 
			
		||||
                'dark_mode': self.setting_dark_mode,
 | 
			
		||||
                'job_status_mail_notification_level': \
 | 
			
		||||
                    self.setting_job_status_mail_notification_level.name
 | 
			
		||||
            }
 | 
			
		||||
@@ -552,6 +550,13 @@ class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model):
 | 
			
		||||
            str(self.id)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def url(self):
 | 
			
		||||
        return url_for(
 | 
			
		||||
            'contributions.tesseract_ocr_pipeline_model',
 | 
			
		||||
            tesseract_ocr_pipeline_model_id=self.id
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def insert_defaults():
 | 
			
		||||
        nopaque_user = User.query.filter_by(username='nopaque').first()
 | 
			
		||||
@@ -660,6 +665,13 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
 | 
			
		||||
            str(self.id)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def url(self):
 | 
			
		||||
        return url_for(
 | 
			
		||||
            'contributions.spacy_nlp_pipeline_model',
 | 
			
		||||
            spacy_nlp_pipeline_model_id=self.id
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def insert_defaults():
 | 
			
		||||
        nopaque_user = User.query.filter_by(username='nopaque').first()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,58 +0,0 @@
 | 
			
		||||
class QueryResult(FileMixin, HashidMixin, db.Model):
 | 
			
		||||
    __tablename__ = 'query_results'
 | 
			
		||||
    # Primary key
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)
 | 
			
		||||
    # Foreign keys
 | 
			
		||||
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
 | 
			
		||||
    # Fields
 | 
			
		||||
    description = db.Column(db.String(255))
 | 
			
		||||
    query_metadata = db.Column(db.JSON())
 | 
			
		||||
    title = db.Column(db.String(32))
 | 
			
		||||
    # Backrefs: user: User
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        '''
 | 
			
		||||
        String representation of the QueryResult. For human readability.
 | 
			
		||||
        '''
 | 
			
		||||
        return f'<QueryResult {self.title}>'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def download_url(self):
 | 
			
		||||
        return url_for(
 | 
			
		||||
            'corpora.download_query_result', query_result_id=self.id)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def jsonpatch_path(self):
 | 
			
		||||
        return f'{self.user.jsonpatch_path}/query_results/{self.hashid}'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def path(self):
 | 
			
		||||
        return os.path.join(
 | 
			
		||||
            self.user.path, 'query_results', str(self.id), self.filename)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def url(self):
 | 
			
		||||
        return url_for('corpora.query_result', query_result_id=self.id)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def user_hashid(self):
 | 
			
		||||
        return self.user.hashid
 | 
			
		||||
 | 
			
		||||
    def delete(self):
 | 
			
		||||
        shutil.rmtree(self.path, ignore_errors=True)
 | 
			
		||||
        db.session.delete(self)
 | 
			
		||||
 | 
			
		||||
    def to_json(self, backrefs=False, relationships=False):
 | 
			
		||||
        _json = {
 | 
			
		||||
            'id': self.hashid,
 | 
			
		||||
            'corpus_title': self.query_metadata['corpus_name'],
 | 
			
		||||
            'description': self.description,
 | 
			
		||||
            'filename': self.filename,
 | 
			
		||||
            'query': self.query_metadata['query'],
 | 
			
		||||
            'query_metadata': self.query_metadata,
 | 
			
		||||
            'title': self.title,
 | 
			
		||||
            **self.file_mixin_to_json(
 | 
			
		||||
                backrefs=backrefs, relationships=relationships)
 | 
			
		||||
        }
 | 
			
		||||
        if backrefs:
 | 
			
		||||
            _json['user'] = self.user.to_json(backrefs=True, relationships=False)
 | 
			
		||||
@@ -72,11 +72,9 @@ class CreateTesseractOCRPipelineJobForm(CreateJobBaseForm):
 | 
			
		||||
        self.ocropus_nlbin_threshold.render_kw['disabled'] = True
 | 
			
		||||
        if 'methods' in service_info:
 | 
			
		||||
            if 'binarization' in service_info['methods']:
 | 
			
		||||
                if 'disabled' in self.binarization.render_kw:
 | 
			
		||||
                    del self.binarization.render_kw['disabled']
 | 
			
		||||
                del self.binarization.render_kw['disabled']
 | 
			
		||||
            if 'ocropus_nlbin_threshold' in service_info['methods']:
 | 
			
		||||
                if 'disabled' in self.ocropus_nlbin_threshold.render_kw:
 | 
			
		||||
                    del self.ocropus_nlbin_threshold.render_kw['disabled']
 | 
			
		||||
                del self.ocropus_nlbin_threshold.render_kw['disabled']
 | 
			
		||||
        models = [
 | 
			
		||||
            x for x in TesseractOCRPipelineModel.query.order_by(TesseractOCRPipelineModel.title).all()
 | 
			
		||||
            if version in x.compatible_service_versions and (x.shared == True or x.user == current_user)
 | 
			
		||||
@@ -118,8 +116,7 @@ class CreateTranskribusHTRPipelineJobForm(CreateJobBaseForm):
 | 
			
		||||
        self.binarization.render_kw['disabled'] = True
 | 
			
		||||
        if 'methods' in service_info:
 | 
			
		||||
            if 'binarization' in service_info['methods']:
 | 
			
		||||
                if 'disabled' in self.binarization.render_kw:
 | 
			
		||||
                    del self.binarization.render_kw['disabled']
 | 
			
		||||
                del self.binarization.render_kw['disabled']
 | 
			
		||||
        self.model.choices = [('', 'Choose your option')]
 | 
			
		||||
        self.model.choices += [(x['modelId'], x['name']) for x in transkribus_htr_pipeline_models]
 | 
			
		||||
        self.model.default = ''
 | 
			
		||||
@@ -157,8 +154,7 @@ class CreateSpacyNLPPipelineJobForm(CreateJobBaseForm):
 | 
			
		||||
        self.encoding_detection.render_kw['disabled'] = True
 | 
			
		||||
        if 'methods' in service_info:
 | 
			
		||||
            if 'encoding_detection' in service_info['methods']:
 | 
			
		||||
                if 'disabled' in self.encoding_detection.render_kw:
 | 
			
		||||
                    del self.encoding_detection.render_kw['disabled']
 | 
			
		||||
                del self.encoding_detection.render_kw['disabled']
 | 
			
		||||
        models = [
 | 
			
		||||
            x for x in SpaCyNLPPipelineModel.query.order_by(SpaCyNLPPipelineModel.title).all()
 | 
			
		||||
            if version in x.compatible_service_versions and (x.shared == True or x.user == current_user)
 | 
			
		||||
 
 | 
			
		||||
@@ -71,10 +71,6 @@ class EditGeneralSettingsForm(FlaskForm):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.user = user
 | 
			
		||||
 | 
			
		||||
    def prefill(self, user):
 | 
			
		||||
        self.email.data = user.email
 | 
			
		||||
        self.username.data = user.username
 | 
			
		||||
 | 
			
		||||
    def validate_email(self, field):
 | 
			
		||||
        if (field.data != self.user.email
 | 
			
		||||
                and User.query.filter_by(email=field.data).first()):
 | 
			
		||||
@@ -86,13 +82,6 @@ class EditGeneralSettingsForm(FlaskForm):
 | 
			
		||||
            raise ValidationError('Username already in use')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EditInterfaceSettingsForm(FlaskForm):
 | 
			
		||||
    dark_mode = BooleanField('Dark mode')
 | 
			
		||||
    submit = SubmitField()
 | 
			
		||||
 | 
			
		||||
    def prefill(self, user):
 | 
			
		||||
        self.dark_mode.data = user.setting_dark_mode
 | 
			
		||||
 | 
			
		||||
class EditNotificationSettingsForm(FlaskForm):
 | 
			
		||||
    job_status_mail_notification_level = SelectField(
 | 
			
		||||
        'Job status mail notification level',
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ from . import bp
 | 
			
		||||
from .forms import (
 | 
			
		||||
    ChangePasswordForm,
 | 
			
		||||
    EditGeneralSettingsForm,
 | 
			
		||||
    EditInterfaceSettingsForm,
 | 
			
		||||
    EditNotificationSettingsForm
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -20,11 +19,9 @@ def settings():
 | 
			
		||||
    )
 | 
			
		||||
    edit_general_settings_form = EditGeneralSettingsForm(
 | 
			
		||||
        current_user,
 | 
			
		||||
        obj=current_user,
 | 
			
		||||
        prefix='edit-general-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
    edit_interface_settings_form = EditInterfaceSettingsForm(
 | 
			
		||||
        prefix='edit-interface-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
    edit_notification_settings_form = EditNotificationSettingsForm(
 | 
			
		||||
        prefix='edit-notification-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
@@ -41,13 +38,6 @@ def settings():
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Your changes have been saved')
 | 
			
		||||
        return redirect(url_for('.settings'))
 | 
			
		||||
    if (edit_interface_settings_form.submit.data
 | 
			
		||||
            and edit_interface_settings_form.validate()):
 | 
			
		||||
        current_user.setting_dark_mode = (
 | 
			
		||||
            edit_interface_settings_form.dark_mode.data)
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Your changes have been saved')
 | 
			
		||||
        return redirect(url_for('.settings'))
 | 
			
		||||
    if (edit_notification_settings_form.submit.data
 | 
			
		||||
            and edit_notification_settings_form.validate()):
 | 
			
		||||
        current_user.setting_job_status_mail_notification_level = (
 | 
			
		||||
@@ -58,14 +48,11 @@ def settings():
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Your changes have been saved')
 | 
			
		||||
        return redirect(url_for('.settings'))
 | 
			
		||||
    edit_general_settings_form.prefill(current_user)
 | 
			
		||||
    edit_interface_settings_form.prefill(current_user)
 | 
			
		||||
    edit_notification_settings_form.prefill(current_user)
 | 
			
		||||
    return render_template(
 | 
			
		||||
        'settings/settings.html.j2',
 | 
			
		||||
        change_password_form=change_password_form,
 | 
			
		||||
        edit_general_settings_form=edit_general_settings_form,
 | 
			
		||||
        edit_interface_settings_form=edit_interface_settings_form,
 | 
			
		||||
        edit_notification_settings_form=edit_notification_settings_form,
 | 
			
		||||
        title='Settings'
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -27,38 +27,6 @@
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <form method="POST">
 | 
			
		||||
      {{ edit_interface_settings_form.hidden_tag() }}
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <span class="card-title">Interface settings</span>
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col s12"><p> </p></div>
 | 
			
		||||
            <div class="col s1">
 | 
			
		||||
              <p><i class="material-icons">brightness_3</i></p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col s8">
 | 
			
		||||
              <p>{{ edit_interface_settings_form.dark_mode.label.text }}</p>
 | 
			
		||||
              <p class="light">Enable dark mode to ease your eyes.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col s3 right-align">
 | 
			
		||||
              <div class="switch">
 | 
			
		||||
                <label>
 | 
			
		||||
                  {{ edit_interface_settings_form.dark_mode() }}
 | 
			
		||||
                  <span class="lever"></span>
 | 
			
		||||
                </label>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-action">
 | 
			
		||||
          <div class="right-align">
 | 
			
		||||
            {{ wtf.render_field(edit_interface_settings_form.submit, material_icon='send') }}
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <form method="POST">
 | 
			
		||||
      {{ edit_notification_settings_form.hidden_tag() }}
 | 
			
		||||
      <div class="card">
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,6 @@
 | 
			
		||||
{% block head %}
 | 
			
		||||
{{ super() }}
 | 
			
		||||
<link href="{{ url_for('static', filename='images/nopaque_-_favicon.png') }}" rel="icon">
 | 
			
		||||
{% if current_user.setting_dark_mode %}
 | 
			
		||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/darkreader/4.9.40/darkreader.min.js" integrity="sha512-0Jbi9gWSyU5SvNS16za0aILl6l+MgM8N+TGlZxy4qPQEzqKoU9egh4h56Kz0xp2R+ZFPQMfeDn26Gh6cqu2WAg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 | 
			
		||||
<script>
 | 
			
		||||
  DarkReader.enable();
 | 
			
		||||
</script>
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock head %}
 | 
			
		||||
 | 
			
		||||
{% block metas %}
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,7 @@
 | 
			
		||||
              <div class="col s12">
 | 
			
		||||
                <span class="card-title">Preprocessing</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              {% if 'disabled' not in form.encoding_detection.render_kw or not form.encoding_detection.render_kw['disabled'] %}
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>{{ form.encoding_detection.label.text }}</p>
 | 
			
		||||
                <p class="light">If the input files are not created with the nopaque OCR service or you do not know if your text files are UTF-8 encoded, check this switch. We will try to automatically determine the right encoding for your texts to process them.</p>
 | 
			
		||||
@@ -99,6 +100,7 @@
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
              <!--
 | 
			
		||||
              Seperate each setting with the following
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,7 @@
 | 
			
		||||
              <div class="col s12">
 | 
			
		||||
                <span class="card-title">Preprocessing</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              {% if 'disabled' not in form.binarization.render_kw or not form.binarization.render_kw['disabled'] %}
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>{{ form.binarization.label.text }}</p>
 | 
			
		||||
                <p class="light">Based on a brightness threshold pixels are converted into either black or white. It is useful to reduce noise in images. (<b>longer duration</b>)</p>
 | 
			
		||||
@@ -84,56 +85,14 @@
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>  
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
              {% if 'disabled' not in form.ocropus_nlbin_threshold.render_kw or not form.ocropus_nlbin_threshold.render_kw['disabled'] %}
 | 
			
		||||
              <div class="col s9 hide" id="create-job-form-ocropus_nlbin_threshold-container">
 | 
			
		||||
                <br>
 | 
			
		||||
                <p>Intensity (between 0 and 1)</p>
 | 
			
		||||
                <p class="range-field">{{ form.ocropus_nlbin_threshold() }}</p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s12 divider"></div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>Page range</p>
 | 
			
		||||
                <p class="light"></p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s3 right-align">
 | 
			
		||||
                <div class="switch">
 | 
			
		||||
                  <label>
 | 
			
		||||
                    <input disabled type="checkbox">
 | 
			
		||||
                    <span class="lever"></span>
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s12 divider"></div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>Page rotation</p>
 | 
			
		||||
                <p class="light"></p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s3 right-align">
 | 
			
		||||
                <div class="switch">
 | 
			
		||||
                  <label>
 | 
			
		||||
                    <input disabled type="checkbox">
 | 
			
		||||
                    <span class="lever"></span>
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s12 divider"></div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>Page split</p>
 | 
			
		||||
                <p class="light"></p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s3 right-align">
 | 
			
		||||
                <div class="switch">
 | 
			
		||||
                  <label>
 | 
			
		||||
                    <input disabled type="checkbox">
 | 
			
		||||
                    <span class="lever"></span>
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
              {% endif %}
 | 
			
		||||
              <!--
 | 
			
		||||
              Seperate each setting with the following
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
@@ -185,3 +144,12 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock modals %}
 | 
			
		||||
 | 
			
		||||
{% block scripts %}
 | 
			
		||||
{{ super() }}
 | 
			
		||||
<script>
 | 
			
		||||
document.querySelector('#create-job-form-binarization').addEventListener('change', (event) => {
 | 
			
		||||
  document.querySelector('#create-job-form-ocropus_nlbin_threshold-container').classList.toggle('hide');
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock scripts %}
 | 
			
		||||
 
 | 
			
		||||
@@ -76,6 +76,7 @@
 | 
			
		||||
              <div class="col s12">
 | 
			
		||||
                <span class="card-title">Preprocessing</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              {% if 'disabled' not in form.binarization.render_kw or not form.binarization.render_kw['disabled'] %}
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>{{ form.binarization.label.text }}</p>
 | 
			
		||||
                <p class="light">Based on a brightness threshold pixels are converted into either black or white. It is useful to reduce noise in images. (<b>longer duration</b>)</p>
 | 
			
		||||
@@ -88,51 +89,7 @@
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s12 divider"></div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>Page range</p>
 | 
			
		||||
                <p class="light"></p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s3 right-align">
 | 
			
		||||
                <div class="switch">
 | 
			
		||||
                  <label>
 | 
			
		||||
                    <input disabled type="checkbox">
 | 
			
		||||
                    <span class="lever"></span>
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s12 divider"></div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>Page rotation</p>
 | 
			
		||||
                <p class="light"></p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s3 right-align">
 | 
			
		||||
                <div class="switch">
 | 
			
		||||
                  <label>
 | 
			
		||||
                    <input disabled type="checkbox">
 | 
			
		||||
                    <span class="lever"></span>
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s12 divider"></div>
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
              <div class="col s9">
 | 
			
		||||
                <p>Page split</p>
 | 
			
		||||
                <p class="light"></p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s3 right-align">
 | 
			
		||||
                <div class="switch">
 | 
			
		||||
                  <label>
 | 
			
		||||
                    <input disabled type="checkbox">
 | 
			
		||||
                    <span class="lever"></span>
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
              <!--
 | 
			
		||||
              Seperate each setting with the following
 | 
			
		||||
              <div class="col s12"><p> </p></div>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,38 +27,6 @@
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <form method="POST">
 | 
			
		||||
      {{ edit_interface_settings_form.hidden_tag() }}
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <span class="card-title">Interface settings</span>
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col s12"><p> </p></div>
 | 
			
		||||
            <div class="col s1">
 | 
			
		||||
              <p><i class="material-icons">brightness_3</i></p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col s8">
 | 
			
		||||
              <p>{{ edit_interface_settings_form.dark_mode.label.text }}</p>
 | 
			
		||||
              <p class="light">Enable dark mode to ease your eyes.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col s3 right-align">
 | 
			
		||||
              <div class="switch">
 | 
			
		||||
                <label>
 | 
			
		||||
                  {{ edit_interface_settings_form.dark_mode() }}
 | 
			
		||||
                  <span class="lever"></span>
 | 
			
		||||
                </label>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-action">
 | 
			
		||||
          <div class="right-align">
 | 
			
		||||
            {{ wtf.render_field(edit_interface_settings_form.submit, material_icon='send') }}
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <form method="POST">
 | 
			
		||||
      {{ edit_notification_settings_form.hidden_tag() }}
 | 
			
		||||
      <div class="card">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user