feat: audit ai config changes
This commit is contained in:
+136
-1
@@ -1,7 +1,8 @@
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import AiModel, ModelAlias
|
||||
from .audit import create_config_audit_log, snapshot_config
|
||||
from .models import AiConfigAuditLog, AiModel, ModelAlias
|
||||
from .security import AiKeyEncryptionError, encrypt_api_key
|
||||
|
||||
|
||||
@@ -98,6 +99,53 @@ class AiModelAdmin(admin.ModelAdmin):
|
||||
def api_key_status(self, obj):
|
||||
return obj.api_key_masked or "not set"
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
before = _snapshot_existing(obj) if change else None
|
||||
super().save_model(request, obj, form, change)
|
||||
create_config_audit_log(
|
||||
actor=request.user,
|
||||
action=(
|
||||
AiConfigAuditLog.Action.UPDATE
|
||||
if change
|
||||
else AiConfigAuditLog.Action.CREATE
|
||||
),
|
||||
instance=obj,
|
||||
before=before,
|
||||
after=snapshot_config(obj),
|
||||
)
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
before = snapshot_config(obj)
|
||||
target_id = obj.pk
|
||||
target_repr = str(obj)
|
||||
super().delete_model(request, obj)
|
||||
create_config_audit_log(
|
||||
actor=request.user,
|
||||
action=AiConfigAuditLog.Action.DELETE,
|
||||
instance=obj,
|
||||
before=before,
|
||||
after=None,
|
||||
target_id=target_id,
|
||||
target_repr=target_repr,
|
||||
)
|
||||
|
||||
def delete_queryset(self, request, queryset):
|
||||
snapshots = [
|
||||
(obj, obj.pk, str(obj), snapshot_config(obj))
|
||||
for obj in queryset
|
||||
]
|
||||
super().delete_queryset(request, queryset)
|
||||
for obj, target_id, target_repr, before in snapshots:
|
||||
create_config_audit_log(
|
||||
actor=request.user,
|
||||
action=AiConfigAuditLog.Action.DELETE,
|
||||
instance=obj,
|
||||
before=before,
|
||||
after=None,
|
||||
target_id=target_id,
|
||||
target_repr=target_repr,
|
||||
)
|
||||
|
||||
|
||||
@admin.register(ModelAlias)
|
||||
class ModelAliasAdmin(admin.ModelAdmin):
|
||||
@@ -113,3 +161,90 @@ class ModelAliasAdmin(admin.ModelAdmin):
|
||||
search_fields = ("alias", "ai_model__name", "ai_model__model")
|
||||
autocomplete_fields = ("ai_model",)
|
||||
readonly_fields = ("created_at", "updated_at")
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
before = _snapshot_existing(obj) if change else None
|
||||
super().save_model(request, obj, form, change)
|
||||
create_config_audit_log(
|
||||
actor=request.user,
|
||||
action=(
|
||||
AiConfigAuditLog.Action.UPDATE
|
||||
if change
|
||||
else AiConfigAuditLog.Action.CREATE
|
||||
),
|
||||
instance=obj,
|
||||
before=before,
|
||||
after=snapshot_config(obj),
|
||||
)
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
before = snapshot_config(obj)
|
||||
target_id = obj.pk
|
||||
target_repr = str(obj)
|
||||
super().delete_model(request, obj)
|
||||
create_config_audit_log(
|
||||
actor=request.user,
|
||||
action=AiConfigAuditLog.Action.DELETE,
|
||||
instance=obj,
|
||||
before=before,
|
||||
after=None,
|
||||
target_id=target_id,
|
||||
target_repr=target_repr,
|
||||
)
|
||||
|
||||
def delete_queryset(self, request, queryset):
|
||||
snapshots = [
|
||||
(obj, obj.pk, str(obj), snapshot_config(obj))
|
||||
for obj in queryset
|
||||
]
|
||||
super().delete_queryset(request, queryset)
|
||||
for obj, target_id, target_repr, before in snapshots:
|
||||
create_config_audit_log(
|
||||
actor=request.user,
|
||||
action=AiConfigAuditLog.Action.DELETE,
|
||||
instance=obj,
|
||||
before=before,
|
||||
after=None,
|
||||
target_id=target_id,
|
||||
target_repr=target_repr,
|
||||
)
|
||||
|
||||
|
||||
@admin.register(AiConfigAuditLog)
|
||||
class AiConfigAuditLogAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"created_at",
|
||||
"actor",
|
||||
"action",
|
||||
"target_type",
|
||||
"target_id",
|
||||
"target_repr",
|
||||
"changed_fields_display",
|
||||
)
|
||||
list_filter = ("action", "target_type", "created_at")
|
||||
search_fields = (
|
||||
"target_repr",
|
||||
"actor__username",
|
||||
"actor__email",
|
||||
)
|
||||
ordering = ("-created_at", "-id")
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
return tuple(field.name for field in self.model._meta.fields)
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
@admin.display(description="changed fields")
|
||||
def changed_fields_display(self, obj):
|
||||
return ", ".join(obj.changed_fields)
|
||||
|
||||
|
||||
def _snapshot_existing(obj):
|
||||
return snapshot_config(obj.__class__.objects.get(pk=obj.pk))
|
||||
|
||||
Reference in New Issue
Block a user