277 lines
8.0 KiB
Python
277 lines
8.0 KiB
Python
from typing import TYPE_CHECKING
|
|
|
|
from sqlmodel import (
|
|
Session,
|
|
Relationship,
|
|
Field,
|
|
)
|
|
|
|
from . import mixin
|
|
from .base import (
|
|
BaseSQLModel,
|
|
DocumentedStrEnum,
|
|
DocumentedIntFlag,
|
|
DocumentedStrFlagType,
|
|
auto_enum,
|
|
RowId,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from .route import Route
|
|
from .team import Team
|
|
|
|
# region # Hike ################################################################
|
|
|
|
|
|
class HikeTeamPage(DocumentedIntFlag):
|
|
ROUTE = auto_enum() # Route steps info
|
|
QUESTIONS = auto_enum() # Visible questions
|
|
|
|
VISITED_PLACES = auto_enum() # Places the team has been
|
|
CURRENT_PLACE = auto_enum() # Place where the team currently is
|
|
UNVISITED_PLACES = auto_enum() # Places the team still neat to visit
|
|
|
|
PLACES = VISITED_PLACES | CURRENT_PLACE | UNVISITED_PLACES # All the places
|
|
|
|
TRAVEL_TIME = auto_enum() # Total travel time
|
|
TRAVEL_FREE_TIME = auto_enum() # Total travel time
|
|
PLACE_TIME = auto_enum() # Total place time
|
|
CALCULATE_TIME = auto_enum() # Total time calculated based on hike settings
|
|
# TODO: Think about time between oter teams
|
|
|
|
PLACE_POINTS = auto_enum() # Points scored on a place
|
|
TOTAL_PLACE_POINTS = auto_enum() # All points got on all places
|
|
ASSIST_POINTS = auto_enum() # Minus points for assistants
|
|
# TODO: Think about place in classement
|
|
|
|
ASSIST_LOG = auto_enum() # Assisted items
|
|
ASSIST_LATTER = auto_enum() # ???
|
|
|
|
|
|
# ##############################################################################
|
|
|
|
|
|
class HikeTimeCalculation(DocumentedIntFlag):
|
|
TRAVEL_TIME = auto_enum() # Time traveling
|
|
|
|
# TODO: Think about time groups (in this model we have 2, free and non free)
|
|
TRAVEL_FREE_TIME = auto_enum() # Time that is excluded from traveling but not at a place
|
|
PLACE_TIME = auto_enum() # Time checked in at a place
|
|
|
|
TOTAL_TIME = TRAVEL_TIME | TRAVEL_FREE_TIME | PLACE_TIME
|
|
|
|
|
|
# ##############################################################################
|
|
|
|
|
|
class HikeVisitLogType(DocumentedStrEnum):
|
|
FIRST_VISIT = auto_enum()
|
|
LAST_VISIT = auto_enum()
|
|
|
|
LONGEST_VISIT = auto_enum()
|
|
SHORTEST_VISIT = auto_enum()
|
|
|
|
EACH_VISIT = auto_enum()
|
|
|
|
DISABLE_VISIT_LOGING = auto_enum()
|
|
|
|
|
|
# ##############################################################################
|
|
|
|
|
|
class HikeBase(
|
|
mixin.Name,
|
|
mixin.Contact,
|
|
BaseSQLModel,
|
|
):
|
|
tracker_interval: int | None = Field(
|
|
default=None,
|
|
nullable=True,
|
|
description="Is GPS button available, value will be the interval",
|
|
)
|
|
|
|
is_multi_day: bool = Field(
|
|
default=False,
|
|
nullable=False,
|
|
description="Show datetime in stead of time only",
|
|
)
|
|
|
|
team_page: HikeTeamPage = Field(
|
|
default=HikeTeamPage.PLACES | HikeTeamPage.ROUTE | HikeTeamPage.QUESTIONS,
|
|
nullable=False,
|
|
description="Show all the places of the route inside the teams page",
|
|
sa_type=DocumentedStrFlagType(HikeTeamPage),
|
|
)
|
|
|
|
time_calculation: HikeTimeCalculation = Field(
|
|
default=HikeTimeCalculation.TRAVEL_TIME,
|
|
nullable=False,
|
|
description="Wath should we calculate inside the total time",
|
|
sa_type=DocumentedStrFlagType(HikeTimeCalculation),
|
|
)
|
|
|
|
visit_log_type: HikeVisitLogType = Field(
|
|
default=HikeVisitLogType.FIRST_VISIT,
|
|
nullable=False,
|
|
)
|
|
|
|
min_time_points: int | None = Field(
|
|
default=0,
|
|
ge=0,
|
|
# TODO: le: max_time_points
|
|
description="Min points for time",
|
|
)
|
|
|
|
max_time_points: int | None = Field(
|
|
default=100,
|
|
ge=0, # TODO: ge > min_time_points
|
|
description="Max points for time",
|
|
)
|
|
|
|
max_question_points: int | None = Field(
|
|
default=None,
|
|
description="None: Calculate from answers (no max), Positive: Set as max for dynamic range",
|
|
)
|
|
|
|
|
|
# Properties to receive via API on creation
|
|
class HikeCreate(HikeBase):
|
|
pass
|
|
|
|
|
|
# Properties to receive via API on update, all are optional
|
|
class HikeUpdate(HikeBase):
|
|
is_multi_day: bool | None = Field(default=None) # type: ignore
|
|
team_page: HikeTeamPage | None = Field(default=None) # type: ignore
|
|
time_calculation: HikeTimeCalculation | None = Field(default=None) # type: ignore
|
|
visit_log_type: HikeVisitLogType | None = Field(default=None) # type: ignore
|
|
|
|
|
|
class Hike(mixin.RowId, HikeBase, table=True):
|
|
# --- database only items --------------------------------------------------
|
|
|
|
# --- read only items ------------------------------------------------------
|
|
|
|
# --- back_populates links -------------------------------------------------
|
|
routes: list["Route"] = Relationship(back_populates="hike", cascade_delete=True)
|
|
teams: list["HikeTeamLink"] = Relationship(back_populates="hike", cascade_delete=True)
|
|
|
|
# --- CRUD actions ---------------------------------------------------------
|
|
@classmethod
|
|
def create(cls, *, session: Session, create_obj: HikeCreate) -> "Hike":
|
|
data_obj = create_obj.model_dump(exclude_unset=True)
|
|
|
|
db_obj = cls.model_validate(data_obj)
|
|
session.add(db_obj)
|
|
session.commit()
|
|
session.refresh(db_obj)
|
|
return db_obj
|
|
|
|
@classmethod
|
|
def update(
|
|
cls, *, session: Session, db_obj: "Hike", in_obj: HikeUpdate
|
|
) -> "Hike":
|
|
data_obj = in_obj.model_dump(exclude_unset=True)
|
|
db_obj.sqlmodel_update(data_obj)
|
|
session.add(db_obj)
|
|
session.commit()
|
|
session.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
# Properties to return via API, id is always required
|
|
class HikePublic(mixin.RowIdPublic, HikeBase):
|
|
pass
|
|
|
|
|
|
class HikesPublic(BaseSQLModel):
|
|
data: list[HikePublic]
|
|
count: int
|
|
|
|
|
|
# endregion
|
|
|
|
# region # Hike / Team #########################################################
|
|
|
|
class HikeTeamLinkBase(
|
|
BaseSQLModel,
|
|
):
|
|
hike_id: RowId = Field(
|
|
nullable=False,
|
|
foreign_key="hike.id",
|
|
)
|
|
|
|
team_id: RowId = Field(
|
|
nullable=False,
|
|
foreign_key="team.id",
|
|
)
|
|
|
|
route_id: RowId = Field(
|
|
nullable=False,
|
|
foreign_key="route.id",
|
|
)
|
|
|
|
start_place_id: RowId | None = Field(
|
|
default=None,
|
|
nullable=True,
|
|
foreign_key="place.id",
|
|
)
|
|
|
|
|
|
# Properties to receive via API on creation
|
|
class HikeTeamLinkCreate(HikeTeamLinkBase):
|
|
pass
|
|
|
|
|
|
# Properties to receive via API on update, all are optional
|
|
class HikeTeamLinkUpdate(HikeTeamLinkBase):
|
|
hike_id: RowId | None = Field(default=None, nullable=True) # type: ignore
|
|
team_id: RowId | None = Field(default=None, nullable=True) # type: ignore
|
|
route_id: RowId | None = Field(default=None, nullable=True) # type: ignore
|
|
|
|
|
|
class HikeTeamLink(mixin.RowId, HikeTeamLinkBase, table=True):
|
|
# --- database only items --------------------------------------------------
|
|
|
|
# --- read only items ------------------------------------------------------
|
|
|
|
# --- back_populates links -------------------------------------------------
|
|
team: "Team" = Relationship(back_populates="hike_links")
|
|
hike: "Hike" = Relationship(back_populates="teams")
|
|
route: "Route" = Relationship(back_populates="teams")
|
|
# start_place: "Place" = Relationship(back_populates="teams")
|
|
|
|
# --- CRUD actions ---------------------------------------------------------
|
|
@classmethod
|
|
def create(cls, *, session: Session, create_obj: HikeTeamLinkCreate) -> "HikeTeamLink":
|
|
data_obj = create_obj.model_dump(exclude_unset=True)
|
|
|
|
db_obj = cls.model_validate(data_obj)
|
|
session.add(db_obj)
|
|
session.commit()
|
|
session.refresh(db_obj)
|
|
return db_obj
|
|
|
|
@classmethod
|
|
def update(
|
|
cls, *, session: Session, db_obj: "HikeTeamLink", in_obj: HikeTeamLinkUpdate
|
|
) -> "HikeTeamLink":
|
|
data_obj = in_obj.model_dump(exclude_unset=True)
|
|
db_obj.sqlmodel_update(data_obj)
|
|
session.add(db_obj)
|
|
session.commit()
|
|
session.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
# Properties to return via API, id is always required
|
|
class HikeTeamLinkPublic(mixin.RowIdPublic, HikeTeamLinkBase):
|
|
pass
|
|
|
|
|
|
class HikeTeamLinksPublic(BaseSQLModel):
|
|
data: list[HikeTeamLinkPublic]
|
|
count: int
|
|
|
|
# endregion
|