Skip to content

Commit bc120b8

Browse files
authored
Dojo Meta: Fix response status codes and refactor permission checks (#14280)
* Fix response status codes in DojoMetaViewSet for POST and PATCH methods * Refactor UserHasDojoMetaPermission to use a permission map for cleaner permission checks
1 parent 6c1d2af commit bc120b8

2 files changed

Lines changed: 74 additions & 88 deletions

File tree

dojo/api_v2/permissions.py

Lines changed: 71 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -226,103 +226,87 @@ def has_object_permission(self, request, view, obj):
226226

227227

228228
class UserHasDojoMetaPermission(permissions.BasePermission):
229+
permission_map = {
230+
"product": {
231+
"model": Product,
232+
"permissions": {
233+
"get_permission": Permissions.Product_View,
234+
"put_permission": Permissions.Product_Edit,
235+
"delete_permission": Permissions.Product_Edit,
236+
"post_permission": Permissions.Product_Edit,
237+
},
238+
},
239+
"finding": {
240+
"model": Finding,
241+
"permissions": {
242+
"get_permission": Permissions.Finding_View,
243+
"put_permission": Permissions.Finding_Edit,
244+
"delete_permission": Permissions.Finding_Edit,
245+
"post_permission": Permissions.Finding_Edit,
246+
},
247+
},
248+
"location": {
249+
"model": Location,
250+
"permissions": {
251+
"get_permission": Permissions.Location_View,
252+
"put_permission": Permissions.Location_Edit,
253+
"delete_permission": Permissions.Location_Edit,
254+
"post_permission": Permissions.Location_Edit,
255+
},
256+
},
257+
# TODO: Delete this after the move to Locations
258+
"endpoint": {
259+
"model": Endpoint if not settings.V3_FEATURE_LOCATIONS else Location,
260+
"permissions": {
261+
"get_permission": Permissions.Location_View,
262+
"put_permission": Permissions.Location_Edit,
263+
"delete_permission": Permissions.Location_Edit,
264+
"post_permission": Permissions.Location_Edit,
265+
},
266+
},
267+
}
268+
229269
def has_permission(self, request, view):
230-
if request.method == "POST":
231-
has_permission_result = True
232-
product_id = request.data.get("product", None)
233-
if product_id:
234-
obj = get_object_or_404(Product, pk=product_id)
235-
has_permission_result = (
236-
has_permission_result
237-
and user_has_permission(
238-
request.user, obj, Permissions.Product_Edit,
239-
)
240-
)
241-
finding_id = request.data.get("finding", None)
242-
if finding_id:
243-
obj = get_object_or_404(Finding, pk=finding_id)
244-
has_permission_result = (
245-
has_permission_result
246-
and user_has_permission(
247-
request.user, obj, Permissions.Finding_Edit,
248-
)
249-
)
250-
location_id = request.data.get("location", None)
251-
if location_id:
252-
obj = get_object_or_404(Location, pk=location_id)
253-
has_permission_result = (
254-
has_permission_result
255-
and user_has_permission(
256-
request.user, obj, Permissions.Location_Edit,
257-
)
258-
)
259-
# TODO: Delete this after the move to Locations
260-
endpoint_id = request.data.get("endpoint", None)
261-
if endpoint_id:
262-
if settings.V3_FEATURE_LOCATIONS:
263-
obj = get_object_or_404(Location, pk=endpoint_id)
264-
else:
265-
obj = get_object_or_404(Endpoint, pk=endpoint_id)
266-
has_permission_result = (
267-
has_permission_result
268-
and user_has_permission(
269-
request.user, obj, Permissions.Location_Edit,
270-
)
271-
)
272-
return has_permission_result
270+
method_to_permission_map = {
271+
"GET": "get_permission",
272+
"POST": "post_permission",
273+
# PATCH is generally not used here, but this endpoint is sorta odd...
274+
"PATCH": "put_permission",
275+
}
276+
for request_method, permission_type in method_to_permission_map.items():
277+
if request.method == request_method:
278+
has_permission_result = True
279+
for model_field, schema in self.permission_map.items():
280+
if (object_id := request.data.get(model_field)) is not None:
281+
obj = get_object_or_404(
282+
schema["model"],
283+
pk=object_id,
284+
)
285+
has_permission_result = (
286+
has_permission_result
287+
and user_has_permission(
288+
request.user,
289+
obj,
290+
schema["permissions"][permission_type],
291+
)
292+
)
293+
return has_permission_result
294+
# If we exit the loop at some point, we must not checking perms for that request method
273295
return True
274296

275297
def has_object_permission(self, request, view, obj):
276298
has_permission_result = True
277-
product = obj.product
278-
if product:
279-
has_permission_result = (
280-
has_permission_result
281-
and check_object_permission(
282-
request,
283-
product,
284-
Permissions.Product_View,
285-
Permissions.Product_Edit,
286-
Permissions.Product_Edit,
287-
)
288-
)
289-
finding = obj.finding
290-
if finding:
291-
has_permission_result = (
292-
has_permission_result
293-
and check_object_permission(
294-
request,
295-
finding,
296-
Permissions.Finding_View,
297-
Permissions.Finding_Edit,
298-
Permissions.Finding_Edit,
299-
)
300-
)
301-
location = obj.location
302-
if location:
303-
has_permission_result = (
304-
has_permission_result
305-
and check_object_permission(
306-
request,
307-
location,
308-
Permissions.Location_View,
309-
Permissions.Location_Edit,
310-
Permissions.Location_Edit,
311-
)
312-
)
313-
# TODO: Delete this after the move to Locations
314-
endpoint = obj.endpoint
315-
if endpoint:
316-
has_permission_result = (
299+
for model_field, schema in self.permission_map.items():
300+
if (object_model := getattr(obj, model_field, None)) is not None:
301+
has_permission_result = (
317302
has_permission_result
318303
and check_object_permission(
319304
request,
320-
endpoint,
321-
Permissions.Location_View,
322-
Permissions.Location_Edit,
323-
Permissions.Location_Edit,
305+
object_model,
306+
**schema["permissions"],
324307
)
325308
)
309+
326310
return has_permission_result
327311

328312

dojo/api_v2/views.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1707,10 +1707,12 @@ def batch(self, request, pk=None):
17071707
if serialized_data.is_valid(raise_exception=True):
17081708
if request.method == "POST":
17091709
self.process_post(request.data)
1710+
status_code = status.HTTP_201_CREATED
17101711
if request.method == "PATCH":
17111712
self.process_patch(request.data)
1713+
status_code = status.HTTP_200_OK
17121714

1713-
return Response(status=status.HTTP_201_CREATED, data=serialized_data.data)
1715+
return Response(status=status_code, data=serialized_data.data)
17141716

17151717
def process_post(self: object, data: dict):
17161718
product = Product.objects.filter(id=data.get("product")).first()

0 commit comments

Comments
 (0)