diff --git a/flowsint-core/src/flowsint_core/core/services/analysis_service.py b/flowsint-core/src/flowsint_core/core/services/analysis_service.py index c92928a..b584201 100644 --- a/flowsint-core/src/flowsint_core/core/services/analysis_service.py +++ b/flowsint-core/src/flowsint_core/core/services/analysis_service.py @@ -2,9 +2,9 @@ Analysis service for managing analyses within investigations. """ +from datetime import datetime, timezone from typing import Any, Dict, List, Optional from uuid import UUID, uuid4 -from datetime import datetime from sqlalchemy.orm import Session @@ -64,8 +64,8 @@ class AnalysisService(BaseService): content=content, owner_id=owner_id, investigation_id=investigation_id, - created_at=datetime.utcnow(), - last_updated_at=datetime.utcnow(), + created_at=datetime.now(timezone.utc), + last_updated_at=datetime.now(timezone.utc), ) self._analysis_repo.add(new_analysis) self._commit() @@ -97,7 +97,7 @@ class AnalysisService(BaseService): self._check_permission(user_id, investigation_id, ["update"]) analysis.investigation_id = investigation_id - analysis.last_updated_at = datetime.utcnow() + analysis.last_updated_at = datetime.now(timezone.utc) self._commit() self._refresh(analysis) return analysis diff --git a/flowsint-core/src/flowsint_core/core/services/chat_service.py b/flowsint-core/src/flowsint_core/core/services/chat_service.py index 2f66787..8364acc 100644 --- a/flowsint-core/src/flowsint_core/core/services/chat_service.py +++ b/flowsint-core/src/flowsint_core/core/services/chat_service.py @@ -4,7 +4,7 @@ Chat service for managing chats and messages with AI integration. import json import os -from datetime import datetime +from datetime import datetime, timezone from typing import Any, AsyncIterator, Dict, List, Optional from uuid import UUID, uuid4 @@ -76,8 +76,8 @@ class ChatService(BaseService): description=description, owner_id=owner_id, investigation_id=investigation_id, - created_at=datetime.utcnow(), - last_updated_at=datetime.utcnow(), + created_at=datetime.now(timezone.utc), + last_updated_at=datetime.now(timezone.utc), ) self._chat_repo.add(new_chat) self._commit() @@ -103,7 +103,7 @@ class ChatService(BaseService): if not chat: raise NotFoundError("Chat not found") - chat.last_updated_at = datetime.utcnow() + chat.last_updated_at = datetime.now(timezone.utc) user_message = ChatMessage( id=uuid4(), @@ -111,7 +111,7 @@ class ChatService(BaseService): context=context, chat_id=chat_id, is_bot=False, - created_at=datetime.utcnow(), + created_at=datetime.now(timezone.utc), ) self._chat_repo.add_message(user_message) self._commit() @@ -124,7 +124,7 @@ class ChatService(BaseService): content=content, chat_id=chat_id, is_bot=True, - created_at=datetime.utcnow(), + created_at=datetime.now(timezone.utc), ) self._chat_repo.add_message(chat_message) self._commit() diff --git a/flowsint-core/src/flowsint_core/core/services/flow_service.py b/flowsint-core/src/flowsint_core/core/services/flow_service.py index f4919bf..1104895 100644 --- a/flowsint-core/src/flowsint_core/core/services/flow_service.py +++ b/flowsint-core/src/flowsint_core/core/services/flow_service.py @@ -2,7 +2,7 @@ Flow service for managing flows and flow computations. """ -from datetime import datetime +from datetime import datetime, timezone from typing import Any, Dict, List, Optional from uuid import UUID, uuid4 @@ -82,8 +82,8 @@ class FlowService(BaseService): description=description, category=category, flow_schema=flow_schema, - created_at=datetime.utcnow(), - last_updated_at=datetime.utcnow(), + created_at=datetime.now(timezone.utc), + last_updated_at=datetime.now(timezone.utc), ) self._flow_repo.add(new_flow) self._commit() @@ -101,7 +101,7 @@ class FlowService(BaseService): value.append("Username") setattr(flow, key, value) - flow.last_updated_at = datetime.utcnow() + flow.last_updated_at = datetime.now(timezone.utc) self._commit() self._refresh(flow) return flow diff --git a/flowsint-core/tests/services/test_timezone_timestamps.py b/flowsint-core/tests/services/test_timezone_timestamps.py new file mode 100644 index 0000000..6f09ab5 --- /dev/null +++ b/flowsint-core/tests/services/test_timezone_timestamps.py @@ -0,0 +1,72 @@ +"""Tests for timezone-aware service timestamps.""" + +from datetime import timezone +from unittest.mock import MagicMock +from uuid import uuid4 + +from flowsint_core.core.services.analysis_service import AnalysisService +from flowsint_core.core.services.chat_service import ChatService +from flowsint_core.core.services.flow_service import FlowService + + +def _assert_utc(value): + assert value.tzinfo is not None + assert value.utcoffset() == timezone.utc.utcoffset(value) + + +def test_analysis_service_create_uses_timezone_aware_timestamps(): + service = AnalysisService( + db=MagicMock(), + analysis_repo=MagicMock(), + investigation_repo=MagicMock(), + ) + service._check_permission = MagicMock() + + analysis = service.create( + title="Summary", + description=None, + content={}, + investigation_id=uuid4(), + owner_id=uuid4(), + ) + + _assert_utc(analysis.created_at) + _assert_utc(analysis.last_updated_at) + + +def test_chat_service_create_uses_timezone_aware_timestamps(): + service = ChatService( + db=MagicMock(), + chat_repo=MagicMock(), + vault_service=MagicMock(), + ) + + chat = service.create( + title="Investigation chat", + description=None, + investigation_id=uuid4(), + owner_id=uuid4(), + ) + + _assert_utc(chat.created_at) + _assert_utc(chat.last_updated_at) + + +def test_flow_service_create_uses_timezone_aware_timestamps(): + service = FlowService( + db=MagicMock(), + flow_repo=MagicMock(), + custom_type_repo=MagicMock(), + sketch_repo=MagicMock(), + investigation_repo=MagicMock(), + ) + + flow = service.create( + name="Resolve domain", + description=None, + category=["Domain"], + flow_schema={"nodes": [], "edges": []}, + ) + + _assert_utc(flow.created_at) + _assert_utc(flow.last_updated_at)