diff --git a/flaschengeist/plugins/schedule/__init__.py b/flaschengeist/plugins/schedule/__init__.py index 075775b..a4dcaa1 100644 --- a/flaschengeist/plugins/schedule/__init__.py +++ b/flaschengeist/plugins/schedule/__init__.py @@ -1,3 +1,7 @@ +"""Schedule plugin + +Provides duty schedule / duty roster functions +""" from dateutil import parser from datetime import datetime, timedelta from flask import Blueprint, request, jsonify @@ -7,8 +11,8 @@ from flaschengeist.database import db from flaschengeist.plugins import Plugin from flaschengeist.decorator import login_required -from .models import EventKind from . import event_controller, permissions +from .models import EventType schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule") @@ -21,32 +25,21 @@ class SchedulePlugin(Plugin): ) -#################################################################################### -# Routes # -# # -# /schedule/events POST: create new # -# GET: get all events this month # -# /schedule/events// GET: get events by month / date # -# /// # -# /schedule/events/ GET: get event by ID # -# DELETE: delete specified event # -# PUT: modify specified event # -# /schedule/events//slots GET: get EventSlots of Event # -# POST: add new EventSlot to Event # -# /schedule/events//slots/ PUT: modify EventSlot # -# GET: get specified EventSlot # -# /schedule/events//slots//jobs POST: add User # -# /schedule/eventKinds -# /schedule/eventKinds/ -# PUT: modify user # -# DELETE: remove user # -#################################################################################### - - -@schedule_bp.route("/events/", methods=["GET"]) +@schedule_bp.route("/events/", methods=["GET"]) @login_required() -def __get_event(eid, **kwargs): - event = event_controller.get_event(eid) +def get_event(event_id, current_session): + """Get event by id + + Route: ``/events/`` | Method: ``GET`` + + Args: + event_id: ID identifying the event + current_session: Session sent with Authorization Header + + Returns: + JSON encoded event object + """ + event = event_controller.get_event(event_id) if not event: raise NotFound return jsonify(event) @@ -87,8 +80,8 @@ def __get_events(year=datetime.now().year, month=datetime.now().month, day=None, raise BadRequest("Invalid date given") -@schedule_bp.route("/eventKinds", methods=["POST"]) -@login_required(permission=_permission_edit_type) +@schedule_bp.route("/event-types", methods=["POST"]) +@login_required(permission=permissions.EVENT_TYPE) def __new_event_kind(**kwargs): data = request.get_json() if "name" not in data: @@ -98,7 +91,7 @@ def __new_event_kind(**kwargs): @schedule_bp.route("/slotKinds", methods=["POST"]) -@login_required(permission=_permission_edit_type) +@login_required(permission=permissions.EVENT_TYPE) def __new_slot_kind(**kwargs): data = request.get_json() if not data or "name" not in data: @@ -108,20 +101,20 @@ def __new_slot_kind(**kwargs): @schedule_bp.route("/events", methods=["POST"]) -@login_required(permission=_permission_create) +@login_required(permission=permissions.CREATE) def __new_event(**kwargs): data = request.get_json() event = event_controller.create_event( begin=parser.isoparse(data["begin"]), end=parser.isoparse(data["end"]), description=data["description"], - kind=EventKind.query.get(data["kind"]), + type=EventType.query.get(data["kind"]), ) return jsonify({"ok": "ok", "id": event.id}) @schedule_bp.route("/events/", methods=["DELETE"]) -@login_required(permission=_permission_delete) +@login_required(permission=permissions.DELETE) def __delete_event(event_id, **kwargs): if not event_controller.delete_event(event_id): raise NotFound @@ -130,7 +123,7 @@ def __delete_event(event_id, **kwargs): @schedule_bp.route("/eventKinds/", methods=["PUT"]) -@login_required(permission=_permission_edit_type) +@login_required(permission=permissions.EVENT_TYPE) def __edit_event_kind(event_id, **kwargs): data = request.get_json() if not data or "name" not in data: @@ -158,7 +151,7 @@ def __get_slot(event_id, slot_id, **kwargs): @schedule_bp.route("/events//slots/", methods=["DELETE"]) -@login_required(permission=_permission_delete) +@login_required(permission=permissions.DELETE) def __delete_slot(event_id, slot_id, **kwargs): if event_controller.delete_event_slot(slot_id, event_id): return jsonify({"ok": "ok"}) @@ -166,7 +159,7 @@ def __delete_slot(event_id, slot_id, **kwargs): @schedule_bp.route("/events//slots/", methods=["PUT"]) -@login_required(permission=_permission_edit) +@login_required(permission=permissions.EDIT) def __update_slot(event_id, slot_id, **kwargs): data = request.get_json() if not data: @@ -180,7 +173,7 @@ def __update_slot(event_id, slot_id, **kwargs): @schedule_bp.route("/events//slots", methods=["POST"]) -@login_required(permission=_permission_edit) +@login_required(permission=permissions.EDIT) def __add_slot(event_id, **kwargs): event = event_controller.get_event(event_id) if not event: diff --git a/flaschengeist/plugins/schedule/models.py b/flaschengeist/plugins/schedule/models.py index 26d2988..a6792da 100644 --- a/flaschengeist/plugins/schedule/models.py +++ b/flaschengeist/plugins/schedule/models.py @@ -5,74 +5,82 @@ from flaschengeist.models import ModelSerializeMixin from flaschengeist.models.user import User from flaschengeist.database import db - -class EventSlot(db.Model, ModelSerializeMixin): - """Model for an EventSlot""" - - __tablename__ = "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("event_id", db.Integer, db.ForeignKey("event.id"), nullable=False) - _event = db.relationship("Event", back_populates="_slots") +######### +# Types # +######### -class EventKind(db.Model, ModelSerializeMixin): - """Model for an EventKind""" - - __tablename__ = "event_kind" +class EventType(db.Model, ModelSerializeMixin): + __tablename__ = "event_type" + id_: int = db.Column("id", db.Integer, primary_key=True) name: str = db.Column(db.String(30), nullable=False, unique=True) - _id: int = db.Column("id", db.Integer, primary_key=True) +class JobType(db.Model, ModelSerializeMixin): + __tablename__ = "job_type" + id_ = db.Column("id", db.Integer, primary_key=True) + name: str = db.Column(db.String(30), nullable=False, unique=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") +######## +# Jobs # +######## class Job(db.Model, ModelSerializeMixin): __tablename__ = "job" userid: str = None - value: float = db.Column(db.Numeric(precision=3, scale=2)) + value: float = db.Column(db.Numeric(precision=3, scale=2), nullable=False) - _id = db.Column("id", db.Integer, primary_key=True) - _user_id = db.Column("user_id", db.Integer, db.ForeignKey("user.id")) - _user: User = db.relationship("User") - _slot_id = db.Column("slot_id", db.Integer, db.ForeignKey("job_slot.id")) - _slot = db.relationship("JobSlot") + id_ = db.Column("id", db.Integer, primary_key=True) + _user_id = db.Column("user_id", db.Integer, db.ForeignKey("user.id"), nullable=False) + _slot_id = db.Column("slot_id", db.Integer, db.ForeignKey("job_slot.id"), nullable=False) + + user_: User = db.relationship("User") + slot_ = db.relationship("JobSlot") @property def userid(self): return self._user.userid -class JobKind(db.Model, ModelSerializeMixin): - __tablename__ = "job_kind" - name: str = db.Column(db.String(30), nullable=False, unique=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")) + _event_slot_id = db.Column("event_slot_id", db.Integer, db.ForeignKey("event_slot.id")) + + id: int = db.Column(db.Integer, primary_key=True) + type: JobType = db.relationship("JobKind") + users: [Job] = db.relationship("Job", back_populates="_slot") + required_jobs: float = db.Column(db.Numeric(precision=4, scale=2)) + + event_slot_ = db.relationship("EventSlot", back_populates="slots") + +########## +# Events # +########## + + +class EventSlot(db.Model, ModelSerializeMixin): + """Model for an EventSlot""" + __tablename__ = "event_slot" + _event_id = db.Column("event_id", db.Integer, db.ForeignKey("event.id"), nullable=False) + + id: int = db.Column(db.Integer, primary_key=True) + start: datetime = db.Column(db.DateTime) + end: Optional[datetime] = db.Column(db.DateTime) + jobs: [JobSlot] = db.relationship("JobSlot", back_populates="_event_slot") + + event_ = db.relationship("Event", back_populates="_slots") + + +class Event(db.Model, ModelSerializeMixin): + """Model for an Event""" + __tablename__ = "event" + _kind_id = db.Column("kind_id", db.Integer, db.ForeignKey("event_kind.id", ondelete="CASCADE"), nullable=False) + + 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)) + type: EventType = db.relationship("EventKind") + slots: [EventSlot] = db.relationship("EventSlot", back_populates="_event", cascade="all, delete")