Skip to content

Commit 70fea8e

Browse files
fix: IO-756 Reduce cognitive complexity in permissions.py
Refactor has_object_permission function to reduce cognitive complexity
1 parent 621a287 commit 70fea8e

1 file changed

Lines changed: 26 additions & 25 deletions

File tree

infraohjelmointi_api/permissions.py

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -551,43 +551,44 @@ def has_permission(self, request, view):
551551

552552
return False
553553

554-
def has_object_permission(self, request, view, obj):
555-
"""Check if user has permission for this specific object"""
554+
def _get_target_class_path_for_restricted_edit(self, obj):
555+
"""Resolve project class path for restricted programmer object checks."""
556556
_type = obj._meta.model.__name__
557+
if _type == "Project":
558+
return obj.projectClass.path if obj.projectClass else None
559+
if _type == "Note":
560+
target_project = obj.project
561+
if target_project and target_project.projectClass:
562+
return target_project.projectClass.path
563+
return None
564+
if _type == "ProjectGroup":
565+
return obj.classRelation.path if obj.classRelation else None
566+
return None
567+
568+
@staticmethod
569+
def _target_path_matches_assigned_paths(target_class_path, assigned_paths):
570+
"""True if target equals or is a child of an assigned path (paths use '/')."""
571+
for path in assigned_paths:
572+
if target_class_path == path or target_class_path.startswith(path + "/"):
573+
return True
574+
return False
557575

558-
# Coordinators and admins bypass restrictions
576+
def has_object_permission(self, request, view, obj):
577+
"""Check if user has permission for this specific object"""
559578
if self.user_is_coordinator_or_admin(request):
560579
return True
561580

562-
# Allow read actions for all objects (lists/retrievals)
563581
if view.action in DJANGO_BASE_READ_ONLY_ACTIONS:
564582
return True
565583

566-
# For edit actions, identify the relevant class path
567-
target_class_path = None
568-
569-
if _type == "Project":
570-
target_class_path = obj.projectClass.path if obj.projectClass else None
571-
elif _type == "Note":
572-
target_project = obj.project
573-
target_class_path = target_project.projectClass.path if target_project and target_project.projectClass else None
574-
elif _type == "ProjectGroup":
575-
# For groups, we check the classRelation
576-
target_class_path = obj.classRelation.path if obj.classRelation else None
577-
578-
# If we couldn't find a target class path to validate against, deny edit
584+
target_class_path = self._get_target_class_path_for_restricted_edit(obj)
579585
if not target_class_path:
580586
return False
581587

582-
# Get all class paths assigned to user
583588
assigned_paths = self.get_user_assigned_classes_paths(request)
584589
if not assigned_paths:
585590
return False
586591

587-
# Check if target class matches or is a child of any assigned path.
588-
# Child paths are separated by "/", so we check exact match or prefix + "/".
589-
for path in assigned_paths:
590-
if target_class_path == path or target_class_path.startswith(path + "/"):
591-
return True
592-
593-
return False
592+
return self._target_path_matches_assigned_paths(
593+
target_class_path, assigned_paths
594+
)

0 commit comments

Comments
 (0)