from rest_framework import mixins, viewsets from infrasynth.security.permissions import IsAuthenticatedAndPermitted from infrasynth.tenancy.context import get_current_tenant from .filters import APIInteractionLogFilter, ModelChangeLogFilter, SecurityEventFilter from .models import APIInteractionLog, ModelChangeLog, SecurityEvent from .serializers import ( APIInteractionLogSerializer, ModelChangeLogSerializer, SecurityEventSerializer, ) class _AuditScopedViewSet: """Audit rows are tenant-filtered for tenants; platform staff see all.""" def _scoped(self, model): from infrasynth.tenancy.services import TenantService qs = model.objects.select_related("actor").order_by("-timestamp") user = getattr(self.request, "user", None) if user is not None and getattr(user, "is_authenticated", False): if getattr(user, "is_superuser", False) or TenantService().is_platform_staff(user): return qs tenant = get_current_tenant() if tenant is None: return qs.none() return qs.filter(tenant_id=tenant.pk) class ModelChangeLogViewSet( _AuditScopedViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet ): serializer_class = ModelChangeLogSerializer permission_classes = [IsAuthenticatedAndPermitted] required_permissions = ["audit.view_model_changes"] filterset_class = ModelChangeLogFilter def get_queryset(self): return self._scoped(ModelChangeLog) class APIInteractionLogViewSet( _AuditScopedViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet ): serializer_class = APIInteractionLogSerializer permission_classes = [IsAuthenticatedAndPermitted] required_permissions = ["audit.view_api_logs"] filterset_class = APIInteractionLogFilter def get_queryset(self): return self._scoped(APIInteractionLog) class SecurityEventViewSet( _AuditScopedViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet ): serializer_class = SecurityEventSerializer permission_classes = [IsAuthenticatedAndPermitted] required_permissions = ["audit.view_security_events"] filterset_class = SecurityEventFilter def get_queryset(self): return self._scoped(SecurityEvent)