diff --git a/backend/config/__init__.py b/backend/config/__init__.py index 1ac80f1e6..38dce85fe 100644 --- a/backend/config/__init__.py +++ b/backend/config/__init__.py @@ -16,6 +16,7 @@ DEV_MODE: Final = str_to_bool(os.environ.get("DEV_MODE", "false")) DEV_HOST: Final = os.environ.get("DEV_HOST", "127.0.0.1") DEV_PORT: Final = int(os.environ.get("DEV_PORT", "5000")) GUNICORN_WORKERS: Final = int(os.environ.get("GUNICORN_WORKERS", 2)) +TIMEZONE: Final = os.environ.get("TZ", "Etc/UTC") # PATHS ROMM_BASE_PATH: Final = os.environ.get("ROMM_BASE_PATH", "/romm") diff --git a/backend/endpoints/auth.py b/backend/endpoints/auth.py index f85a829b6..f273d9753 100644 --- a/backend/endpoints/auth.py +++ b/backend/endpoints/auth.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Annotated, Final from endpoints.forms.identity import OAuth2RequestForm @@ -161,9 +161,8 @@ def login( request.session.update({"iss": "romm:auth", "sub": user.username}) # Update last login and active times - db_user_handler.update_user( - user.id, {"last_login": datetime.now(), "last_active": datetime.now()} - ) + now = datetime.now(timezone.utc) + db_user_handler.update_user(user.id, {"last_login": now, "last_active": now}) return {"msg": "Successfully logged in"} diff --git a/backend/endpoints/platform.py b/backend/endpoints/platform.py index 6f5152c31..24133f6da 100644 --- a/backend/endpoints/platform.py +++ b/backend/endpoints/platform.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from decorators.auth import protected_route from endpoints.responses import MessageResponse @@ -69,6 +69,7 @@ def get_supported_platforms(request: Request) -> list[PlatformSchema]: db_platforms_map = {p.name: p.id for p in db_platforms} for platform in IGDB_PLATFORM_LIST: + now = datetime.now(timezone.utc) sup_plat = { "id": -1, "name": platform["name"], @@ -77,8 +78,8 @@ def get_supported_platforms(request: Request) -> list[PlatformSchema]: "logo_path": "", "roms": [], "rom_count": 0, - "created_at": datetime.now(), - "updated_at": datetime.now(), + "created_at": now, + "updated_at": now, } if platform["name"] in db_platforms_map: diff --git a/backend/endpoints/responses/rom.py b/backend/endpoints/responses/rom.py index 98cd9ed59..5907c249d 100644 --- a/backend/endpoints/responses/rom.py +++ b/backend/endpoints/responses/rom.py @@ -1,7 +1,7 @@ from __future__ import annotations import re -from datetime import datetime +from datetime import datetime, timezone from typing import NotRequired, TypedDict, get_type_hints from endpoints.responses.assets import SaveSchema, ScreenshotSchema, StateSchema @@ -27,12 +27,13 @@ RomMobyMetadata = TypedDict( # type: ignore[misc] def rom_user_schema_factory() -> RomUserSchema: + now = datetime.now(timezone.utc) return RomUserSchema( id=-1, user_id=-1, rom_id=-1, - created_at=datetime.now(), - updated_at=datetime.now(), + created_at=now, + updated_at=now, note_raw_markdown="", note_is_public=False, is_main_sibling=False, diff --git a/backend/endpoints/saves.py b/backend/endpoints/saves.py index 5a588bb17..0a7893d3f 100644 --- a/backend/endpoints/saves.py +++ b/backend/endpoints/saves.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from decorators.auth import protected_route from endpoints.responses import MessageResponse @@ -67,8 +67,9 @@ def add_saves( rom_user = db_rom_handler.get_rom_user(rom.id, current_user.id) if not rom_user: rom_user = db_rom_handler.add_rom_user(rom.id, current_user.id) - rom_user.last_played = datetime.now() - db_rom_handler.update_rom_user(rom_user.id, {"last_played": datetime.now()}) + db_rom_handler.update_rom_user( + rom_user.id, {"last_played": datetime.now(timezone.utc)} + ) # Refetch the rom to get updated saves rom = db_rom_handler.get_rom(rom_id) @@ -116,8 +117,9 @@ async def update_save(request: Request, id: int) -> SaveSchema: rom_user = db_rom_handler.get_rom_user(db_save.rom_id, current_user.id) if not rom_user: rom_user = db_rom_handler.add_rom_user(db_save.rom_id, current_user.id) - rom_user.last_played = datetime.now() - db_rom_handler.update_rom_user(rom_user.id, {"last_played": datetime.now()}) + db_rom_handler.update_rom_user( + rom_user.id, {"last_played": datetime.now(timezone.utc)} + ) # Refetch the save to get updated fields db_save = db_save_handler.get_save(id) diff --git a/backend/endpoints/states.py b/backend/endpoints/states.py index 2da83b318..462c236fc 100644 --- a/backend/endpoints/states.py +++ b/backend/endpoints/states.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from decorators.auth import protected_route from endpoints.responses import MessageResponse @@ -67,8 +67,9 @@ def add_states( rom_user = db_rom_handler.get_rom_user(rom.id, current_user.id) if not rom_user: rom_user = db_rom_handler.add_rom_user(rom.id, current_user.id) - rom_user.last_played = datetime.now() - db_rom_handler.update_rom_user(rom_user.id, {"last_played": datetime.now()}) + db_rom_handler.update_rom_user( + rom_user.id, {"last_played": datetime.now(timezone.utc)} + ) rom = db_rom_handler.get_rom(rom_id) return { @@ -112,8 +113,9 @@ async def update_state(request: Request, id: int) -> StateSchema: rom_user = db_rom_handler.get_rom_user(db_state.rom_id, current_user.id) if not rom_user: rom_user = db_rom_handler.add_rom_user(db_state.rom_id, current_user.id) - rom_user.last_played = datetime.now() - db_rom_handler.update_rom_user(rom_user.id, {"last_played": datetime.now()}) + db_rom_handler.update_rom_user( + rom_user.id, {"last_played": datetime.now(timezone.utc)} + ) db_state = db_state_handler.get_state(id) return db_state diff --git a/backend/handler/auth/base_handler.py b/backend/handler/auth/base_handler.py index 2a5fecfc9..836c8f88f 100644 --- a/backend/handler/auth/base_handler.py +++ b/backend/handler/auth/base_handler.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Final from config import ROMM_AUTH_SECRET_KEY @@ -106,9 +106,11 @@ class OAuthHandler: to_encode = data.copy() if expires_delta: - expire = datetime.utcnow() + expires_delta + expire = datetime.now(timezone.utc) + expires_delta else: - expire = datetime.utcnow() + timedelta(minutes=DEFAULT_OAUTH_TOKEN_EXPIRY) + expire = datetime.now(timezone.utc) + timedelta( + minutes=DEFAULT_OAUTH_TOKEN_EXPIRY + ) to_encode.update({"exp": expire}) diff --git a/backend/models/rom.py b/backend/models/rom.py index 570b2a01b..7fca7b684 100644 --- a/backend/models/rom.py +++ b/backend/models/rom.py @@ -174,7 +174,7 @@ class Rom(BaseModel): return self.file_name -class RomUserStatus(enum.Enum): +class RomUserStatus(enum.StrEnum): INCOMPLETE = "incomplete" # Started but not finished FINISHED = "finished" # Reached the end of the game COMPLETED_100 = "completed_100" # Completed 100% diff --git a/backend/models/user.py b/backend/models/user.py index f880a37ae..635e19eaa 100644 --- a/backend/models/user.py +++ b/backend/models/user.py @@ -1,7 +1,7 @@ from __future__ import annotations import enum -from datetime import datetime +from datetime import datetime, timezone from typing import TYPE_CHECKING from models.base import BaseModel @@ -61,4 +61,6 @@ class User(BaseModel, SimpleUser): def set_last_active(self): from handler.database import db_user_handler - db_user_handler.update_user(self.id, {"last_active": datetime.now()}) + db_user_handler.update_user( + self.id, {"last_active": datetime.now(timezone.utc)} + )