from __future__ import annotations from datetime import datetime from typing import Any from sqlalchemy import DateTime, ForeignKey, Index, String from sqlalchemy.types import JSON from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.sql import func from app.models.base import BaseModel, ID_TYPE class AuditLog(BaseModel): __tablename__ = "audit_logs" __table_args__ = ( Index("idx_audit_logs_created_at", "created_at"), Index("idx_audit_logs_actor_created_at", "actor_user_id", "created_at"), Index("idx_audit_logs_action_created_at", "action_type", "created_at"), Index("idx_audit_logs_target", "target_type", "target_id", "created_at"), ) id: Mapped[int] = mapped_column(ID_TYPE, primary_key=True) actor_user_id: Mapped[int | None] = mapped_column( ID_TYPE, ForeignKey("accounts.id", ondelete="SET NULL"), nullable=True, ) actor_username: Mapped[str] = mapped_column(String(64), nullable=False) actor_display_name: Mapped[str | None] = mapped_column(String(64), nullable=True) action_type: Mapped[str] = mapped_column(String(32), nullable=False) target_type: Mapped[str] = mapped_column(String(32), nullable=False) target_id: Mapped[int | None] = mapped_column(ID_TYPE, nullable=True) target_display_name: Mapped[str | None] = mapped_column(String(128), nullable=True) before_data_json: Mapped[dict[str, object] | list[object] | None] = mapped_column(JSON, nullable=True) after_data_json: Mapped[dict[str, object] | list[object] | None] = mapped_column(JSON, nullable=True) request_path: Mapped[str | None] = mapped_column(String(255), nullable=True) request_method: Mapped[str | None] = mapped_column(String(16), nullable=True) ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True) user_agent: Mapped[str | None] = mapped_column(String(512), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, server_default=func.now(), ) actor: Mapped[Any] = relationship("Account", back_populates="audit_logs")