From 268da220d2160ccba46eb718463d8b91b2438fe7 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch
Date: Wed, 10 Apr 2024 13:34:48 +0200
Subject: [PATCH] Enhance code structure
---
app/__init__.py | 3 +
app/admin/json_routes.py | 2 +-
app/admin/routes.py | 4 +-
app/api/jobs.py | 2 +-
app/api/users.py | 4 +-
.../spacy_nlp_pipeline_models/json_routes.py | 2 +-
.../spacy_nlp_pipeline_models/routes.py | 4 +-
.../tesseract_ocr_pipeline_models/routes.py | 4 +-
app/converters/sandpaper.py | 6 +-
app/corpora/files/json_routes.py | 4 +-
app/corpora/files/utils.py | 1 -
app/ext/flask_sqlalchemy/__init__.py | 2 -
app/ext/flask_sqlalchemy/container_column.py | 21 -------
app/extensions/__init__.py | 1 +
app/extensions/sqlalchemy/__init__.py | 2 +
.../sqlalchemy/types.py} | 20 +++++++
app/{ => extensions}/wtforms/__init__.py | 0
app/{ => extensions}/wtforms/validators.py | 0
app/models/corpus.py | 2 +-
app/models/job.py | 2 +-
app/models/spacy_nlp_pipeline_model.py | 2 +-
app/models/tesseract_ocr_pipeline_model.py | 2 +-
app/models/user.py | 2 +-
app/static/js/forms/base-form-new.js | 57 +++++++++++++++++++
app/users/settings/forms.py | 3 +-
requirements.txt | 2 +-
26 files changed, 104 insertions(+), 50 deletions(-)
delete mode 100644 app/ext/flask_sqlalchemy/__init__.py
delete mode 100644 app/ext/flask_sqlalchemy/container_column.py
create mode 100644 app/extensions/__init__.py
create mode 100644 app/extensions/sqlalchemy/__init__.py
rename app/{ext/flask_sqlalchemy/int_enum_column.py => extensions/sqlalchemy/types.py} (52%)
rename app/{ => extensions}/wtforms/__init__.py (100%)
rename app/{ => extensions}/wtforms/validators.py (100%)
create mode 100644 app/static/js/forms/base-form-new.js
diff --git a/app/__init__.py b/app/__init__.py
index 43648294..3b8d8a15 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -33,6 +33,9 @@ scheduler = APScheduler()
socketio = SocketIO()
+# TODO: Create export for lemmatized corpora
+
+
def create_app(config: Config = Config) -> Flask:
''' Creates an initialized Flask (WSGI Application) object. '''
app = Flask(__name__)
diff --git a/app/admin/json_routes.py b/app/admin/json_routes.py
index 9b4ca7d0..e120a654 100644
--- a/app/admin/json_routes.py
+++ b/app/admin/json_routes.py
@@ -1,6 +1,6 @@
from flask import abort, request
-from app import db
from app.decorators import content_negotiation
+from app import db
from app.models import User
from . import bp
diff --git a/app/admin/routes.py b/app/admin/routes.py
index 66d02f00..a1f5e455 100644
--- a/app/admin/routes.py
+++ b/app/admin/routes.py
@@ -9,12 +9,12 @@ from app.users.settings.forms import (
UpdateAccountInformationForm,
UpdateProfileInformationForm
)
-from . import bp
-from .forms import UpdateUserForm
from app.users.utils import (
user_endpoint_arguments_constructor as user_eac,
user_dynamic_list_constructor as user_dlc
)
+from . import bp
+from .forms import UpdateUserForm
@bp.route('')
diff --git a/app/api/jobs.py b/app/api/jobs.py
index 2eaecd3f..97c0a98a 100644
--- a/app/api/jobs.py
+++ b/app/api/jobs.py
@@ -5,8 +5,8 @@ from flask import abort, Blueprint
from werkzeug.exceptions import InternalServerError
from app import db, hashids
from app.models import Job, JobInput, JobStatus, TesseractOCRPipelineModel
-from .schemas import EmptySchema, JobSchema, SpaCyNLPPipelineJobSchema, TesseractOCRPipelineJobSchema, TesseractOCRPipelineModelSchema
from .auth import auth_error_responses, token_auth
+from .schemas import EmptySchema, JobSchema, SpaCyNLPPipelineJobSchema, TesseractOCRPipelineJobSchema, TesseractOCRPipelineModelSchema
bp = Blueprint('jobs', __name__)
diff --git a/app/api/users.py b/app/api/users.py
index c9ea5d39..11c71c97 100644
--- a/app/api/users.py
+++ b/app/api/users.py
@@ -3,11 +3,11 @@ from apifairy import authenticate, body, response
from apifairy.decorators import other_responses
from flask import abort, Blueprint
from werkzeug.exceptions import InternalServerError
-from app import db
from app.email import create_message, send
+from app import db
from app.models import User
-from .schemas import EmptySchema, UserSchema
from .auth import auth_error_responses, token_auth
+from .schemas import EmptySchema, UserSchema
bp = Blueprint('users', __name__)
diff --git a/app/contributions/spacy_nlp_pipeline_models/json_routes.py b/app/contributions/spacy_nlp_pipeline_models/json_routes.py
index 8c081ce8..a4bfa2f0 100644
--- a/app/contributions/spacy_nlp_pipeline_models/json_routes.py
+++ b/app/contributions/spacy_nlp_pipeline_models/json_routes.py
@@ -4,7 +4,7 @@ from threading import Thread
from app import db
from app.decorators import content_negotiation, permission_required
from app.models import SpaCyNLPPipelineModel
-from .. import bp
+from . import bp
@bp.route('/spacy-nlp-pipeline-models/', methods=['DELETE'])
diff --git a/app/contributions/spacy_nlp_pipeline_models/routes.py b/app/contributions/spacy_nlp_pipeline_models/routes.py
index 53593cc8..3bd67d12 100644
--- a/app/contributions/spacy_nlp_pipeline_models/routes.py
+++ b/app/contributions/spacy_nlp_pipeline_models/routes.py
@@ -8,9 +8,7 @@ from .forms import (
CreateSpaCyNLPPipelineModelForm,
UpdateSpaCyNLPPipelineModelForm
)
-from .utils import (
- spacy_nlp_pipeline_model_dlc as spacy_nlp_pipeline_model_dlc
-)
+from .utils import spacy_nlp_pipeline_model_dlc
@bp.route('/spacy-nlp-pipeline-models')
diff --git a/app/contributions/tesseract_ocr_pipeline_models/routes.py b/app/contributions/tesseract_ocr_pipeline_models/routes.py
index 0f0390aa..9471f53d 100644
--- a/app/contributions/tesseract_ocr_pipeline_models/routes.py
+++ b/app/contributions/tesseract_ocr_pipeline_models/routes.py
@@ -8,9 +8,7 @@ from .forms import (
CreateTesseractOCRPipelineModelForm,
UpdateTesseractOCRPipelineModelForm
)
-from .utils import (
- tesseract_ocr_pipeline_model_dlc as tesseract_ocr_pipeline_model_dlc
-)
+from .utils import tesseract_ocr_pipeline_model_dlc
@bp.route('/tesseract-ocr-pipeline-models')
diff --git a/app/converters/sandpaper.py b/app/converters/sandpaper.py
index 86deb8d0..57ac547e 100644
--- a/app/converters/sandpaper.py
+++ b/app/converters/sandpaper.py
@@ -1,11 +1,11 @@
-from flask import current_app
-from app import db
-from app.models import User, Corpus, CorpusFile
from datetime import datetime
+from flask import current_app
from pathlib import Path
from typing import Dict, List
import json
import shutil
+from app import db
+from app.models import User, Corpus, CorpusFile
class SandpaperConverter:
diff --git a/app/corpora/files/json_routes.py b/app/corpora/files/json_routes.py
index f8d5ddb4..d89f3ed6 100644
--- a/app/corpora/files/json_routes.py
+++ b/app/corpora/files/json_routes.py
@@ -1,7 +1,7 @@
-from flask import abort, current_app
+from flask import current_app
from threading import Thread
-from app import db
from app.decorators import content_negotiation
+from app import db
from app.models import CorpusFile
from ..decorators import corpus_follower_permission_required
from . import bp
diff --git a/app/corpora/files/utils.py b/app/corpora/files/utils.py
index 2bb10285..69a66f79 100644
--- a/app/corpora/files/utils.py
+++ b/app/corpora/files/utils.py
@@ -1,6 +1,5 @@
from flask import request, url_for
from app.models import CorpusFile
-from ..utils import corpus_endpoint_arguments_constructor as corpus_eac
def corpus_file_dynamic_list_constructor():
diff --git a/app/ext/flask_sqlalchemy/__init__.py b/app/ext/flask_sqlalchemy/__init__.py
deleted file mode 100644
index fcd46133..00000000
--- a/app/ext/flask_sqlalchemy/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from .container_column import ContainerColumn
-from .int_enum_column import IntEnumColumn
diff --git a/app/ext/flask_sqlalchemy/container_column.py b/app/ext/flask_sqlalchemy/container_column.py
deleted file mode 100644
index a93149fc..00000000
--- a/app/ext/flask_sqlalchemy/container_column.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import json
-from app import db
-
-
-class ContainerColumn(db.TypeDecorator):
- impl = db.String
-
- def __init__(self, container_type, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.container_type = container_type
-
- def process_bind_param(self, value, dialect):
- if isinstance(value, self.container_type):
- return json.dumps(value)
- elif isinstance(value, str) and isinstance(json.loads(value), self.container_type):
- return value
- else:
- return TypeError()
-
- def process_result_value(self, value, dialect):
- return json.loads(value)
diff --git a/app/extensions/__init__.py b/app/extensions/__init__.py
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/app/extensions/__init__.py
@@ -0,0 +1 @@
+
diff --git a/app/extensions/sqlalchemy/__init__.py b/app/extensions/sqlalchemy/__init__.py
new file mode 100644
index 00000000..47f029db
--- /dev/null
+++ b/app/extensions/sqlalchemy/__init__.py
@@ -0,0 +1,2 @@
+from .types import ContainerColumn
+from .types import IntEnumColumn
diff --git a/app/ext/flask_sqlalchemy/int_enum_column.py b/app/extensions/sqlalchemy/types.py
similarity index 52%
rename from app/ext/flask_sqlalchemy/int_enum_column.py
rename to app/extensions/sqlalchemy/types.py
index a0ba4974..215b19cc 100644
--- a/app/ext/flask_sqlalchemy/int_enum_column.py
+++ b/app/extensions/sqlalchemy/types.py
@@ -1,6 +1,26 @@
+import json
from app import db
+class ContainerColumn(db.TypeDecorator):
+ impl = db.String
+
+ def __init__(self, container_type, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.container_type = container_type
+
+ def process_bind_param(self, value, dialect):
+ if isinstance(value, self.container_type):
+ return json.dumps(value)
+ elif isinstance(value, str) and isinstance(json.loads(value), self.container_type):
+ return value
+ else:
+ return TypeError()
+
+ def process_result_value(self, value, dialect):
+ return json.loads(value)
+
+
class IntEnumColumn(db.TypeDecorator):
impl = db.Integer
diff --git a/app/wtforms/__init__.py b/app/extensions/wtforms/__init__.py
similarity index 100%
rename from app/wtforms/__init__.py
rename to app/extensions/wtforms/__init__.py
diff --git a/app/wtforms/validators.py b/app/extensions/wtforms/validators.py
similarity index 100%
rename from app/wtforms/validators.py
rename to app/extensions/wtforms/validators.py
diff --git a/app/models/corpus.py b/app/models/corpus.py
index 1d541413..147fbb02 100644
--- a/app/models/corpus.py
+++ b/app/models/corpus.py
@@ -9,7 +9,7 @@ import shutil
import xml.etree.ElementTree as ET
from app import db
from app.converters.vrt import normalize_vrt_file
-from app.ext.flask_sqlalchemy import IntEnumColumn
+from app.extensions.sqlalchemy import IntEnumColumn
from .corpus_follower_association import CorpusFollowerAssociation
diff --git a/app/models/job.py b/app/models/job.py
index daa043c5..bba8ea0e 100644
--- a/app/models/job.py
+++ b/app/models/job.py
@@ -7,7 +7,7 @@ from typing import Union
from pathlib import Path
import shutil
from app import db
-from app.ext.flask_sqlalchemy import ContainerColumn, IntEnumColumn
+from app.extensions.sqlalchemy import ContainerColumn, IntEnumColumn
class JobStatus(IntEnum):
diff --git a/app/models/spacy_nlp_pipeline_model.py b/app/models/spacy_nlp_pipeline_model.py
index 4cea0d3f..e8a2501b 100644
--- a/app/models/spacy_nlp_pipeline_model.py
+++ b/app/models/spacy_nlp_pipeline_model.py
@@ -5,7 +5,7 @@ from pathlib import Path
import requests
import yaml
from app import db
-from app.ext.flask_sqlalchemy import ContainerColumn
+from app.extensions.sqlalchemy import ContainerColumn
from .file_mixin import FileMixin
from .user import User
diff --git a/app/models/tesseract_ocr_pipeline_model.py b/app/models/tesseract_ocr_pipeline_model.py
index 20f5feee..43198711 100644
--- a/app/models/tesseract_ocr_pipeline_model.py
+++ b/app/models/tesseract_ocr_pipeline_model.py
@@ -5,7 +5,7 @@ from pathlib import Path
import requests
import yaml
from app import db
-from app.ext.flask_sqlalchemy import ContainerColumn
+from app.extensions.sqlalchemy import ContainerColumn
from .file_mixin import FileMixin
from .user import User
diff --git a/app/models/user.py b/app/models/user.py
index 8ba96b14..829337ca 100644
--- a/app/models/user.py
+++ b/app/models/user.py
@@ -12,7 +12,7 @@ import re
import secrets
import shutil
from app import db, hashids
-from app.ext.flask_sqlalchemy import IntEnumColumn
+from app.extensions.sqlalchemy import IntEnumColumn
from .corpus import Corpus
from .corpus_follower_association import CorpusFollowerAssociation
from .corpus_follower_role import CorpusFollowerRole
diff --git a/app/static/js/forms/base-form-new.js b/app/static/js/forms/base-form-new.js
new file mode 100644
index 00000000..6689eee5
--- /dev/null
+++ b/app/static/js/forms/base-form-new.js
@@ -0,0 +1,57 @@
+export class BaseForm {
+ constructor(formElement) {
+ this.element = formElement;
+
+ this.element.addEventListener('submit', (event) => {
+ event.preventDefault();
+ this.submit();
+ });
+ console.log("UsernamePostFormInitialized");
+ }
+
+ submit() {
+ let errorTextElements = this.element
+ .querySelectorAll('.supporting-text[data-supporting-text-type="error"]');
+ for (let errorTextElement of errorTextElements) {errorTextElement.remove();}
+
+ const body = new FormData(this.element);
+ const headers = {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ };
+ const method = this.element.method;
+
+ const fetchPromise = new Promise((resolve, reject) => {
+ fetch(this.element.action, {body: body, headers: headers, method: method})
+ .then((response) => {
+ if (!response.ok) {
+ console.log("reject", response);
+ reject(response);
+ return;
+ }
+ console.log("resolve", response);
+ resolve(response);
+ });
+ });
+
+ fetchPromise
+ .then(
+ (response) => {console.log("Hello from resolve handler");return response.json();},
+ (response) => {
+ console.log("Hello from reject handler 1/2");
+ response.json()
+ .then((errors) => {
+ console.log("Hello from reject handler 2/2");
+ for (let [name, messages] of Object.entries(errors)) {
+ console.log(name, messages);
+ const inputFieldElement = this.element[name].closest('.input-field');
+ for (let message of messages) {
+ const messageHTML = `${message}`;
+ inputFieldElement.insertAdjacentHTML('beforeend', messageHTML);
+ }
+ }
+ });
+ }
+ );
+ }
+};
diff --git a/app/users/settings/forms.py b/app/users/settings/forms.py
index 71c29456..dc4687c1 100644
--- a/app/users/settings/forms.py
+++ b/app/users/settings/forms.py
@@ -1,4 +1,3 @@
-from flask_login import current_user
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired
from wtforms import (
@@ -17,7 +16,7 @@ from wtforms.validators import (
Regexp
)
from app.models import User, UserSettingJobStatusMailNotificationLevel
-from app.wtforms.validators import FileSize
+from app.extensions.wtforms.validators import FileSize
class UpdateAccountInformationForm(FlaskForm):
diff --git a/requirements.txt b/requirements.txt
index 9002ce02..422d1a2d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,7 +15,7 @@ Flask-Marshmallow==0.14.0
Flask-Menu==0.7.2
Flask-Migrate
Flask-Paranoid
-Flask-SocketIO
+Flask-SocketIO==5.3.6
Flask-SQLAlchemy==2.5.1
Flask-WTF
hiredis