From 10b5254e8279ac43b4101228b1b3f40487c8c064 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch <p.jentsch@uni-bielefeld.de>
Date: Mon, 25 Apr 2022 11:32:10 +0200
Subject: [PATCH] Restructure code

---
 app/__init__.py                               |  4 +-
 app/email.py                                  |  4 +-
 app/models.py                                 | 46 +++----------------
 ...ocketio.py => socketio_event_listeners.py} |  3 --
 app/sqlalchemy_custom_types.py                | 43 +++++++++++++++++
 ...chemy.py => sqlalchemy_event_listeners.py} |  3 --
 6 files changed, 53 insertions(+), 50 deletions(-)
 rename app/{events/socketio.py => socketio_event_listeners.py} (76%)
 create mode 100644 app/sqlalchemy_custom_types.py
 rename app/{events/sqlalchemy.py => sqlalchemy_event_listeners.py} (92%)

diff --git a/app/__init__.py b/app/__init__.py
index 304f937d..81766262 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -43,8 +43,8 @@ def create_app(config: Config = Config) -> Flask:
         message_queue=app.config['NOPAQUE_SOCKETIO_MESSAGE_QUEUE_URI']
     )
 
-    from .events import socketio as socketio_events
-    from .events import sqlalchemy as sqlalchemy_events
+    from app import socketio_event_listeners
+    from app import sqlalchemy_event_listeners
 
     from .admin import bp as admin_blueprint
     app.register_blueprint(admin_blueprint, url_prefix='/admin')
diff --git a/app/email.py b/app/email.py
index 5e76ca9d..50c41caa 100644
--- a/app/email.py
+++ b/app/email.py
@@ -16,8 +16,8 @@ def create_message(
         f'{subject_prefix} {subject}',
         recipients=[recipient]
     )
-    msg.body: Text = render_template(f'{template}.txt.j2', **kwargs)
-    msg.html: Text = render_template(f'{template}.html.j2', **kwargs)
+    msg.body = render_template(f'{template}.txt.j2', **kwargs)
+    msg.html = render_template(f'{template}.html.j2', **kwargs)
     return msg
 
 
diff --git a/app/models.py b/app/models.py
index 3c4bd94f..84bf7b3c 100644
--- a/app/models.py
+++ b/app/models.py
@@ -1,4 +1,6 @@
+from app import db, login
 from app.converters.vrt import normalize_vrt_file
+from app.sqlalchemy_custom_types import ContainerColumn, IntEnumColumn
 from datetime import datetime, timedelta
 from enum import IntEnum
 from flask import current_app, url_for
@@ -8,7 +10,6 @@ from itsdangerous import BadSignature, TimedJSONWebSignatureSerializer
 from time import sleep
 from tqdm import tqdm
 from werkzeug.security import generate_password_hash, check_password_hash
-from . import db, login
 import base64
 import json
 import os
@@ -22,45 +23,10 @@ TRANSKRIBUS_HTR_MODELS = \
     json.loads(requests.get('https://transkribus.eu/TrpServer/rest/models/text').content)['trpModelMetadata']  # noqa
 
 
-class IntEnumColumn(db.TypeDecorator):
-    impl = db.Integer
-
-    def __init__(self, enum_type, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.enum_type = enum_type
-
-    def process_bind_param(self, value, dialect):
-        if isinstance(value, self.enum_type) and isinstance(value.value, int):
-            return value.value
-        elif isinstance(value, int):
-            return self.enum_type(value).value
-        else:
-            return TypeError()
-
-    def process_result_value(self, value, dialect):
-        return self.enum_type(value)
-
-
-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):  # noqa
-            return value
-        else:
-            return TypeError()
-
-    def process_result_value(self, value, dialect):
-        return json.loads(value)
-
-
 class FileMixin:
+    '''
+    Mixin for db.Model classes. All file related models should use this.
+    '''
     creation_date = db.Column(db.DateTime, default=datetime.utcnow)
     filename = db.Column(db.String(255))
     last_edited_date = db.Column(db.DateTime, default=datetime.utcnow)
@@ -127,7 +93,7 @@ class Role(HashidMixin, db.Model):
         }
         if relationships:
             dict_role['users'] = {
-                x.to_dict(backrefs=False, relationships=True)
+                x.hashid: x.to_dict(backrefs=False, relationships=True)
                 for x in self.users
             }
         return dict_role
diff --git a/app/events/socketio.py b/app/socketio_event_listeners.py
similarity index 76%
rename from app/events/socketio.py
rename to app/socketio_event_listeners.py
index e892ea9d..c432687b 100644
--- a/app/events/socketio.py
+++ b/app/socketio_event_listeners.py
@@ -5,9 +5,6 @@ from flask_login import current_user
 from flask_socketio import join_room
 
 
-###############################################################################
-# Socket.IO event handlers                                                    #
-###############################################################################
 @socketio.on('users.user.get')
 @socketio_login_required
 def users_user_get(user_hashid):
diff --git a/app/sqlalchemy_custom_types.py b/app/sqlalchemy_custom_types.py
new file mode 100644
index 00000000..ac97e308
--- /dev/null
+++ b/app/sqlalchemy_custom_types.py
@@ -0,0 +1,43 @@
+from app import db
+import json
+
+
+class IntEnumColumn(db.TypeDecorator):
+    impl = db.Integer
+
+    def __init__(self, enum_type, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.enum_type = enum_type
+
+    def process_bind_param(self, value, dialect):
+        if isinstance(value, self.enum_type) and isinstance(value.value, int):
+            return value.value
+        elif isinstance(value, int):
+            return self.enum_type(value).value
+        else:
+            return TypeError()
+
+    def process_result_value(self, value, dialect):
+        return self.enum_type(value)
+
+
+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)
\ No newline at end of file
diff --git a/app/events/sqlalchemy.py b/app/sqlalchemy_event_listeners.py
similarity index 92%
rename from app/events/sqlalchemy.py
rename to app/sqlalchemy_event_listeners.py
index 31ffcb20..94470591 100644
--- a/app/events/sqlalchemy.py
+++ b/app/sqlalchemy_event_listeners.py
@@ -13,9 +13,6 @@ from datetime import datetime
 from enum import Enum
 
 
-###############################################################################
-# SQLAlchemy event handlers                                                   #
-###############################################################################
 @db.event.listens_for(Corpus, 'after_delete')
 @db.event.listens_for(CorpusFile, 'after_delete')
 @db.event.listens_for(Job, 'after_delete')
-- 
GitLab