From 77173178657d24f27fb3e11ccd728a4e24ebacf0 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 9 Jan 2025 20:48:54 -0500 Subject: [PATCH] [ROMM-1452] Mark naive datetimes as UTC --- backend/endpoints/responses/assets.py | 2 +- backend/endpoints/responses/base.py | 18 ++++++++++++++++++ backend/endpoints/responses/collection.py | 3 ++- backend/endpoints/responses/firmware.py | 2 +- backend/endpoints/responses/identity.py | 3 ++- backend/endpoints/responses/platform.py | 3 ++- backend/endpoints/responses/rom.py | 4 +++- backend/endpoints/responses/search.py | 2 +- backend/endpoints/rom.py | 3 ++- 9 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 backend/endpoints/responses/base.py diff --git a/backend/endpoints/responses/assets.py b/backend/endpoints/responses/assets.py index def6a753d..5a326c80f 100644 --- a/backend/endpoints/responses/assets.py +++ b/backend/endpoints/responses/assets.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import TypedDict -from pydantic import BaseModel +from .base import BaseModel class BaseAsset(BaseModel): diff --git a/backend/endpoints/responses/base.py b/backend/endpoints/responses/base.py new file mode 100644 index 000000000..404d70b98 --- /dev/null +++ b/backend/endpoints/responses/base.py @@ -0,0 +1,18 @@ +from datetime import datetime, timezone + +from pydantic import BaseModel as PydanticBaseModel +from pydantic import ConfigDict + + +class BaseModel(PydanticBaseModel): + """Ensures all datetime fields include UTC timezone""" + + model_config = ConfigDict( + json_encoders={ + datetime: lambda dt: ( + dt.isoformat() + if dt.tzinfo + else dt.replace(tzinfo=timezone.utc).isoformat() + ) + } + ) diff --git a/backend/endpoints/responses/collection.py b/backend/endpoints/responses/collection.py index 0ad5be05a..da8d6ee70 100644 --- a/backend/endpoints/responses/collection.py +++ b/backend/endpoints/responses/collection.py @@ -1,7 +1,8 @@ from datetime import datetime from models.collection import Collection -from pydantic import BaseModel + +from .base import BaseModel class CollectionSchema(BaseModel): diff --git a/backend/endpoints/responses/firmware.py b/backend/endpoints/responses/firmware.py index b4a19cd60..9c6c403ff 100644 --- a/backend/endpoints/responses/firmware.py +++ b/backend/endpoints/responses/firmware.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import TypedDict -from pydantic import BaseModel +from .base import BaseModel class FirmwareSchema(BaseModel): diff --git a/backend/endpoints/responses/identity.py b/backend/endpoints/responses/identity.py index ac43eb2be..c45bbe778 100644 --- a/backend/endpoints/responses/identity.py +++ b/backend/endpoints/responses/identity.py @@ -1,7 +1,8 @@ from datetime import datetime from models.user import Role -from pydantic import BaseModel + +from .base import BaseModel class UserSchema(BaseModel): diff --git a/backend/endpoints/responses/platform.py b/backend/endpoints/responses/platform.py index c19300312..6ca60452e 100644 --- a/backend/endpoints/responses/platform.py +++ b/backend/endpoints/responses/platform.py @@ -1,8 +1,9 @@ from datetime import datetime from models.platform import DEFAULT_COVER_ASPECT_RATIO -from pydantic import BaseModel, Field, computed_field +from pydantic import Field, computed_field +from .base import BaseModel from .firmware import FirmwareSchema diff --git a/backend/endpoints/responses/rom.py b/backend/endpoints/responses/rom.py index d4108afd4..971893cbf 100644 --- a/backend/endpoints/responses/rom.py +++ b/backend/endpoints/responses/rom.py @@ -10,7 +10,9 @@ from handler.metadata.igdb_handler import IGDBMetadata from handler.metadata.moby_handler import MobyMetadata from models.rom import Rom, RomFile, RomUserStatus -from pydantic import BaseModel, computed_field +from pydantic import computed_field + +from .base import BaseModel SORT_COMPARE_REGEX = re.compile(r"^([Tt]he|[Aa]|[Aa]nd)\s") diff --git a/backend/endpoints/responses/search.py b/backend/endpoints/responses/search.py index 7f1de633d..43b264753 100644 --- a/backend/endpoints/responses/search.py +++ b/backend/endpoints/responses/search.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel +from .base import BaseModel class SearchRomSchema(BaseModel): diff --git a/backend/endpoints/rom.py b/backend/endpoints/rom.py index f9fab79d3..950dbb7ea 100644 --- a/backend/endpoints/rom.py +++ b/backend/endpoints/rom.py @@ -1,5 +1,6 @@ import binascii from base64 import b64encode +from datetime import datetime, timezone from io import BytesIO from shutil import rmtree from typing import Annotated @@ -584,6 +585,6 @@ async def update_rom_user(request: Request, id: int) -> RomUserSchema: cleaned_data = {field: data[field] for field in fields_to_update if field in data} if data.get("update_last_played", False): - cleaned_data.update({"last_played": func.now()}) + cleaned_data.update({"last_played": datetime.now(timezone.utc)}) return db_rom_handler.update_rom_user(db_rom_user.id, cleaned_data)