import json from django.contrib import admin from .models import AuditEvent from .utils import log_event PATCH_MARKER = "_cmmc_audit_admin_log_patch_installed" def _message_to_text(message): if isinstance(message, str): return message return json.dumps(message, default=str) def _admin_change_message(obj, message): details = _message_to_text(message) if details: return f"Admin changed {obj}: {details}" return f"Admin changed {obj}" def install_admin_audit_patch(): if getattr(admin.ModelAdmin, PATCH_MARKER, False): return original_log_addition = admin.ModelAdmin.log_addition original_log_change = admin.ModelAdmin.log_change original_log_deletion = admin.ModelAdmin.log_deletion original_log_deletions = admin.ModelAdmin.log_deletions def log_addition(self, request, obj, message): result = original_log_addition(self, request, obj, message) log_event( AuditEvent.Action.ADMIN_ADDITION, obj, message=f"Admin added {obj}", actor=getattr(request, "user", None), request=request, source=AuditEvent.Source.DJANGO_ADMIN, ) return result def log_change(self, request, obj, message): result = original_log_change(self, request, obj, message) log_event( AuditEvent.Action.ADMIN_CHANGE, obj, message=_admin_change_message(obj, message), actor=getattr(request, "user", None), request=request, source=AuditEvent.Source.DJANGO_ADMIN, ) return result def log_deletion(self, request, obj, object_repr): result = original_log_deletion(self, request, obj, object_repr) log_event( AuditEvent.Action.ADMIN_DELETION, obj, message=f"Admin deleted {object_repr}", actor=getattr(request, "user", None), request=request, source=AuditEvent.Source.DJANGO_ADMIN, target_repr=object_repr, ) return result def log_deletions(self, request, queryset): objects = list(queryset) result = original_log_deletions(self, request, queryset) for obj in objects: log_event( AuditEvent.Action.ADMIN_DELETION, obj, message=f"Admin deleted {obj}", actor=getattr(request, "user", None), request=request, source=AuditEvent.Source.DJANGO_ADMIN, ) return result admin.ModelAdmin.log_addition = log_addition admin.ModelAdmin.log_change = log_change admin.ModelAdmin.log_deletion = log_deletion admin.ModelAdmin.log_deletions = log_deletions setattr(admin.ModelAdmin, PATCH_MARKER, True)