from typing import Optional, Any from sqlalchemy.orm import Session from fastapi import BackgroundTasks from app.models.AuditLogModel import AuditLog from app.core.database.db_session import SessionLocal import ulid class AuditService: @staticmethod def log_change( db: Session, request_id: str, user_id: Optional[str], entity_type: str, entity_id: str, action: str, old_value: Optional[Any], new_value: Optional[Any], ip_address: str, user_agent: Optional[str] ) -> AuditLog: audit_id = str(ulid.ULID()) log_entry = AuditLog( audit_id=audit_id, request_id=request_id, user_id=user_id, entity_type=entity_type, entity_id=entity_id, action=action, old_value=old_value, new_value=new_value, ip_address=ip_address, user_agent=user_agent ) db.add(log_entry) db.commit() db.refresh(log_entry) return log_entry @classmethod def _log_change_task( cls, request_id: str, user_id: Optional[str], entity_type: str, entity_id: str, action: str, old_value: Optional[Any], new_value: Optional[Any], ip_address: str, user_agent: Optional[str] ) -> None: # Open fresh session for background thread db = SessionLocal() try: cls.log_change( db=db, request_id=request_id, user_id=user_id, entity_type=entity_type, entity_id=entity_id, action=action, old_value=old_value, new_value=new_value, ip_address=ip_address, user_agent=user_agent ) finally: db.close() @classmethod def log_change_async( cls, background_tasks: BackgroundTasks, request_id: str, user_id: Optional[str], entity_type: str, entity_id: str, action: str, old_value: Optional[Any], new_value: Optional[Any], ip_address: str, user_agent: Optional[str] ) -> None: background_tasks.add_task( cls._log_change_task, request_id=request_id, user_id=user_id, entity_type=entity_type, entity_id=entity_id, action=action, old_value=old_value, new_value=new_value, ip_address=ip_address, user_agent=user_agent ) audit_service = AuditService()