diff --git a/server/app/apis/__init__.py b/server/app/apis/__init__.py index 3b2ed213ac140a49096aeee16cdd3924a76ae30d..9e3bd0346372f3f651acb7163cc28c8dfadc8c6f 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..360463dc249eaef9662c99168eef960240bc7afb 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 99d467ba7251962de5de2ec24ed1cbb150d001ed..3e6b0cda4c0e52739dca3a34a67dd9502abcac15 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 274406420a2f7f55832f8676b2995276704a8f31..fca727b2ddfb589eb24b8e10a202d14034657315 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 f612cdd67a858cc68b5ec2ca952089c2a77bd756..8d17cdb6d8df70284e5ba5af69c5a77491bc7fe9 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 a2b45fedf42bbec2c1874cdf35060d9c177582ef..02e6df6adf0f238980dc4897888f8335d853968f 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 5a17fb0d7bd28353827c3e9cb97049292ac7ef77..cc492222bbbe4b57eb764c3b37396e58872df983 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)