From 393a76ebc20ea9aac1f77bb68fef50d5ecfe235f Mon Sep 17 00:00:00 2001
From: robban64 <carl@schonfelder.se>
Date: Wed, 14 Apr 2021 15:02:55 +0200
Subject: [PATCH] add: component

---
 server/app/apis/__init__.py           |  3 ++
 server/app/apis/components.py         | 30 +++++++++++
 server/app/core/dto.py                |  6 +++
 server/app/core/schemas.py            | 14 ++++++
 server/app/database/controller/add.py |  8 +++
 server/app/database/controller/get.py |  7 ++-
 server/app/database/models.py         | 72 +++++++++++++++++++++++++++
 7 files changed, 138 insertions(+), 2 deletions(-)

diff --git a/server/app/apis/__init__.py b/server/app/apis/__init__.py
index 3b2ed213..9e3bd034 100644
--- a/server/app/apis/__init__.py
+++ b/server/app/apis/__init__.py
@@ -44,6 +44,7 @@ from flask_restx import Api
 
 from .auth import api as auth_ns
 from .competitions import api as comp_ns
+from .components import api as component_ns
 from .media import api as media_ns
 from .misc import api as misc_ns
 from .questions import api as question_ns
@@ -58,6 +59,8 @@ flask_api.add_namespace(user_ns, path="/api/users")
 flask_api.add_namespace(auth_ns, path="/api/auth")
 flask_api.add_namespace(comp_ns, path="/api/competitions")
 flask_api.add_namespace(slide_ns, path="/api/competitions/<CID>/slides")
+flask_api.add_namespace(component_ns, path="/api/competitions/<CID>/slides/<SID>/components/")
+
 flask_api.add_namespace(team_ns, path="/api/competitions/<CID>/teams")
 flask_api.add_namespace(question_ns, path="/api/competitions/<CID>/questions")
 # flask_api.add_namespace(question_ns, path="/api/competitions/<CID>/slides/<SID>/question")
diff --git a/server/app/apis/components.py b/server/app/apis/components.py
index e69de29b..360463dc 100644
--- a/server/app/apis/components.py
+++ b/server/app/apis/components.py
@@ -0,0 +1,30 @@
+import app.database.controller as dbc
+from app.apis import admin_required, item_response, list_response
+from app.core.dto import ComponentDTO
+from app.core.parsers import competition_parser, competition_search_parser
+from app.database.models import Competition
+from flask.globals import request
+from flask_jwt_extended import jwt_required
+from flask_restx import Resource
+
+api = ComponentDTO.api
+schema = ComponentDTO.schema
+list_schema = ComponentDTO.list_schema
+
+
+@api.route("/<component_id>")
+@api.param("CID, SID, component_id")
+class ComponentByID(Resource):
+    @jwt_required
+    def get(self, CID, SID, component_id):
+        item = dbc.get.component(component_id)
+        return item_response(schema.dump(item))
+
+
+@api.route("/")
+@api.param("CID, SID")
+class ComponentList(Resource):
+    @jwt_required
+    def post(self, CID, SID):
+        item = dbc.add.component(**request.args)
+        return item_response(schema.dump(item))
diff --git a/server/app/core/dto.py b/server/app/core/dto.py
index 99d467ba..3e6b0cda 100644
--- a/server/app/core/dto.py
+++ b/server/app/core/dto.py
@@ -5,6 +5,12 @@ from flask_restx import Namespace, fields
 from flask_uploads import IMAGES, UploadSet
 
 
+class ComponentDTO:
+    api = Namespace("component")
+    schema = schemas.ComponentSchema(many=False)
+    list_schema = schemas.ComponentSchema(many=True)
+
+
 class MediaDTO:
     api = Namespace("media")
     image_set = UploadSet("photos", IMAGES)
diff --git a/server/app/core/schemas.py b/server/app/core/schemas.py
index 27440642..fca727b2 100644
--- a/server/app/core/schemas.py
+++ b/server/app/core/schemas.py
@@ -113,3 +113,17 @@ class CompetitionSchema(BaseSchema):
     name = ma.auto_field()
     year = ma.auto_field()
     city_id = ma.auto_field()
