Implement basic hike functions

This commit is contained in:
Sebastiaan
2025-10-24 17:48:02 +02:00
parent f958856e95
commit 23d7d63103
8 changed files with 514 additions and 0 deletions

181
backend/app/models/hike.py Normal file
View File

@@ -0,0 +1,181 @@
from typing import TYPE_CHECKING
from sqlmodel import (
Session,
Relationship,
Field,
)
from . import mixin
from .base import (
BaseSQLModel,
DocumentedStrEnum,
DocumentedIntFlag,
DocumentedStrFlagType,
auto_enum,
)
if TYPE_CHECKING:
from .event import Event
# 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 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),
)
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
class Hike(mixin.RowId, HikeBase, table=True):
# --- database only items --------------------------------------------------
# --- read only items ------------------------------------------------------
# --- back_populates links -------------------------------------------------
# --- 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 / Route ########################################################
class RouteType(DocumentedStrEnum):
START_FINISH = auto_enum() # Start at the start and end at the finish
CIRCULAR = auto_enum() # Start some ware, finish at the last new place
CIRCULAR_BACK_TO_START = auto_enum() # Start and finish on the same random place (CIRCULAR + next to start)
# ##############################################################################
# endregion