"""Kit base viewsets with model-derived permissions wired in. Subclass one of these in a consuming app and CRUD/view endpoints require the auto-derived codename (``{app}.{verb}_{model}``) with no per-view configuration:: from infrasynth.security.viewsets import InfraSynthModelViewSet class TicketViewSet(InfraSynthModelViewSet): queryset = Ticket.objects.all() serializer_class = TicketSerializer # needs view/add/change/delete_ticket An explicit ``required_permissions`` still wins, and custom actions can name their own codename with ``action_permissions = {"resolve": "helpdesk.resolve_ticket"}``. """ from __future__ import annotations from rest_framework import viewsets from .permissions import IsAuthenticatedAndPermitted __all__ = [ "InfraSynthModelViewSet", "InfraSynthReadOnlyModelViewSet", "AutoPermissionMixin", ] class AutoPermissionMixin: """Marks a viewset as opting into auto-derived model permissions.""" auto_permissions = True class InfraSynthModelViewSet(AutoPermissionMixin, viewsets.ModelViewSet): """Full CRUD viewset: derives view/add/change/delete permissions.""" permission_classes = [IsAuthenticatedAndPermitted] class InfraSynthReadOnlyModelViewSet(AutoPermissionMixin, viewsets.ReadOnlyModelViewSet): """Read-only viewset: derives the view permission.""" permission_classes = [IsAuthenticatedAndPermitted]