Coverage for netbox/api/metadata.py: 87%

30 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 18:35 +0000

1from django.core.exceptions import PermissionDenied 

2from django.http import Http404 

3from django.utils.encoding import force_str 

4from rest_framework import exceptions 

5from rest_framework.metadata import SimpleMetadata 

6from rest_framework.request import clone_request 

7 

8from netbox.api.fields import ContentTypeField 

9 

10 

11class BulkOperationMetadata(SimpleMetadata): 

12 

13 def determine_actions(self, request, view): 

14 """ 

15 Replace the stock determine_actions() method to assess object permissions only 

16 when viewing a specific object. This is necessary to support OPTIONS requests 

17 with bulk update in place (see #5470). 

18 """ 

19 actions = {} 

20 for method in {'PUT', 'POST'} & set(view.allowed_methods): 

21 view.request = clone_request(request, method) 

22 try: 

23 # Test global permissions 

24 if hasattr(view, 'check_permissions'): 24 ↛ 27line 24 didn't jump to line 27 because the condition on line 24 was always true

25 view.check_permissions(view.request) 

26 # Test object permissions (if viewing a specific object) 

27 if method == 'PUT' and view.lookup_url_kwarg and hasattr(view, 'get_object'): 27 ↛ 28line 27 didn't jump to line 28 because the condition on line 27 was never true

28 view.get_object() 

29 except (exceptions.APIException, PermissionDenied, Http404): 

30 pass 

31 else: 

32 # If user has appropriate permissions for the view, include 

33 # appropriate metadata about the fields that should be supplied. 

34 serializer = view.get_serializer() 

35 actions[method] = self.get_serializer_info(serializer) 

36 finally: 

37 view.request = request 

38 

39 return actions 

40 

41 

42class ContentTypeMetadata(BulkOperationMetadata): 

43 

44 def get_field_info(self, field): 

45 field_info = super().get_field_info(field) 

46 if hasattr(field, 'queryset') and not field_info.get('read_only') and isinstance(field, ContentTypeField): 

47 field_info['choices'] = [ 

48 { 

49 'value': choice_value, 

50 'display_name': force_str(choice_name, strings_only=True) 

51 } 

52 for choice_value, choice_name in field.choices.items() 

53 ] 

54 field_info['choices'].sort(key=lambda item: item['display_name']) 

55 return field_info