refactor: update timestamp handling to use timezone-aware datetime

This commit is contained in:
JSC
2025-07-04 19:20:56 +02:00
parent 4375718c2f
commit 1cd43a670d
5 changed files with 94 additions and 58 deletions

View File

@@ -3,6 +3,7 @@
import secrets
from datetime import datetime
from typing import TYPE_CHECKING, Optional
from zoneinfo import ZoneInfo
from sqlalchemy import DateTime, ForeignKey, Integer, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
@@ -63,13 +64,13 @@ class User(db.Model):
# Timestamps
created_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.utcnow,
default=lambda: datetime.now(tz=ZoneInfo("UTC")),
nullable=False,
)
updated_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.utcnow,
onupdate=datetime.utcnow,
default=lambda: datetime.now(tz=ZoneInfo("UTC")),
onupdate=lambda: datetime.now(tz=ZoneInfo("UTC")),
nullable=False,
)
@@ -103,9 +104,11 @@ class User(db.Model):
"role": self.role,
"is_active": self.is_active,
"api_token": self.api_token,
"api_token_expires_at": self.api_token_expires_at.isoformat()
if self.api_token_expires_at
else None,
"api_token_expires_at": (
self.api_token_expires_at.isoformat()
if self.api_token_expires_at
else None
),
"providers": providers,
"plan": self.plan.to_dict() if self.plan else None,
"credits": self.credits,
@@ -129,13 +132,13 @@ class User(db.Model):
self.email = provider_data.get("email", self.email)
self.name = provider_data.get("name", self.name)
self.picture = provider_data.get("picture", self.picture)
self.updated_at = datetime.utcnow()
self.updated_at = datetime.now(tz=ZoneInfo("UTC"))
db.session.commit()
def set_password(self, password: str) -> None:
"""Hash and set user password."""
self.password_hash = generate_password_hash(password)
self.updated_at = datetime.utcnow()
self.updated_at = datetime.now(tz=ZoneInfo("UTC"))
def check_password(self, password: str) -> bool:
"""Check if provided password matches user's password."""
@@ -151,7 +154,7 @@ class User(db.Model):
"""Generate a new API token for the user."""
self.api_token = secrets.token_urlsafe(32)
self.api_token_expires_at = None # No expiration by default
self.updated_at = datetime.utcnow()
self.updated_at = datetime.now(tz=ZoneInfo("UTC"))
return self.api_token
def is_api_token_valid(self) -> bool:
@@ -162,23 +165,23 @@ class User(db.Model):
if self.api_token_expires_at is None:
return True # No expiration
return datetime.utcnow() < self.api_token_expires_at
return datetime.now(tz=ZoneInfo("UTC")) < self.api_token_expires_at
def revoke_api_token(self) -> None:
"""Revoke the user's API token."""
self.api_token = None
self.api_token_expires_at = None
self.updated_at = datetime.utcnow()
self.updated_at = datetime.now(tz=ZoneInfo("UTC"))
def activate(self) -> None:
"""Activate the user account."""
self.is_active = True
self.updated_at = datetime.utcnow()
self.updated_at = datetime.now(tz=ZoneInfo("UTC"))
def deactivate(self) -> None:
"""Deactivate the user account."""
self.is_active = False
self.updated_at = datetime.utcnow()
self.updated_at = datetime.now(tz=ZoneInfo("UTC"))
@classmethod
def find_by_email(cls, email: str) -> Optional["User"]:
@@ -218,7 +221,7 @@ class User(db.Model):
oauth_provider.email = email
oauth_provider.name = name
oauth_provider.picture = picture
oauth_provider.updated_at = datetime.utcnow()
oauth_provider.updated_at = datetime.now(tz=ZoneInfo("UTC"))
# Update user info with latest data
user.update_from_provider(