From ea030e012d0aef7333998361fcd4a6a3d7e4c04d Mon Sep 17 00:00:00 2001 From: HumanoidSandvichDispenser Date: Wed, 20 Nov 2024 15:12:44 -0800 Subject: [PATCH] Add event management endpoints - Implemented endpoints for creating, retrieving, and managing events. - Added `EventSchema` for event serialization and deserialization. - Updated `Event` model to include relationships with `PlayerEvent` and `Team`. - Modified `Player` and `Team` models to include relationships with `Event`. - Added new file `events.py` to handle event-related API routes. --- backend-flask/events.py | 117 +++++++++++++++++++++++++++++++++ backend-flask/models/event.py | 24 ++++++- backend-flask/models/player.py | 2 + backend-flask/models/team.py | 2 + 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 backend-flask/events.py diff --git a/backend-flask/events.py b/backend-flask/events.py new file mode 100644 index 0000000..ca09fff --- /dev/null +++ b/backend-flask/events.py @@ -0,0 +1,117 @@ +#! /usr/bin/env python3 +# vim:fenc=utf-8 +# +# Copyright © 2024 sandvich +# +# Distributed under terms of the MIT license. + + +from datetime import datetime + +from flask import Blueprint, abort +from spectree import Response +from models.player_event import PlayerEvent +from models.player import Player +from spec import BaseModel, spec +from middleware import assert_team_authority, requires_authentication, requires_team_membership +from models.event import Event, EventSchema +from models.player_team import PlayerTeam +from app_db import db + + +api_events = Blueprint("events", __name__, url_prefix="/events") + +@api_events.get("/") +@spec.validate( + resp=Response( + HTTP_200=EventSchema, + ), + operation_id="get_event", +) +def get_event(event_id: int): + event = db.session.query(Event).filter(Event.id == event_id).one_or_none() + + if not event: + abort(404) + + return EventSchema.from_model(event).dict(by_alias=True) + +@api_events.get("/team/id/") +@spec.validate( + resp=Response( + HTTP_200=list[EventSchema], + ), + operation_id="get_team_events", +) +def get_team_events(team_id: int): + events = db.session.query( + Event + ).filter( + Event.team_id == team_id + ).all() + + def map_to_schema(event: Event): + return EventSchema.from_model(event).dict(by_alias=True) + + return list(map(map_to_schema, events)) + +@api_events.get("/user/id/") +def get_user_events(user_id: int): + raise NotImplementedError() + +class CreateEventJson(BaseModel): + name: str + description: str + start_time: datetime + player_ids: list[int] + +@api_events.post("/team/id/") +@spec.validate( + resp=Response( + HTTP_200=EventSchema, + ) +) +@requires_authentication +@requires_team_membership +def create_event(player_team: PlayerTeam, json: CreateEventJson, **_): + event = Event() + event.team_id = player_team.team_id + event.name = json.name + event.description = json.description + event.start_time = json.start_time + + db.session.add(event) + db.session.flush() + db.session.refresh(event) + + players_teams = db.session.query( + PlayerTeam + ).join( + Player + ).where( + PlayerTeam.team_id == player_team.team_id + ).where( + PlayerTeam.player_id.in_(json.player_ids) + ).all() + + for player_team in players_teams: + player = player_team.player + player_event = PlayerEvent() + player_event.player_id = player.steam_id + player_event.event_id = event.id + db.session.add(player_event) + + db.session.commit() + + return EventSchema.from_model(event).dict(by_alias=True), 200 + +@api_events.patch("//players") +@requires_authentication +@requires_team_membership +def set_event_players(player_team: PlayerTeam, event_id: int, **_): + assert_team_authority(player_team, None) + + # merge players into event + db.session.query(Event).filter(Event.id == event_id).update({"players": []}) + + raise NotImplementedError() diff --git a/backend-flask/models/event.py b/backend-flask/models/event.py index f35c82f..ac4919c 100644 --- a/backend-flask/models/event.py +++ b/backend-flask/models/event.py @@ -1,10 +1,12 @@ from datetime import datetime from sqlalchemy.orm import mapped_column, relationship from sqlalchemy.orm.attributes import Mapped +from sqlalchemy.orm.properties import ForeignKey from sqlalchemy.types import TIMESTAMP, Integer, String, Text from sqlalchemy.sql import func from sqlalchemy_utc import UtcDateTime import app_db +import spec class Event(app_db.BaseModel): @@ -14,10 +16,30 @@ class Event(app_db.BaseModel): name: Mapped[str] = mapped_column(String(255), nullable=False) description: Mapped[str] = mapped_column(Text, nullable=True) start_time: Mapped[datetime] = mapped_column(UtcDateTime, nullable=False) - team_id: Mapped[int] = mapped_column(Integer, nullable=False) + team_id: Mapped[int] = mapped_column(ForeignKey("teams.id"), nullable=False) created_at: Mapped[datetime] = mapped_column(TIMESTAMP, server_default=func.now()) team: Mapped["Team"] = relationship("Team", back_populates="events") + players: Mapped["PlayerEvent"] = relationship("PlayerEvent", back_populates="event") +class EventSchema(spec.BaseModel): + id: int + team_id: int + name: str + description: str + start_time: datetime + created_at: datetime + + @classmethod + def from_model(cls, model: Event) -> "EventSchema": + return cls( + id=model.id, + name=model.name, + description=model.description, + start_time=model.start_time, + team_id=model.team_id, + created_at=model.created_at, + ) from models.team import Team +from models.player_event import PlayerEvent diff --git a/backend-flask/models/player.py b/backend-flask/models/player.py index 8e42c71..358b1a5 100644 --- a/backend-flask/models/player.py +++ b/backend-flask/models/player.py @@ -15,6 +15,7 @@ class Player(app_db.BaseModel): teams: Mapped[list["PlayerTeam"]] = relationship(back_populates="player") auth_sessions: Mapped[list["AuthSession"]] = relationship(back_populates="player") + events: Mapped[list["PlayerEvent"]] = relationship(back_populates="player") created_at: Mapped[datetime] = mapped_column(TIMESTAMP, server_default=func.now()) @@ -28,4 +29,5 @@ class PlayerSchema(spec.BaseModel): from models.auth_session import AuthSession +from models.player_event import PlayerEvent from models.player_team import PlayerTeam diff --git a/backend-flask/models/team.py b/backend-flask/models/team.py index cce26f0..c4e4389 100644 --- a/backend-flask/models/team.py +++ b/backend-flask/models/team.py @@ -19,6 +19,7 @@ class Team(app_db.BaseModel): players: Mapped[list["PlayerTeam"]] = relationship(back_populates="team") invites: Mapped[list["TeamInvite"]] = relationship(back_populates="team") integrations: Mapped[list["TeamIntegration"]] = relationship(back_populates="team") + events: Mapped[list["Event"]] = relationship(back_populates="team") created_at: Mapped[datetime] = mapped_column(TIMESTAMP, server_default=func.now()) @@ -42,3 +43,4 @@ class TeamSchema(spec.BaseModel): from models.player_team import PlayerTeam from models.team_integration import TeamIntegration from models.team_invite import TeamInvite +from models.event import Event