From ba0c76a72719e4306a6133e3d660ac439ce718a4 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Fri, 23 Oct 2020 02:03:06 +0200 Subject: [PATCH] Improved Typescript Interface generation, enabled it for events --- flaschengeist/system/models/__init__.py | 5 +- flaschengeist/system/models/event.py | 95 ++++++++++++++----------- flaschengeist/system/models/user.py | 8 +-- run_flaschengeist | 33 +++++---- 4 files changed, 74 insertions(+), 67 deletions(-) diff --git a/flaschengeist/system/models/__init__.py b/flaschengeist/system/models/__init__.py index 2fd22e1..595a52e 100644 --- a/flaschengeist/system/models/__init__.py +++ b/flaschengeist/system/models/__init__.py @@ -28,10 +28,9 @@ class UtcDateTime(TypeDecorator): def process_bind_param(self, value, dialect): if value is not None: if not isinstance(value, datetime.datetime): - raise TypeError('expected datetime.datetime, not ' + - repr(value)) + raise TypeError("expected datetime.datetime, not " + repr(value)) elif value.tzinfo is None: - raise ValueError('naive datetime is disallowed') + raise ValueError("naive datetime is disallowed") return value.astimezone(datetime.timezone.utc) def process_result_value(self, value, dialect): diff --git a/flaschengeist/system/models/event.py b/flaschengeist/system/models/event.py index 00d8a43..94b6e50 100644 --- a/flaschengeist/system/models/event.py +++ b/flaschengeist/system/models/event.py @@ -1,65 +1,74 @@ +from datetime import datetime +from typing import Optional + from . import ModelSerializeMixin +from .user import User from ..database import db -class Event(db.Model, ModelSerializeMixin): - """Model for an Event""" - __tablename__ = "event" - id = db.Column(db.Integer, primary_key=True) - begin = db.Column(db.DateTime, nullable=False) - end = db.Column(db.DateTime) - description = db.Column(db.String(240)) - kind = db.relationship("EventKind") - slots = db.relationship("EventSlot", back_populates="event", cascade="all, delete") - # notices = db.relationship("EventNotice", back_populates="event") - - _kind_id = db.Column(db.Integer, db.ForeignKey("event_kind.id", ondelete="CASCADE"), nullable=False) - - -class EventKind(db.Model, ModelSerializeMixin): - """Model for an EventKind""" - __tablename__ = "event_kind" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(30), nullable=False, unique=True) - - class EventSlot(db.Model, ModelSerializeMixin): """Model for an EventSlot""" + __tablename__ = "event_slot" - id = db.Column(db.Integer, primary_key=True) - start = db.Column(db.DateTime) - end = db.Column(db.DateTime) - slots = db.relationship("JobSlot", back_populates="event_slot") + id: int = db.Column(db.Integer, primary_key=True) + start: datetime = db.Column(db.DateTime) + end: Optional[datetime] = db.Column(db.DateTime) + slots: [any] = db.relationship("JobSlot", back_populates="_event_slot") - _event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False) - _event = db.relationship("Event", back_populates="slots") + _event_id = db.Column("event_id", db.Integer, db.ForeignKey("event.id"), nullable=False) + _event = db.relationship("Event", back_populates="_slots") -class JobSlot(db.Model, ModelSerializeMixin): - __tablename__ = "job_slot" - id = db.Column(db.Integer, primary_key=True) - needed_persons = db.Column(db.Numeric(precision=4, scale=2)) - kind = db.relationship("JobKind") - jobs = db.relationship("Job", back_populates="slot") +class EventKind(db.Model, ModelSerializeMixin): + """Model for an EventKind""" - _event_slot_id = db.Column(db.Integer, db.ForeignKey("event_slot.id")) - _event_slot = db.relationship("EventSlot", back_populates="slots") - _kind_id = db.Column(db.Integer, db.ForeignKey("job_kind.id")) + __tablename__ = "event_kind" + name: str = db.Column(db.String(30), nullable=False, unique=True) + + _id: int = db.Column("id", db.Integer, primary_key=True) + + +class Event(db.Model, ModelSerializeMixin): + """Model for an Event""" + + __tablename__ = "event" + id: int = db.Column(db.Integer, primary_key=True) + begin: datetime = db.Column(db.DateTime, nullable=False) + end: datetime = db.Column(db.DateTime) + description: str = db.Column(db.String(240)) + kind: EventKind = db.relationship("EventKind") + # notices = db.relationship("EventNotice", back_populates="event") + + _kind_id = db.Column("kind_id", db.Integer, db.ForeignKey("event_kind.id", ondelete="CASCADE"), nullable=False) + _slots: [EventSlot] = db.relationship("EventSlot", back_populates="_event", cascade="all, delete") class Job(db.Model, ModelSerializeMixin): __tablename__ = "job" - user = db.relationship("User") - value = db.Column(db.Numeric(precision=3, scale=2)) + _user: User = db.relationship("User") + # user: str = column_property(_user.userid) + value: float = db.Column(db.Numeric(precision=3, scale=2)) - _user_id = db.Column(db.Integer, db.ForeignKey("user.id")) - _slot_id = db.Column(db.Integer, db.ForeignKey("job_slot.id")) + _id = db.Column("id", db.Integer, primary_key=True) + _user_id = db.Column("user_id", db.Integer, db.ForeignKey("user.id")) + _slot_id = db.Column("slot_id", db.Integer, db.ForeignKey("job_slot.id")) _slot = db.relationship("JobSlot") - _id = db.Column(db.Integer, primary_key=True) class JobKind(db.Model, ModelSerializeMixin): __tablename__ = "job_kind" - name = db.Column(db.String(30), nullable=False, unique=True) + name: str = db.Column(db.String(30), nullable=False, unique=True) - _id = db.Column(db.Integer, primary_key=True) + _id = db.Column("id", db.Integer, primary_key=True) + + +class JobSlot(db.Model, ModelSerializeMixin): + __tablename__ = "job_slot" + id: int = db.Column(db.Integer, primary_key=True) + needed_persons: float = db.Column(db.Numeric(precision=4, scale=2)) + kind: JobKind = db.relationship("JobKind") + jobs: [Job] = db.relationship("Job", back_populates="_slot") + + _event_slot_id = db.Column("event_slot_id", db.Integer, db.ForeignKey("event_slot.id")) + _event_slot = db.relationship("EventSlot", back_populates="slots") + _kind_id = db.Column("kind_id", db.Integer, db.ForeignKey("job_kind.id")) diff --git a/flaschengeist/system/models/user.py b/flaschengeist/system/models/user.py index d6a2f64..fa4bfe6 100644 --- a/flaschengeist/system/models/user.py +++ b/flaschengeist/system/models/user.py @@ -92,12 +92,8 @@ class User(db.Model, ModelSerializeMixin): def get_permissions(self): return ["user"] + [permission.name for role in self.roles for permission in role.permissions] - def has_permissions(self, permissions): - for role in self.roles: - for permission in role.permissions: - if permission.name in permissions: - return True - return False + def has_permission(self, permission): + return permission in self.get_permissions() class _UserAttribute(db.Model, ModelSerializeMixin): diff --git a/run_flaschengeist b/run_flaschengeist index 7942c54..db91492 100644 --- a/run_flaschengeist +++ b/run_flaschengeist @@ -1,11 +1,8 @@ #!/usr/bin/python3 import inspect import argparse -from datetime import datetime - import bjoern -import sqlalchemy -from sqlalchemy.orm import RelationshipProperty, ColumnProperty +import typing def install(arguments): @@ -36,12 +33,16 @@ def export(arguments): def pytype(cls): if isinstance(cls, list): - return "Array<{}>".format(pytype(cls[0])) - mapper = {"str": "string", "int": "number", "datetime": "Date"} - if cls.__name__ in mapper: - return mapper[cls.__name__] - else: - return cls.__name__ + return "", "Array<{}>".format(pytype(cls[0])[1]) + #if typing.get_origin(cls) is typing.Optional: + # return "?", pytype(typing.get_args(cls)[1]) + mapper = {"str": "string", "int": "number", "float": "number", "datetime": "Date"} + if hasattr(cls, "__name__"): + if cls.__name__ in mapper: + return "", mapper[cls.__name__] + else: + return "", cls.__name__ + return "?", "any" def walker(mod): if inspect.ismodule(mod[1]) and mod[1].__name__.startswith(models.__name__) and mod[1].__name__ not in known: @@ -58,7 +59,7 @@ def export(arguments): d = {param: pytype(ptype) for param, ptype in mod[1].__annotations__.items() if not param.startswith("_")} if len(d) == 1: key, value = d.popitem() - classes[mod[0]] = value + classes[mod[0]] = value[1] else: classes[mod[0]] = d @@ -68,14 +69,16 @@ def export(arguments): with app.app_context(): walker(("models", models)) with open(arguments.file, "w") as file: + file.write("declare namespace FG {\n") for cls, params in classes.items(): if isinstance(params, str): - file.write("type {} = {};\n".format(cls, params)) + file.write("\ttype {} = {};\n".format(cls, params)) else: - file.write("interface {} {{\n".format(cls)) + file.write("\tinterface {} {{\n".format(cls)) for name in params: - file.write(" {}: {};\n".format(name, params[name])) - file.write("}\n") + file.write("\t\t{}{}: {};\n".format(name, *params[name])) + file.write("\t}\n") + file.write("}\n") if __name__ == "__main__":