diff --git a/backend/src/apiserver/app/routers/ranking.py b/backend/src/apiserver/app/routers/ranking.py index d9e9c4bc..4a575d64 100644 --- a/backend/src/apiserver/app/routers/ranking.py +++ b/backend/src/apiserver/app/routers/ranking.py @@ -23,6 +23,7 @@ ClassEvent, NewEvent, NewTrainingEvent, + RankingInfo, UserEvent, UserPointsNames, UserPointsNamesList, @@ -75,10 +76,46 @@ async def get_classification( debug_key="bad_ranking", ) - user_points = await context_most_recent_class_points(ctx, dsrc, rank_type, admin) + user_points = ( + await context_most_recent_class_points(ctx, dsrc, rank_type, admin) + ).points return RawJSONResponse(UserPointsNamesList.dump_json(user_points)) +async def get_classification_with_meta( + dsrc: Source, ctx: RankingContext, rank_type: str, admin: bool = False +) -> RawJSONResponse: + if not is_rank_type(rank_type): + reason = f"Ranking {rank_type} is unknown!" + raise ErrorResponse( + status_code=400, + err_type="invalid_ranking", + err_desc=reason, + debug_key="bad_ranking", + ) + + ranking_info = await context_most_recent_class_points(ctx, dsrc, rank_type, admin) + return RawJSONResponse(RankingInfo.model_dump_json(ranking_info).encode()) + + +@ranking_members_router.get("/get_meta/{rank_type}/", response_model=RankingInfo) +async def member_classification_meta( + rank_type: str, dsrc: SourceDep, app_context: AppContext +) -> RawJSONResponse: + return await get_classification_with_meta( + dsrc, app_context.rank_ctx, rank_type, False + ) + + +@ranking_admin_router.get("/get_meta/{rank_type}/", response_model=RankingInfo) +async def member_classification_admin_meta( + rank_type: str, dsrc: SourceDep, app_context: AppContext +) -> RawJSONResponse: + return await get_classification_with_meta( + dsrc, app_context.rank_ctx, rank_type, True + ) + + @ranking_members_router.get("/get/{rank_type}/", response_model=list[UserPointsNames]) async def member_classification( rank_type: str, dsrc: SourceDep, app_context: AppContext diff --git a/backend/src/apiserver/data/context/app_context.py b/backend/src/apiserver/data/context/app_context.py index aa99c7e0..d06fdd74 100644 --- a/backend/src/apiserver/data/context/app_context.py +++ b/backend/src/apiserver/data/context/app_context.py @@ -19,6 +19,7 @@ from apiserver.lib.model.entities import ( ClassEvent, NewEvent, + RankingInfo, UserData, User, UserEvent, @@ -76,7 +77,7 @@ async def context_most_recent_class_id_of_type( @classmethod async def context_most_recent_class_points( cls, dsrc: Source, rank_type: Literal["points", "training"], is_admin: bool - ) -> list[UserPointsNames]: + ) -> RankingInfo: raise ContextNotImpl() @classmethod diff --git a/backend/src/apiserver/data/context/ranking.py b/backend/src/apiserver/data/context/ranking.py index ec75dfc7..f07c2b3f 100644 --- a/backend/src/apiserver/data/context/ranking.py +++ b/backend/src/apiserver/data/context/ranking.py @@ -1,3 +1,4 @@ +from datetime import date from apiserver.data.api.trainings import add_training_event from datacontext.context import ContextRegistry from typing import Any, Literal @@ -11,6 +12,7 @@ ClassView, NewEvent, NewTrainingEvent, + RankingInfo, UserEvent, UserPointsNames, ) @@ -141,14 +143,19 @@ async def context_most_recent_class_id_of_type( @ctx_reg.register(RankingContext) async def context_most_recent_class_points( dsrc: Source, rank_type: Literal["points", "training"], is_admin: bool -) -> list[UserPointsNames]: +) -> RankingInfo: async with get_conn(dsrc) as conn: class_view = await most_recent_class_of_type(conn, rank_type) user_points = await all_points_in_class( conn, class_view.classification_id, is_admin ) - return user_points + is_frozen = date.today() >= class_view.hidden_date + ranking_info = RankingInfo( + points=user_points, last_updated=class_view.last_updated, frozen=is_frozen + ) + + return ranking_info @ctx_reg.register(RankingContext) diff --git a/backend/src/apiserver/lib/model/entities.py b/backend/src/apiserver/lib/model/entities.py index fbedea1c..d13d5786 100644 --- a/backend/src/apiserver/lib/model/entities.py +++ b/backend/src/apiserver/lib/model/entities.py @@ -223,6 +223,12 @@ class UserPointsNames(BaseModel): UserPointsNamesList = TypeAdapter(List[UserPointsNames]) +class RankingInfo(BaseModel): + last_updated: date + frozen: bool + points: list[UserPointsNames] + + # class PointsData(BaseModel): # points: int