| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- """
- AuditLog model - tracks all user actions.
- """
- from sqlalchemy import BigInteger, ForeignKey, Integer, String
- from sqlalchemy.dialects.postgresql import INET, JSONB
- from sqlalchemy.orm import Mapped, mapped_column, relationship
- from app.models.base import Base
- class AuditLog(Base):
- """
- Audit log model for tracking user actions.
- Logs every action: login, view, create, update, delete, export, etc.
- """
- __tablename__ = "audit_logs"
- id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
- # Who
- user_id: Mapped[int | None] = mapped_column(
- ForeignKey("users.id", ondelete="SET NULL")
- )
- user_email: Mapped[str | None] = mapped_column(
- String(255)
- ) # Cached for deleted users
- organization_id: Mapped[int | None] = mapped_column(
- ForeignKey("organizations.id", ondelete="SET NULL")
- )
- # What
- action: Mapped[str] = mapped_column(
- String(50), nullable=False
- ) # login, logout, failed_login, view, create, update, delete, export, etc.
- resource_type: Mapped[str | None] = mapped_column(
- String(50)
- ) # device, user, location, beacon, etc.
- resource_id: Mapped[int | None] = mapped_column(Integer)
- # Details
- description: Mapped[str | None] = mapped_column(String)
- changes: Mapped[dict | None] = mapped_column(JSONB) # Before/after values
- # When & Where
- ip_address: Mapped[str | None] = mapped_column(INET)
- user_agent: Mapped[str | None] = mapped_column(String)
- # Relationships
- user: Mapped["User | None"] = relationship("User", back_populates="audit_logs")
- organization: Mapped["Organization | None"] = relationship("Organization")
- def __repr__(self) -> str:
- return f"<AuditLog {self.id}: {self.action} by {self.user_email}>"
|