miningniti-api / app /models /audit.py
Milan Soni
Deploy MiningNiti API with production RAG pipeline
3a7eb07
Raw
History Blame Contribute Delete
3.84 kB
"""
Audit Log Model
Enterprise compliance logging for all user actions
"""
import uuid
from datetime import datetime
from enum import Enum
from sqlalchemy import JSON, Column, DateTime, String, Text
from sqlalchemy.dialects.postgresql import JSONB as PG_JSONB
from sqlalchemy.dialects.postgresql import UUID
JSONB = JSON().with_variant(PG_JSONB, "postgresql")
from app.models.base import Base, UUIDMixin
class AuditAction(str, Enum):
"""Types of auditable actions"""
# Document actions
DOCUMENT_UPLOAD = "document.upload"
DOCUMENT_VIEW = "document.view"
DOCUMENT_DELETE = "document.delete"
DOCUMENT_PROCESS = "document.process"
# Chat actions
CHAT_CREATE = "chat.create"
CHAT_MESSAGE = "chat.message"
CHAT_DELETE = "chat.delete"
# User actions
USER_LOGIN = "user.login"
USER_LOGOUT = "user.logout"
USER_PROFILE_UPDATE = "user.profile_update"
# Admin actions
ADMIN_ACTION = "admin.action"
# System actions
SYSTEM_ERROR = "system.error"
AI_ANALYSIS = "ai.analysis"
class AuditLog(Base, UUIDMixin):
"""
Immutable audit log for enterprise compliance.
Tracks all user actions and system events.
"""
__tablename__ = "audit_logs"
# Who
user_id = Column(
String(255), nullable=True, index=True
) # Nullable for system events
user_email = Column(String(255), nullable=True)
# What
action = Column(String(100), nullable=False, index=True)
resource_type = Column(String(50), nullable=True) # document, chat, user
resource_id = Column(String(255), nullable=True)
# Details
description = Column(Text, nullable=True)
details = Column(JSONB, default={})
# Example details:
# {
# "file_name": "safety_manual.pdf",
# "file_size": 1024000,
# "category": "safety_protocol"
# }
# When
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
# Where
ip_address = Column(String(50), nullable=True)
user_agent = Column(Text, nullable=True)
# Outcome
success = Column(String(10), default="true") # true, false, partial
error_message = Column(Text, nullable=True)
def __repr__(self):
return f"<AuditLog {self.action} by {self.user_id}>"
def to_dict(self):
"""Convert to dictionary for API responses"""
return {
"id": str(self.id),
"user_id": self.user_id,
"action": self.action,
"resource_type": self.resource_type,
"resource_id": self.resource_id,
"description": self.description,
"details": self.details,
"timestamp": self.timestamp.isoformat() if self.timestamp else None,
"success": self.success,
}
def create_audit_log(
action: str,
user_id: str = None,
user_email: str = None,
resource_type: str = None,
resource_id: str = None,
description: str = None,
details: dict = None,
ip_address: str = None,
user_agent: str = None,
success: str = "true",
error_message: str = None,
) -> AuditLog:
"""
Factory function to create audit log entries.
Usage:
log = create_audit_log(
action=AuditAction.DOCUMENT_UPLOAD.value,
user_id=current_user.id,
resource_type="document",
resource_id=str(doc.id),
details={"file_name": doc.file_name}
)
db.add(log)
"""
return AuditLog(
action=action,
user_id=user_id,
user_email=user_email,
resource_type=resource_type,
resource_id=resource_id,
description=description,
details=details or {},
ip_address=ip_address,
user_agent=user_agent,
success=success,
error_message=error_message,
)