From 6f13757d633e6069ff50f53ba5aee9cbc73bfbb0 Mon Sep 17 00:00:00 2001 From: tiptenbrink <75669206+tiptenbrink@users.noreply.github.com> Date: Thu, 4 Jan 2024 03:48:20 +0100 Subject: [PATCH] feat: also remove class --- backend/actions/local_actions.py | 8 +-- backend/src/apiserver/app/ops/startup.py | 8 ++- backend/src/apiserver/app/routers/ranking.py | 31 +++++++++-- .../src/apiserver/data/api/classifications.py | 36 +++++++++--- .../src/apiserver/data/context/app_context.py | 15 ++--- backend/src/apiserver/data/context/ranking.py | 55 +++++++++++-------- backend/src/apiserver/lib/model/entities.py | 4 +- backend/src/store/db.py | 4 +- 8 files changed, 104 insertions(+), 57 deletions(-) diff --git a/backend/actions/local_actions.py b/backend/actions/local_actions.py index 710e4e9d..1b34f38f 100644 --- a/backend/actions/local_actions.py +++ b/backend/actions/local_actions.py @@ -166,12 +166,12 @@ async def test_add_classification(local_dsrc): @pytest.mark.asyncio async def test_update_points(local_dsrc): async with get_conn(local_dsrc) as conn: - training_class = await data.classifications.most_recent_class_of_type( + training_class = (await data.classifications.most_recent_class_of_type( conn, "training" - ) - points_class = await data.classifications.most_recent_class_of_type( + ))[0] + points_class = (await data.classifications.most_recent_class_of_type( conn, "points" - ) + ))[0] await update_class_points(conn, training_class.classification_id) await update_class_points(conn, points_class.classification_id) diff --git a/backend/src/apiserver/app/ops/startup.py b/backend/src/apiserver/app/ops/startup.py index 791baf96..f32be385 100644 --- a/backend/src/apiserver/app/ops/startup.py +++ b/backend/src/apiserver/app/ops/startup.py @@ -1,4 +1,5 @@ from apiserver.app.error import AppError, ErrorKeys +from apiserver.data.special import update_class_points from loguru import logger from asyncio import sleep from datetime import date @@ -199,8 +200,11 @@ async def initial_population(dsrc: Source, config: Config) -> None: user_id = await data.user.insert_return_user_id(conn, fake_user) assert user_id == "1_fakerecord" - await insert_classification(conn, "training") - await insert_classification(conn, "points") + new_training_id = await insert_classification(conn, "training") + new_points_id = await insert_classification(conn, "points") + + await update_class_points(conn, new_training_id, False) + await update_class_points(conn, new_points_id, False) async def get_keystate(dsrc: Source) -> KeyState: diff --git a/backend/src/apiserver/app/routers/ranking.py b/backend/src/apiserver/app/routers/ranking.py index 7ae49252..d8b93870 100644 --- a/backend/src/apiserver/app/routers/ranking.py +++ b/backend/src/apiserver/app/routers/ranking.py @@ -9,7 +9,10 @@ mod_user_events_in_class, ) from apiserver.app.response import RawJSONResponse -from apiserver.data.api.classifications import get_event_user_points +from apiserver.data.api.classifications import ( + get_event_user_points, + remove_classification, +) from apiserver.data import Source from apiserver.data.context.app_context import RankingContext, conn_wrap from apiserver.data.context.ranking import ( @@ -108,8 +111,10 @@ async def get_classification_with_meta( async def get_classifications( recent_number: int, dsrc: SourceDep, app_context: AppContext ) -> RawJSONResponse: - recent_classes = await most_recent_classes(app_context.rank_ctx, dsrc, recent_number) - + recent_classes = await most_recent_classes( + app_context.rank_ctx, dsrc, recent_number + ) + return RawJSONResponse(ClassMetaList.dump_json(recent_classes)) @@ -206,13 +211,27 @@ async def get_event_users( @ranking_admin_router.post("/new/") async def new_classes( - dsrc: SourceDep, app_context: AppContext, + dsrc: SourceDep, + app_context: AppContext, ) -> None: await context_new_classes(app_context.rank_ctx, dsrc) @ranking_admin_router.post("/modify/") async def modify_class( - updated_class: ClassUpdate, dsrc: SourceDep, app_context: AppContext, + updated_class: ClassUpdate, + dsrc: SourceDep, + app_context: AppContext, ) -> None: - await context_modify_class(app_context.rank_ctx, dsrc, updated_class) \ No newline at end of file + await context_modify_class(app_context.rank_ctx, dsrc, updated_class) + + +@ranking_admin_router.post("/remove/{class_id}/") +async def remove_class( + class_id: int, + dsrc: SourceDep, + app_context: AppContext, +) -> None: + await ctxlize_wrap(remove_classification, conn_wrap)( + app_context.rank_ctx, dsrc, class_id + ) diff --git a/backend/src/apiserver/data/api/classifications.py b/backend/src/apiserver/data/api/classifications.py index ffba5183..120a6da9 100644 --- a/backend/src/apiserver/data/api/classifications.py +++ b/backend/src/apiserver/data/api/classifications.py @@ -11,7 +11,6 @@ ClassMetaList, ClassUpdate, Classification, - ClassView, EventDate, UserPoints, UserPointsNames, @@ -44,15 +43,16 @@ ) from store.db import ( LiteralDict, + delete_by_column, get_largest_where, insert, insert_many, + insert_return_col, lit_model, select_some_join_where, select_some_where, update_by_unique, update_column_by_unique, - upsert_by_unique, ) from store.error import DataError, NoDataError, DbError, DbErrors @@ -67,7 +67,7 @@ def parse_user_points(user_points: list[RowMapping]) -> list[UserPointsNames]: async def insert_classification( conn: AsyncConnection, class_type: str, start_date: date | None = None -) -> None: +) -> int: if start_date is None: start_date = date.today() new_classification = Classification( @@ -77,7 +77,10 @@ async def insert_classification( end_date=start_date + timedelta(days=30 * 5), hidden_date=start_date + timedelta(days=30 * 4), ) - await insert(conn, CLASSIFICATION_TABLE, lit_model(new_classification)) + return_id: int = await insert_return_col( + conn, CLASSIFICATION_TABLE, lit_model(new_classification), CLASS_ID + ) + return return_id async def most_recent_class_of_type( @@ -96,7 +99,14 @@ async def most_recent_class_of_type( largest_class_list = await get_largest_where( conn, CLASSIFICATION_TABLE, - {CLASS_ID, CLASS_LAST_UPDATED, CLASS_START_DATE, CLASS_HIDDEN_DATE, CLASS_END_DATE}, + { + CLASS_ID, + CLASS_TYPE, + CLASS_LAST_UPDATED, + CLASS_START_DATE, + CLASS_HIDDEN_DATE, + CLASS_END_DATE, + }, CLASS_TYPE, query_class_type, CLASS_START_DATE, @@ -267,8 +277,16 @@ async def class_update_last_updated( conn, CLASSIFICATION_TABLE, CLASS_LAST_UPDATED, date, CLASS_ID, class_id ) -async def update_classification( - conn: AsyncConnection, class_view: ClassUpdate -) -> None: - await update_by_unique(conn, CLASSIFICATION_TABLE, lit_model(class_view), "classification_id", class_view.classification_id) +async def update_classification(conn: AsyncConnection, class_view: ClassUpdate) -> None: + await update_by_unique( + conn, + CLASSIFICATION_TABLE, + lit_model(class_view), + "classification_id", + class_view.classification_id, + ) + + +async def remove_classification(conn: AsyncConnection, class_id: int) -> None: + await delete_by_column(conn, CLASSIFICATION_TABLE, "classification_id", class_id) diff --git a/backend/src/apiserver/data/context/app_context.py b/backend/src/apiserver/data/context/app_context.py index 1d96e744..de7005a1 100644 --- a/backend/src/apiserver/data/context/app_context.py +++ b/backend/src/apiserver/data/context/app_context.py @@ -20,7 +20,6 @@ ClassEvent, ClassMeta, ClassUpdate, - ClassView, NewEvent, RankingInfo, UserData, @@ -104,23 +103,21 @@ async def context_get_event_users( cls, dsrc: Source, event_id: str ) -> list[UserPointsNames]: raise ContextNotImpl() - + @classmethod async def most_recent_classes( cls, dsrc: Source, amount: int = 10 ) -> list[ClassMeta]: raise ContextNotImpl() - + @classmethod - async def context_new_classes( - cls, dsrc: Source - ) -> None: + async def context_new_classes(cls, dsrc: Source) -> None: raise ContextNotImpl() - + @classmethod async def context_modify_class( - cls, dsrc: Source, class_update: ClassUpdate - ) -> None: + cls, dsrc: Source, class_update: ClassUpdate + ) -> None: raise ContextNotImpl() diff --git a/backend/src/apiserver/data/context/ranking.py b/backend/src/apiserver/data/context/ranking.py index ed074a7e..52f30a33 100644 --- a/backend/src/apiserver/data/context/ranking.py +++ b/backend/src/apiserver/data/context/ranking.py @@ -53,7 +53,9 @@ async def add_new_event(dsrc: Source, new_event: NewEvent) -> None: date. Use the 'publish' function to force them to be equal.""" async with get_conn(dsrc) as conn: try: - classification = (await most_recent_class_of_type(conn, new_event.class_type))[0] + classification = ( + await most_recent_class_of_type(conn, new_event.class_type) + )[0] except DataError as e: if e.key != "incorrect_class_type": raise e @@ -139,14 +141,18 @@ async def context_most_recent_class_id_of_type( dsrc: Source, rank_type: Literal["points", "training"] ) -> int: async with get_conn(dsrc) as conn: - class_id = (await most_recent_class_of_type(conn, rank_type))[0].classification_id + class_id = (await most_recent_class_of_type(conn, rank_type))[ + 0 + ].classification_id return class_id @ctx_reg.register(RankingContext) async def context_most_recent_class_points( - dsrc: Source, rank_type: Literal["points", "training"], is_admin: bool, + dsrc: Source, + rank_type: Literal["points", "training"], + is_admin: bool, ) -> RankingInfo: async with get_conn(dsrc) as conn: class_view = (await most_recent_class_of_type(conn, rank_type))[0] @@ -198,36 +204,39 @@ async def context_get_event_users(dsrc: Source, event_id: str) -> list[UserPoint return events_points +MIN_AMOUNT = 2 + + @ctx_reg.register(RankingContext) -async def most_recent_classes( - dsrc: Source, amount: int = 10 -) -> list[ClassMeta]: - if amount < 2 or amount % 2 != 0: +async def most_recent_classes(dsrc: Source, amount: int = 10) -> list[ClassMeta]: + if amount < MIN_AMOUNT or amount % 2 != 0: raise AppError( - ErrorKeys.DATA, - "Request at least 2 classes and make sure it is an even number!", - "most_recent_too_few", - ) - + ErrorKeys.DATA, + "Request at least 2 classes and make sure it is an even number!", + "most_recent_too_few", + ) + async with get_conn(dsrc) as conn: - training_classes = (await most_recent_class_of_type(conn, "training", amount // 2)) - points_classes = (await most_recent_class_of_type(conn, "points", amount // 2)) + training_classes = await most_recent_class_of_type( + conn, "training", amount // 2 + ) + points_classes = await most_recent_class_of_type(conn, "points", amount // 2) return training_classes + points_classes @ctx_reg.register(RankingContext) -async def context_new_classes( - dsrc: Source -) -> None: +async def context_new_classes(dsrc: Source) -> None: async with get_conn(dsrc) as conn: - await insert_classification(conn, "training") - await insert_classification(conn, "points") + new_training_id = await insert_classification(conn, "training") + new_points_id = await insert_classification(conn, "points") + + await update_class_points(conn, new_training_id, False) + await update_class_points(conn, new_points_id, False) @ctx_reg.register(RankingContext) -async def context_modify_class( - dsrc: Source, class_update: ClassUpdate -) -> None: +async def context_modify_class(dsrc: Source, class_update: ClassUpdate) -> None: async with get_conn(dsrc) as conn: - await update_classification(conn, class_update) \ No newline at end of file + await update_classification(conn, class_update) + await update_class_points(conn, class_update.classification_id, False) diff --git a/backend/src/apiserver/lib/model/entities.py b/backend/src/apiserver/lib/model/entities.py index f4a7e736..1f821428 100644 --- a/backend/src/apiserver/lib/model/entities.py +++ b/backend/src/apiserver/lib/model/entities.py @@ -285,6 +285,7 @@ class EventDate(BaseModel): class ClassMeta(ClassView): + type: Literal["points", "training"] end_date: date @@ -294,4 +295,5 @@ class ClassUpdate(BaseModel): hidden_date: date end_date: date -ClassMetaList = TypeAdapter(List[ClassMeta]) \ No newline at end of file + +ClassMetaList = TypeAdapter(List[ClassMeta]) diff --git a/backend/src/store/db.py b/backend/src/store/db.py index 311457f8..b4ad53d8 100644 --- a/backend/src/store/db.py +++ b/backend/src/store/db.py @@ -238,9 +238,7 @@ async def update_by_unique( _, _, row_keys_set = _row_keys_vars_set(set_dict) - query = text( - f"UPDATE {table} SET {row_keys_set} WHERE {unique_column} = :val;" - ) + query = text(f"UPDATE {table} SET {row_keys_set} WHERE {unique_column} = :val;") val_dict: LiteralDict = {"val": value} params = set_dict | val_dict