+
+
+class ComponentSchema(BaseSchema):
+    class Meta(BaseSchema.Meta):
+        model = models.Component
+
+    id = ma.auto_field()
+    x = ma.auto_field()
+    y = ma.auto_field()
+    w = ma.auto_field()
+    h = ma.auto_field()
+    slide_id = ma.auto_field()
+    text = ma.auto_field()
+    image_id = ma.auto_field()
diff --git a/server/app/database/controller/add.py b/server/app/database/controller/add.py
index f612cdd6..8d17cdb6 100644
--- a/server/app/database/controller/add.py
+++ b/server/app/database/controller/add.py
@@ -4,6 +4,8 @@ from app.database.models import (
     Blacklist,
     City,
     Competition,
+    Component,
+    ImageComponent,
     Media,
     MediaType,
     Question,
@@ -11,6 +13,7 @@ from app.database.models import (
     Role,
     Slide,
     Team,
+    TextComponent,
     User,
 )
 from flask_restx import abort
@@ -31,6 +34,11 @@ def db_add(func):
     return wrapper
 
 
+@db_add
+def component(x, y, w, h, data, type_id, item_slide):
+    return Component(x, y, w, h, data, item_slide.id, type_id)
+
+
 @db_add
 def blacklist(jti):
     return Blacklist(jti)
diff --git a/server/app/database/controller/get.py b/server/app/database/controller/get.py
index a2b45fed..02e6df6a 100644
--- a/server/app/database/controller/get.py
+++ b/server/app/database/controller/get.py
@@ -1,11 +1,14 @@
-from app.database.models import Competition, Question, Slide, Team, User
-from sqlalchemy.sql.expression import outerjoin
+from app.database.models import Competition, Component, ImageComponent, Question, Slide, Team, TextComponent, User
 
 
 def user_exists(email):
     return User.query.filter(User.email == email).count() > 0
 
 
+def component(ID):
+    return Component.query.filter(Component.id == ID)
+
+
 def competition(CID, required=True, error_msg=None):
     return Competition.query.filter(Competition.id == CID).first_extended(required, error_msg)
 
diff --git a/server/app/database/models.py b/server/app/database/models.py
index 5a17fb0d..cc492222 100644
--- a/server/app/database/models.py
+++ b/server/app/database/models.py
@@ -130,6 +130,8 @@ class Slide(db.Model):
     background_image_id = db.Column(db.Integer, db.ForeignKey("media.id"), nullable=True)
     background_image = db.relationship("Media", uselist=False)
 
+    components = db.relationship("Component", backref="slide")
+
     def __init__(self, order, competition_id):
         self.order = order
         self.competition_id = competition_id
@@ -181,6 +183,76 @@ class QuestionAnswer(db.Model):
         self.team_id = team_id
 
 
+class Component(db.Model):
+    # __mapper_args__ = {"polymorphic_on": type, "polymorphic_identity": "component"}
+    id = db.Column(db.Integer, primary_key=True)
+    x = db.Column(db.Integer, nullable=False, default=0)
+    y = db.Column(db.Integer, nullable=False, default=0)
+    w = db.Column(db.Integer, nullable=False, default=1)
+    h = db.Column(db.Integer, nullable=False, default=1)
+    data = db.Column(db.Text)
+    type_id = db.Column(db.Integer, db.ForeignKey("component_type.id"), nullable=False)
+
+    slide_id = db.Column(db.Integer, db.ForeignKey("slide.id"), nullable=False)
+
+    def __init__(self, x, y, w, h, data, slide_id, type_id):
+        self.x = x
+        self.y = y
+        self.w = w
+        self.h = h
+        self.data = data
+        self.slide_id = slide_id
+        self.type_id = type_id
+
+
+"""
+class ImageComponent(Component):
+    __mapper_args__ = {"polymorphic_identity": "image_component"}
+
+    id = db.Column(db.Integer, db.ForeignKey("component.id"), primary_key=True)
+    # id = db.Column(db.Integer, primary_key=True)
+    image_id = db.Column(db.Integer, db.ForeignKey("media.id"), nullable=False)
+    image = db.relationship("Media", uselist=False)
+
+    def __init__(self, id, image_id, x, y, w, h, slide_id, type):
+        super.__init__(x, y, w, h, slide_id, type)
+        self.id = id
+        self.image_id = image_id
+
+
+class TextComponent(Component):
+    __mapper_args__ = {"polymorphic_identity": "text_component"}
+    id = db.Column(db.Integer, db.ForeignKey("component.id"), primary_key=True)
+    text = db.Column(db.Text, default="", nullable=False)
+
+    def __init__(self, id, text, x, y, w, h, slide_id, type):
+        super.__init__(x, y, w, h, slide_id, type)
+        self.id = id
+        self.text = text
+"""
+
+
+class Code(db.Model):
+    table_args = (db.UniqueConstraint("pointer", "type"),)
+    id = db.Column(db.Integer, primary_key=True)
+    code = db.Column(db.Text, unique=True)
+    pointer = db.Column(db.Integer, nullable=False)
+
+    view_type_id = db.Column(db.Integer, db.ForeignKey("view_type.id"), nullable=False)
+
+
+class ViewType(db.Model):
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.Text)
+    codes = db.relationship("Code", backref="view_type")
+
+
+class ComponentType(db.Model):
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.Text)
+    components = db.relationship("Component", backref="component_type")
+
+
 class MediaType(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(db.String(STRING_SIZE), unique=True)
-- 
GitLab