petcare-api / audit /models.py
Sameer669
Initial PawCare Django backend with JWT auth, RBAC, audit logging, and HF storage
4f01198
"""
Audit Log Model β€” persists every sensitive action in the system.
Written to by the AuditLogMiddleware and signal handlers.
"""
import uuid
from django.db import models
from django.conf import settings
class AuditAction(models.TextChoices):
LOGIN = 'login', 'Login'
LOGOUT = 'logout', 'Logout'
LOGIN_FAILED = 'login_failed', 'Login Failed'
REGISTER = 'register', 'Register'
PASSWORD_CHANGE = 'password_change', 'Password Changed'
CREATE = 'create', 'Create'
UPDATE = 'update', 'Update'
DELETE = 'delete', 'Delete'
VIEW = 'view', 'View'
BOOKING_CREATE = 'booking_create', 'Booking Created'
BOOKING_UPDATE = 'booking_update', 'Booking Updated'
BOOKING_CANCEL = 'booking_cancel', 'Booking Cancelled'
CAREGIVER_ADD = 'caregiver_add', 'Caregiver Added'
CAREGIVER_UPDATE = 'caregiver_update', 'Caregiver Updated'
CAREGIVER_DELETE = 'caregiver_delete', 'Caregiver Deleted'
IMAGE_UPLOAD = 'image_upload', 'Image Uploaded'
DATA_EXPORT = 'data_export', 'Data Exported'
class AuditLog(models.Model):
"""Immutable audit trail β€” never update or delete records."""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# Who did it
actor = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True, blank=True,
related_name='audit_logs',
)
actor_email = models.EmailField(blank=True) # snapshot (actor may be deleted)
actor_role = models.CharField(max_length=20, blank=True)
# What happened
action = models.CharField(max_length=30, choices=AuditAction.choices)
description = models.TextField(blank=True)
# Target resource
resource_type = models.CharField(max_length=50, blank=True) # e.g. 'Caregiver'
resource_id = models.CharField(max_length=100, blank=True) # str(pk)
# Snapshot of changed data (sanitised β€” no raw passwords/keys)
before_state = models.JSONField(null=True, blank=True)
after_state = models.JSONField(null=True, blank=True)
# Request metadata
ip_address = models.GenericIPAddressField(null=True, blank=True)
user_agent = models.TextField(blank=True)
request_path = models.CharField(max_length=500, blank=True)
request_method = models.CharField(max_length=10, blank=True)
response_status = models.PositiveSmallIntegerField(null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
db_table = 'audit_logs'
ordering = ['-timestamp']
# No update/delete permissions at model level β€” enforced in admin
default_permissions = ('add', 'view') # no change/delete
def __str__(self):
return f'[{self.timestamp:%Y-%m-%d %H:%M}] {self.actor_email} β€” {self.action}'
def save(self, *args, **kwargs):
"""Snapshot actor info at write time."""
if self.actor and not self.actor_email:
self.actor_email = self.actor.email
self.actor_role = self.actor.role
super().save(*args, **kwargs)