From 5555d69abe403c9c126226d9e7fadd9867bc86ad Mon Sep 17 00:00:00 2001 From: tiptenbrink <75669206+tiptenbrink@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:29:49 +0100 Subject: [PATCH] feat: last_updated column of class is updated when new event is added --- .../src/apiserver/data/api/classifications.py | 42 +++++++++++++++++++ backend/src/apiserver/data/context/ranking.py | 14 ++++++- backend/src/apiserver/lib/model/entities.py | 4 ++ test.nu | 11 +++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/backend/src/apiserver/data/api/classifications.py b/backend/src/apiserver/data/api/classifications.py index b8f1dd98..e9907a30 100644 --- a/backend/src/apiserver/data/api/classifications.py +++ b/backend/src/apiserver/data/api/classifications.py @@ -8,6 +8,7 @@ ClassEvent, Classification, ClassView, + EventDate, UserPoints, UserPointsNames, UserPointsNamesList, @@ -45,6 +46,7 @@ lit_model, select_some_join_where, select_some_where, + update_column_by_unique, ) from store.error import DataError, NoDataError, DbError, DbErrors @@ -218,3 +220,43 @@ async def get_event_user_points( ) return UserPointsNamesList.validate_python(user_points) + + +async def class_last_updated(conn: AsyncConnection, class_id: int) -> date: + """Get the date of the most recent event in a classification or otherwise the start date of the classification.""" + most_recent_event_date = await get_largest_where( + conn, + CLASS_EVENTS_TABLE, + {C_EVENTS_DATE}, + CLASS_ID, + class_id, + C_EVENTS_DATE, + 1, + True, + ) + if len(most_recent_event_date) == 0: + # in this case no event exists, so we set the date to the start date of the classification + most_recent_event_date = await select_some_where( + conn, CLASSIFICATION_TABLE, {CLASS_START_DATE}, CLASS_ID, class_id + ) + + if len(most_recent_event_date) != 1: + # in this case there is certainly a problem + raise NoDataError( + f"Could not retrieve last updated date for classification {class_id}. Does" + " it exist?", + "no_class_last_date", + ) + + event_date = EventDate.model_validate(most_recent_event_date[0]).date + + return event_date + + +async def class_update_last_updated( + conn: AsyncConnection, class_id: int, date: date +) -> int: + """Update the `last_updated` column of a classification so users know how recent it is.""" + return await update_column_by_unique( + conn, CLASSIFICATION_TABLE, CLASS_LAST_UPDATED, date, CLASS_ID, class_id + ) diff --git a/backend/src/apiserver/data/context/ranking.py b/backend/src/apiserver/data/context/ranking.py index 31cd401a..ec75dfc7 100644 --- a/backend/src/apiserver/data/context/ranking.py +++ b/backend/src/apiserver/data/context/ranking.py @@ -19,6 +19,8 @@ add_class_event, add_users_to_event, all_points_in_class, + class_last_updated, + class_update_last_updated, events_in_class, get_event_user_points, most_recent_class_of_type, @@ -33,7 +35,7 @@ def check_add_to_class(classification: ClassView, new_event: NewEvent) -> None: - """Throws AppError if not correct.""" + """Checks whether the event is after the classification start date. Throws AppError if not correct.""" if classification.start_date > new_event.date: desc = "Event cannot happen before start of classification!" raise AppError(ErrorKeys.RANKING_UPDATE, desc, "ranking_date_before_start") @@ -79,6 +81,16 @@ async def add_new_event(dsrc: Source, new_event: NewEvent) -> None: classification.classification_id, ) + # we want in a new transaction to ensure the event has been added + async with get_conn(dsrc) as conn: + # this can throw but should never happen after above transaction + last_updated_date = await class_last_updated( + conn, classification.classification_id + ) + await class_update_last_updated( + conn, classification.classification_id, last_updated_date + ) + async def add_new_training(dsrc: Source, new_event: NewTrainingEvent) -> None: async with get_conn(dsrc) as conn: diff --git a/backend/src/apiserver/lib/model/entities.py b/backend/src/apiserver/lib/model/entities.py index de990599..fbedea1c 100644 --- a/backend/src/apiserver/lib/model/entities.py +++ b/backend/src/apiserver/lib/model/entities.py @@ -272,3 +272,7 @@ class NewTrainingEvent(BaseModel): date: date event_id: str description: str = "" + + +class EventDate(BaseModel): + date: date diff --git a/test.nu b/test.nu index 282cb996..f7fa9af4 100755 --- a/test.nu +++ b/test.nu @@ -17,6 +17,11 @@ def check_backend [] { poetry run mypy } +def lint_fix [] { + cd $backend_dir + poetry run ruff src tests --fix +} + # Run pyest and run the formatter, linter and type checker def "main backend" [] { print "Testing and checking backend..." @@ -30,6 +35,12 @@ def "main pytest" [] { pytest_backend } +# Run pytest on the backend +def "main lint:fix" [] { + print "Linting and fixing issues..." + lint_fix +} + # important for the command to be exposed to the outside