From 2cfecd7052dd120452cf5a09ed98c29f7c363cb9 Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Fri, 20 Feb 2026 13:45:52 -0600 Subject: [PATCH] Add ModelAction and register_model_actions() API for custom permission actions --- netbox/netbox/registry.py | 1 + netbox/utilities/permissions.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/netbox/netbox/registry.py b/netbox/netbox/registry.py index 829d0de93..c1d757e92 100644 --- a/netbox/netbox/registry.py +++ b/netbox/netbox/registry.py @@ -28,6 +28,7 @@ registry = Registry({ 'denormalized_fields': collections.defaultdict(list), 'event_types': dict(), 'filtersets': dict(), + 'model_actions': collections.defaultdict(list), 'model_features': dict(), 'models': collections.defaultdict(set), 'plugins': dict(), diff --git a/netbox/utilities/permissions.py b/netbox/utilities/permissions.py index 81a1ff70b..c442b2030 100644 --- a/netbox/utilities/permissions.py +++ b/netbox/utilities/permissions.py @@ -1,19 +1,46 @@ +from dataclasses import dataclass + from django.apps import apps from django.conf import settings -from django.db.models import Q +from django.db.models import Model, Q from django.utils.translation import gettext_lazy as _ +from netbox.registry import registry from users.constants import CONSTRAINT_TOKEN_USER __all__ = ( + 'ModelAction', 'get_permission_for_model', 'permission_is_exempt', 'qs_filter_from_constraints', + 'register_model_actions', 'resolve_permission', 'resolve_permission_type', ) +@dataclass +class ModelAction: + name: str + help_text: str = '' + + def __hash__(self): + return hash(self.name) + + def __eq__(self, other): + if isinstance(other, ModelAction): + return self.name == other.name + return self.name == other + + +def register_model_actions(model: type[Model], actions: list[ModelAction | str]): + label = f'{model._meta.app_label}.{model._meta.model_name}' + for action in actions: + if isinstance(action, str): + action = ModelAction(name=action) + registry['model_actions'][label].append(action) + + def get_permission_for_model(model, action): """ Resolve the named permission for a given model (or instance) and action (e.g. view or add).