Coverage for users/api/views.py: 90%
71 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1import logging
3from django.db.models import Count
4from drf_spectacular.types import OpenApiTypes
5from drf_spectacular.utils import extend_schema
6from rest_framework.permissions import IsAuthenticated
7from rest_framework.response import Response
8from rest_framework.routers import APIRootView
9from rest_framework.status import HTTP_201_CREATED
10from rest_framework.views import APIView
11from rest_framework.viewsets import ViewSet
13from netbox.api.viewsets import NetBoxModelViewSet
14from users import filtersets
15from users.models import Group, ObjectPermission, Owner, OwnerGroup, Token, User, UserConfig
16from utilities.data import deepmerge
17from utilities.querysets import RestrictedQuerySet
19from . import serializers
22class UsersRootView(APIRootView):
23 """
24 Users API root view
25 """
26 def get_view_name(self):
27 return 'Users'
30#
31# Users and groups
32#
34class UserViewSet(NetBoxModelViewSet):
35 queryset = RestrictedQuerySet(model=User).order_by('username')
36 serializer_class = serializers.UserSerializer
37 filterset_class = filtersets.UserFilterSet
40class GroupViewSet(NetBoxModelViewSet):
41 queryset = Group.objects.annotate(user_count=Count('user'))
42 serializer_class = serializers.GroupSerializer
43 filterset_class = filtersets.GroupFilterSet
46#
47# REST API tokens
48#
50class TokenViewSet(NetBoxModelViewSet):
51 queryset = Token.objects.all()
52 serializer_class = serializers.TokenSerializer
53 filterset_class = filtersets.TokenFilterSet
54 # A created v2 Token's plaintext must not be retained in a job record.
55 background_enabled = False
58class TokenProvisionView(APIView):
59 """
60 Non-authenticated REST API endpoint via which a user may create a Token.
61 """
62 permission_classes = []
64 @extend_schema(
65 request=serializers.TokenProvisionSerializer,
66 responses={
67 201: serializers.TokenProvisionSerializer,
68 401: OpenApiTypes.OBJECT,
69 }
70 )
71 def post(self, request):
72 serializer = serializers.TokenProvisionSerializer(data=request.data, context={'request': request})
73 serializer.is_valid(raise_exception=True)
74 self.perform_create(serializer)
75 return Response(serializer.data, status=HTTP_201_CREATED)
77 def perform_create(self, serializer):
78 model = serializer.Meta.model
79 logger = logging.getLogger('netbox.api.views.TokenProvisionView')
80 logger.info(f"Creating new {model._meta.verbose_name}")
81 serializer.save()
84#
85# ObjectPermissions
86#
88class ObjectPermissionViewSet(NetBoxModelViewSet):
89 queryset = ObjectPermission.objects.all()
90 serializer_class = serializers.ObjectPermissionSerializer
91 filterset_class = filtersets.ObjectPermissionFilterSet
94#
95# Owners
96#
98class OwnerGroupViewSet(NetBoxModelViewSet):
99 queryset = OwnerGroup.objects.all()
100 serializer_class = serializers.OwnerGroupSerializer
101 filterset_class = filtersets.OwnerGroupFilterSet
104class OwnerViewSet(NetBoxModelViewSet):
105 queryset = Owner.objects.all()
106 serializer_class = serializers.OwnerSerializer
107 filterset_class = filtersets.OwnerFilterSet
110#
111# User preferences
112#
114class UserConfigViewSet(ViewSet):
115 """
116 An API endpoint via which a user can update his or her own UserConfig data (but no one else's).
117 """
118 permission_classes = [IsAuthenticated]
120 def get_queryset(self):
121 return UserConfig.objects.filter(user=self.request.user)
123 @extend_schema(responses={200: OpenApiTypes.OBJECT})
124 def list(self, request):
125 """
126 Return the UserConfig for the currently authenticated User.
127 """
128 userconfig = self.get_queryset().first()
130 return Response(userconfig.data)
132 @extend_schema(methods=["patch"], responses={201: OpenApiTypes.OBJECT})
133 def patch(self, request):
134 """
135 Update the UserConfig for the currently authenticated User.
136 """
137 # TODO: How can we validate this data?
138 userconfig = self.get_queryset().first()
139 userconfig.data = deepmerge(userconfig.data, request.data)
140 userconfig.save()
142 return Response(userconfig.data)