From 5d422a98638ad4ea98079a6a1eab2069def4ca35 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sat, 23 May 2026 01:49:17 +0200 Subject: [PATCH] migrate seaing plan --- src/elm/components/SeatingPlan.py | 179 ++++++++++++++++++++++++ src/elm/components/SeatingPlanPixels.py | 138 ++++++++++++++++++ src/elm/components/__init__.py | 2 + src/elm/pages/SeatInfoPage.py | 129 +++++++++++++++++ src/elm/pages/SeatingPlanPage.py | 29 ++++ src/elm/services/DatabaseService.py | 4 +- src/elm/types/Seat.py | 15 ++ src/elm/types/__init__.py | 1 + 8 files changed, 495 insertions(+), 2 deletions(-) create mode 100644 src/elm/components/SeatingPlan.py create mode 100644 src/elm/components/SeatingPlanPixels.py create mode 100644 src/elm/pages/SeatInfoPage.py create mode 100644 src/elm/pages/SeatingPlanPage.py create mode 100644 src/elm/types/Seat.py diff --git a/src/elm/components/SeatingPlan.py b/src/elm/components/SeatingPlan.py new file mode 100644 index 0000000..1de2369 --- /dev/null +++ b/src/elm/components/SeatingPlan.py @@ -0,0 +1,179 @@ +from typing import Optional + +from rio import Component, Rectangle, Grid, Column, Row, Text, TextStyle, Color, Spacer + +from elm.components import SeatPixel, WallPixel, TextPixel +from elm.types import Seat + +MAX_GRID_WIDTH_PIXELS = 70 +MAX_GRID_HEIGHT_PIXELS = 60 + +class SeatingPlan(Component): + preloaded_seats: list[Seat] + + def get_seat(self, seat_id: str) -> Optional[Seat]: + return next(filter(lambda x: x.seat_id == seat_id, self.preloaded_seats), None) + + """ + This seating plan is for the community center "Donsbach" + """ + def build(self) -> Component: + grid = Grid() + # Outlines + for x in range(0, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=0, column=x) + + for y in range(0, MAX_GRID_HEIGHT_PIXELS): + grid.add(WallPixel(), row=y, column=0) + + for x in range(0, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=MAX_GRID_HEIGHT_PIXELS, column=x) + + for x in range(0, 41): + grid.add(WallPixel(), row=15, column=x) + + for x in range(51, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=32, column=x) + + for x in range(41, 44): + grid.add(WallPixel(), row=32, column=x) + grid.add(WallPixel(), row=19, column=x) + + for x in range(52, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=11, column=x) + grid.add(WallPixel(), row=22, column=x) + + for x in range(32, 40): + grid.add(WallPixel(), row=5, column=x) + grid.add(WallPixel(), row=10, column=x) + + + for y in range(5, 11): + grid.add(WallPixel(), row=y, column=31) + grid.add(WallPixel(), row=y, column=40) + + for y in range(40, MAX_GRID_HEIGHT_PIXELS): + grid.add(WallPixel(), row=y, column=40) + + for y in range(32, 36): + grid.add(WallPixel(), row=y, column=40) + + for y in range(19, 33): + grid.add(WallPixel(), row=y, column=44) + + for y in range(16, 20): + grid.add(WallPixel(), row=y, column=40) + + for y in range(0, 5): + grid.add(WallPixel(), row=y, column=51) + + for y in range(9, 15): + grid.add(WallPixel(), row=y, column=51) + + for y in range(19, 33): + grid.add(WallPixel(), row=y, column=51) + + + # Block A + grid.add(SeatPixel("A01", seat=self.get_seat("A01"), seat_orientation="bottom"), row=57, column=1, width=5, height=2) + grid.add(SeatPixel("A02", seat=self.get_seat("A02"), seat_orientation="bottom"), row=57, column=6, width=5, height=2) + grid.add(SeatPixel("A03", seat=self.get_seat("A03"), seat_orientation="bottom"), row=57, column=11, width=5, height=2) + grid.add(SeatPixel("A04", seat=self.get_seat("A04"), seat_orientation="bottom"), row=57, column=16, width=5, height=2) + grid.add(SeatPixel("A05", seat=self.get_seat("A05"), seat_orientation="bottom"), row=57, column=21, width=5, height=2) + + grid.add(SeatPixel("A10", seat=self.get_seat("A10"), seat_orientation="top"), row=55, column=1, width=5, height=2) + grid.add(SeatPixel("A11", seat=self.get_seat("A11"), seat_orientation="top"), row=55, column=6, width=5, height=2) + grid.add(SeatPixel("A12", seat=self.get_seat("A12"), seat_orientation="top"), row=55, column=11, width=5, height=2) + grid.add(SeatPixel("A13", seat=self.get_seat("A13"), seat_orientation="top"), row=55, column=16, width=5, height=2) + grid.add(SeatPixel("A14", seat=self.get_seat("A14"), seat_orientation="top"), row=55, column=21, width=5, height=2) + + # Block B + grid.add(SeatPixel("B01", seat=self.get_seat("B01"), seat_orientation="bottom"), row=50, column=1, width=3, height=2) + grid.add(SeatPixel("B02", seat=self.get_seat("B02"), seat_orientation="bottom"), row=50, column=4, width=3, height=2) + grid.add(SeatPixel("B03", seat=self.get_seat("B03"), seat_orientation="bottom"), row=50, column=7, width=3, height=2) + grid.add(SeatPixel("B04", seat=self.get_seat("B04"), seat_orientation="bottom"), row=50, column=10, width=3, height=2) + grid.add(SeatPixel("B05", seat=self.get_seat("B05"), seat_orientation="bottom"), row=50, column=13, width=3, height=2) + grid.add(SeatPixel("B06", seat=self.get_seat("B06"), seat_orientation="bottom"), row=50, column=16, width=3, height=2) + grid.add(SeatPixel("B07", seat=self.get_seat("B07"), seat_orientation="bottom"), row=50, column=19, width=3, height=2) + grid.add(SeatPixel("B08", seat=self.get_seat("B08"), seat_orientation="bottom"), row=50, column=22, width=3, height=2) + + grid.add(SeatPixel("B10", seat=self.get_seat("B10"), seat_orientation="top"), row=48, column=1, width=3, height=2) + grid.add(SeatPixel("B11", seat=self.get_seat("B11"), seat_orientation="top"), row=48, column=4, width=3, height=2) + grid.add(SeatPixel("B12", seat=self.get_seat("B12"), seat_orientation="top"), row=48, column=7, width=3, height=2) + grid.add(SeatPixel("B13", seat=self.get_seat("B13"), seat_orientation="top"), row=48, column=10, width=3, height=2) + grid.add(SeatPixel("B14", seat=self.get_seat("B14"), seat_orientation="top"), row=48, column=13, width=3, height=2) + grid.add(SeatPixel("B15", seat=self.get_seat("B15"), seat_orientation="top"), row=48, column=16, width=3, height=2) + grid.add(SeatPixel("B16", seat=self.get_seat("B16"), seat_orientation="top"), row=48, column=19, width=3, height=2) + grid.add(SeatPixel("B17", seat=self.get_seat("B17"), seat_orientation="top"), row=48, column=22, width=3, height=2) + + # Block C + grid.add(SeatPixel("C01", seat=self.get_seat("C01"), seat_orientation="bottom"), row=43, column=1, width=3, height=2) + grid.add(SeatPixel("C02", seat=self.get_seat("C02"), seat_orientation="bottom"), row=43, column=4, width=3, height=2) + grid.add(SeatPixel("C03", seat=self.get_seat("C03"), seat_orientation="bottom"), row=43, column=7, width=3, height=2) + grid.add(SeatPixel("C04", seat=self.get_seat("C04"), seat_orientation="bottom"), row=43, column=10, width=3, height=2) + grid.add(SeatPixel("C05", seat=self.get_seat("C05"), seat_orientation="bottom"), row=43, column=13, width=3, height=2) + grid.add(SeatPixel("C06", seat=self.get_seat("C06"), seat_orientation="bottom"), row=43, column=16, width=3, height=2) + grid.add(SeatPixel("C07", seat=self.get_seat("C07"), seat_orientation="bottom"), row=43, column=19, width=3, height=2) + grid.add(SeatPixel("C08", seat=self.get_seat("C08"), seat_orientation="bottom"), row=43, column=22, width=3, height=2) + + + grid.add(SeatPixel("C10", seat=self.get_seat("C10"), seat_orientation="top"), row=41, column=1, width=3, height=2) + grid.add(SeatPixel("C11", seat=self.get_seat("C11"), seat_orientation="top"), row=41, column=4, width=3, height=2) + grid.add(SeatPixel("C12", seat=self.get_seat("C12"), seat_orientation="top"), row=41, column=7, width=3, height=2) + grid.add(SeatPixel("C13", seat=self.get_seat("C13"), seat_orientation="top"), row=41, column=10, width=3, height=2) + grid.add(SeatPixel("C14", seat=self.get_seat("C14"), seat_orientation="top"), row=41, column=13, width=3, height=2) + grid.add(SeatPixel("C15", seat=self.get_seat("C15"), seat_orientation="top"), row=41, column=16, width=3, height=2) + grid.add(SeatPixel("C16", seat=self.get_seat("C16"), seat_orientation="top"), row=41, column=19, width=3, height=2) + grid.add(SeatPixel("C17", seat=self.get_seat("C17"), seat_orientation="top"), row=41, column=22, width=3, height=2) + + # Block D + grid.add(SeatPixel("D01", seat=self.get_seat("D01"), seat_orientation="bottom"), row=34, column=1, width=5, height=2) + grid.add(SeatPixel("D02", seat=self.get_seat("D02"), seat_orientation="bottom"), row=34, column=6, width=5, height=2) + grid.add(SeatPixel("D03", seat=self.get_seat("D03"), seat_orientation="bottom"), row=34, column=11, width=5, height=2) + grid.add(SeatPixel("D04", seat=self.get_seat("D04"), seat_orientation="bottom"), row=34, column=16, width=5, height=2) + grid.add(SeatPixel("D05", seat=self.get_seat("D05"), seat_orientation="bottom"), row=34, column=21, width=5, height=2) + + grid.add(SeatPixel("D10", seat=self.get_seat("D10"), seat_orientation="top"), row=32, column=1, width=5, height=2) + grid.add(SeatPixel("D11", seat=self.get_seat("D11"), seat_orientation="top"), row=32, column=6, width=5, height=2) + grid.add(SeatPixel("D12", seat=self.get_seat("D12"), seat_orientation="top"), row=32, column=11, width=5, height=2) + grid.add(SeatPixel("D13", seat=self.get_seat("D13"), seat_orientation="top"), row=32, column=16, width=5, height=2) + grid.add(SeatPixel("D14", seat=self.get_seat("D14"), seat_orientation="top"), row=32, column=21, width=5, height=2) + + # Block E + grid.add(SeatPixel("E01", seat=self.get_seat("E01"), seat_orientation="bottom"), row=27, column=1, width=5, height=2) + grid.add(SeatPixel("E02", seat=self.get_seat("E02"), seat_orientation="bottom"), row=27, column=6, width=5, height=2) + grid.add(SeatPixel("E03", seat=self.get_seat("E03"), seat_orientation="bottom"), row=27, column=11, width=5, height=2) + grid.add(SeatPixel("E04", seat=self.get_seat("E04"), seat_orientation="bottom"), row=27, column=16, width=5, height=2) + grid.add(SeatPixel("E05", seat=self.get_seat("E05"), seat_orientation="bottom"), row=27, column=21, width=5, height=2) + + grid.add(SeatPixel("E10", seat=self.get_seat("E10"), seat_orientation="top"), row=25, column=1, width=5, height=2) + grid.add(SeatPixel("E11", seat=self.get_seat("E11"), seat_orientation="top"), row=25, column=6, width=5, height=2) + grid.add(SeatPixel("E12", seat=self.get_seat("E12"), seat_orientation="top"), row=25, column=11, width=5, height=2) + grid.add(SeatPixel("E13", seat=self.get_seat("E13"), seat_orientation="top"), row=25, column=16, width=5, height=2) + grid.add(SeatPixel("E14", seat=self.get_seat("E14"), seat_orientation="top"), row=25, column=21, width=5, height=2) + + # Orga Block + grid.add(SeatPixel("Z01", seat=self.get_seat("Z01"), seat_orientation="top"), row=40, column=35, width=4, height=2) + grid.add(SeatPixel("Z02", seat=self.get_seat("Z02"), seat_orientation="top"), row=40, column=31, width=4, height=2) + grid.add(SeatPixel("Z\n0\n3", seat=self.get_seat("Z03"), seat_orientation="top"), row=40, column=29, width=2, height=6) + grid.add(SeatPixel("Z\n0\n4", seat=self.get_seat("Z04"), seat_orientation="bottom"), row=46, column=29, width=2, height=6) + grid.add(SeatPixel("Z05", seat=self.get_seat("Z05"), seat_orientation="bottom"), row=50, column=31, width=4, height=2) + grid.add(SeatPixel("Z06", seat=self.get_seat("Z06"), seat_orientation="bottom"), row=50, column=35, width=5, height=2) + + # Stage + grid.add(TextPixel(text="Bühne"), row=16, column=1, width=39, height=4) + + # Drinks + grid.add(TextPixel(text="G\ne\nt\nr\nä\nn\nk\ne"), row=20, column=40, width=4, height=12) + + # Main Entrance + grid.add(TextPixel(text="H\na\nl\nl\ne\nn\n\nE\ni\nn\ng\na\nn\ng"), row=33, column=66, width=4, height=27) + + # Sleeping + grid.add(TextPixel(icon_name="material/bed"), row=1, column=1, width=30, height=14) + + # Toilet + grid.add(TextPixel(icon_name="material/wc"), row=1, column=52, width=19, height=10) + grid.add(TextPixel(icon_name="material/wc"), row=12, column=52, width=19, height=10) + + return grid diff --git a/src/elm/components/SeatingPlanPixels.py b/src/elm/components/SeatingPlanPixels.py new file mode 100644 index 0000000..552be8b --- /dev/null +++ b/src/elm/components/SeatingPlanPixels.py @@ -0,0 +1,138 @@ +from rio import Component, Text, Icon, TextStyle, Rectangle, Spacer, Color, PointerEventListener, Row, PointerEvent, Tooltip +from typing import Optional, Literal + +from rio.event import on_populate + +from elm.types import Seat, UserSession, User + + +class SeatPixel(Component): + seat_id: str + seat_orientation: Literal["top", "bottom"] + seat: Optional[Seat] = None + associated_user: Optional[User] = None + + @on_populate + async def on_populate(self) -> None: + if self.seat is None: + self.seat = await Seat.find_one(Seat.seat_id == self.seat_id.replace("\n", ""), fetch_links=True) + if self.seat and self.seat.user is not None: + self.associated_user = await self.seat.user.fetch() + + async def on_press(self, _: PointerEvent) -> None: + self.session.navigate_to(f"./seat-info?seat_id={self.seat_id.replace("\n", "")}") + + def determine_color(self) -> Color: + if self.seat is not None: + try: + user_name = self.session[UserSession].user_name + except KeyError: + user_name = None + + if self.seat.user is not None and self.associated_user and self.associated_user.user_name == user_name: + return Color.from_hex("800080") + elif self.seat.is_blocked or self.seat.user is not None: + return self.session.theme.danger_color + return self.session.theme.success_color + return self.session.theme.success_color + + def build(self) -> Component: + if self.seat is None: + return Spacer() + text = Text(f"{self.seat_id}", style=TextStyle(fill=Color.BLACK, font_size=0.9), align_x=0.5, selectable=False) + rec = Rectangle( + content=Row(text), + min_width=1, + min_height=1, + fill=self.determine_color(), + stroke_width=0.1, + hover_stroke_width=0.1, + stroke_color=Color.BLACK, + grow_x=True, + grow_y=True, + hover_fill=self.session.theme.hud_color, + transition_time=0.4, + ripple=True + ) + + if self.associated_user or self.seat.is_blocked: + return PointerEventListener( + content=Tooltip( + anchor=rec, + tip=self.associated_user.user_name if self.associated_user else "Gesperrt", + position=self.seat_orientation, + ), + on_press=self.on_press, + ) + else: + return PointerEventListener( + content=rec, + on_press=self.on_press, + ) + + +class TextPixel(Component): + text: Optional[str] = None + icon_name: Optional[str] = None + no_outline: bool = False + + def build(self) -> Component: + if self.text is not None: + content = Text(self.text, style=TextStyle(fill=self.session.theme.text_color, font_size=1), align_x=0.5, selectable=False) + elif self.icon_name is not None: + content = Icon(self.icon_name, fill=self.session.theme.text_color) + else: + content = None + return Rectangle( + content=content, + min_width=1, + min_height=1, + fill=self.session.theme.background_color, + stroke_width=0.0 if self.no_outline else 0.1, + stroke_color=self.session.theme.neutral_color, + hover_stroke_width=None if self.no_outline else 0.1, + grow_x=True, + grow_y=True, + hover_fill=None, + ripple=True + ) + + +class WallPixel(Component): + def build(self) -> Component: + return Rectangle( + min_width=1, + min_height=1, + fill=Color.from_hex("434343"), + grow_x=True, + grow_y=True, + ) + + +class DebugPixel(Component): + def build(self) -> Component: + return Rectangle( + content=Spacer(), + min_width=1, + min_height=1, + fill=self.session.theme.success_color, + hover_stroke_color=self.session.theme.hud_color, + hover_stroke_width=0.1, + grow_x=True, + grow_y=True, + hover_fill=self.session.theme.secondary_color, + transition_time=0.1 + ) + + +class InvisiblePixel(Component): + def build(self) -> Component: + return Rectangle( + content=Spacer(), + min_width=1, + min_height=1, + fill=Color.TRANSPARENT, + hover_stroke_width=0.0, + grow_x=True, + grow_y=True + ) diff --git a/src/elm/components/__init__.py b/src/elm/components/__init__.py index cee3f1a..3d6b0c3 100644 --- a/src/elm/components/__init__.py +++ b/src/elm/components/__init__.py @@ -7,3 +7,5 @@ from .AvatarEditBox import AvatarEditBox from .AccountInfoBox import AccountInfoBox from .PersonalInfoBox import PersonalInfoBox from .BuyTicketBox import BuyTicketBox +from .SeatingPlanPixels import * +from .SeatingPlan import * diff --git a/src/elm/pages/SeatInfoPage.py b/src/elm/pages/SeatInfoPage.py new file mode 100644 index 0000000..e540798 --- /dev/null +++ b/src/elm/pages/SeatInfoPage.py @@ -0,0 +1,129 @@ +from __future__ import annotations + +from typing import Optional + +from bson import ObjectId +from rio import Component, page, Rectangle, ProgressCircle, Row, QueryParameter, Column, Text, Spacer +from rio.event import on_populate + +from elm import UserSession +from elm.components import ElmButton +from elm.types import Seat, User, Ticket + + +@page(name="Seat Info", url_segment="seat-info") +class SeatInfoPage(Component): + seat_id: QueryParameter[str] = "" + seat: Optional[Seat] = None + seat_user: Optional[User] = None + initial_load_done: bool = False + choosing_button_loading: bool = False + message: str = "" + message_is_error: bool = False + + @on_populate + async def on_populate(self) -> None: + self.seat = await Seat.find_one(Seat.seat_id == self.seat_id) + if self.seat and self.seat.user is not None: + self.seat_user = await self.seat.user.fetch() + self.initial_load_done = True + + async def choose_seat(self) -> None: + self.choosing_button_loading = True + try: + user_name = self.session[UserSession].user_name + except KeyError: + self.session.navigate_to("./login") + return + + user = await User.find_one(User.user_name == user_name) + if not user: + return + + user_ticket = await Ticket.find_one( + {"owner.$id": ObjectId(user.id)} + ) + + if not user_ticket or user_ticket.category != self.seat.category: + self.message = "Du hast nicht das passende Ticket" + self.message_is_error = True + self.choosing_button_loading = False + return + + user_seat = await Seat.find_one( + {"user.$id": ObjectId(user.id)} + ) + + if user_seat is not None: + self.message = "Du hast bereits einen Sitzplatz" + self.message_is_error = True + self.choosing_button_loading = False + return + + s = await Seat.find_one(Seat.seat_id == self.seat_id) + if not s: + return + s.user = user + await s.save() + self.message = "Sitzplatz gewählt!" + self.message_is_error = False + self.choosing_button_loading = False + + def build(self) -> Component: + if not self.initial_load_done: + box_contents = [ProgressCircle(margin=1)] + else: + if self.seat is None: + box_contents = [Text(text="Der angeforderte Sitzplatz konnte nicht gefunden werden", margin=1, overflow="wrap", justify="center", fill=self.session.theme.danger_color)] + else: + box_contents = [ + Row( + Text(text="Kategorie:", justify="left"), + Text(text=self.seat.category, justify="right"), + spacing=1 + ), + Row( + Text(text="Belegt:", justify="left"), + Text(text="Ja" if self.seat.user is not None or self.seat.is_blocked else "Nein", justify="right", fill=self.session.theme.danger_color if self.seat.user is not None or self.seat.is_blocked else self.session.theme.success_color), + spacing=1 + ), + Row( + Text(text="Nutzer:", justify="left"), + Text(text=self.seat_user.user_name if self.seat_user else "-", justify="right"), + spacing=1 + ), + ] + if not self.seat.is_blocked and self.seat.user is None: + box_contents.append( + ElmButton(text="Platz wählen", on_press=self.choose_seat, is_loading=self.choosing_button_loading) + ) + box_contents.append( + Text(text=self.message, fill=self.session.theme.danger_color if self.message_is_error else self.session.theme.success_color, overflow="wrap", justify="center") + ) + + return Row( + Rectangle( + content=Column( + Rectangle( + content=Rectangle( + content=Text(f"Sitzplatz: {self.seat_id}", margin=0.5, selectable=False), + fill=self.session.theme.header_box_background_color, + margin=0.4 + ), + stroke_width=0.1, + stroke_color=self.session.theme.box_border_color, + ), + Column( + *box_contents, + margin=1, + spacing=1 + ), + Spacer() + ), + fill=self.session.theme.box_color, + stroke_width=0.1, + stroke_color=self.session.theme.box_border_color + ), + align_x=0.5, + align_y=0.5 + ) diff --git a/src/elm/pages/SeatingPlanPage.py b/src/elm/pages/SeatingPlanPage.py new file mode 100644 index 0000000..0ea3bd7 --- /dev/null +++ b/src/elm/pages/SeatingPlanPage.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from typing import Optional + +from rio import Component, page, Rectangle, PointerEvent, ProgressCircle, Row +from rio.event import on_populate + +from elm.components import SeatingPlan +from elm.types import Seat + + +@page(name="Seating Plan", url_segment="seating") +class SeatingPlanPage(Component): + preloaded_seats: Optional[list[Seat]] = None + + @on_populate + async def on_populate(self) -> None: + self.preloaded_seats = await Seat.find_all().to_list() + + + def build(self) -> Component: + return Rectangle( + content=Row(ProgressCircle(), margin=self.session.screen_width // 6) if self.preloaded_seats is None else SeatingPlan(margin=0, preloaded_seats=self.preloaded_seats), + fill=self.session.theme.box_color, + stroke_width = 0.1, + stroke_color = self.session.theme.box_border_color, + margin_left=1, + margin_top=1 + ) diff --git a/src/elm/services/DatabaseService.py b/src/elm/services/DatabaseService.py index 90a53ca..ebfe018 100644 --- a/src/elm/services/DatabaseService.py +++ b/src/elm/services/DatabaseService.py @@ -4,7 +4,7 @@ from beanie import init_beanie from pymongo import AsyncMongoClient from pymongo.asynchronous.collection import AsyncCollection -from elm.types import User, Transaction, Ticket +from elm.types import User, Transaction, Ticket, Seat from elm.types.ConfigurationTypes import DatabaseConfiguration logger = logging.getLogger(__name__.split(".")[-1]) @@ -33,5 +33,5 @@ class DatabaseService: self._users: AsyncCollection = self._database["users"] await init_beanie( database=self._database, - document_models=[User, Transaction, Ticket] + document_models=[User, Transaction, Ticket, Seat] ) diff --git a/src/elm/types/Seat.py b/src/elm/types/Seat.py new file mode 100644 index 0000000..793e8aa --- /dev/null +++ b/src/elm/types/Seat.py @@ -0,0 +1,15 @@ +from typing import Optional + +from beanie import Document, Link + +from elm.types import User + + +class Seat(Document): + seat_id: str + is_blocked: bool + category: str + user: Optional[Link[User]] = None + + class Settings: + name = "seats" diff --git a/src/elm/types/__init__.py b/src/elm/types/__init__.py index 4ea67dd..0d0373f 100644 --- a/src/elm/types/__init__.py +++ b/src/elm/types/__init__.py @@ -3,3 +3,4 @@ from .UserSession import UserSession from .ConfigurationTypes import * from .Transaction import Transaction from .Ticket import Ticket, TicketState +from .Seat import Seat