diff --git a/greenmine/base/permissions.py b/greenmine/base/permissions.py new file mode 100644 index 00000000..bb7c1d8f --- /dev/null +++ b/greenmine/base/permissions.py @@ -0,0 +1,42 @@ +from rest_framework import permissions + +from greenmine.scrum.models import Membership + +def has_project_perm(user, project, perm): + if user.is_authenticated(): + try: + membership = Membership.objects.get(project=project, user=user) + if membership.role.permissions.filter(codename=perm).count() > 0: + return True + except Membership.DoesNotExist: + pass + return False + + +class BaseDetailPermission(permissions.BasePermission): + get_permission = None + put_permission = None + delete_permission = None + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = [] + + def has_object_permission(self, request, view, obj): + if request.method in self.safe_methods: + return True + + project_obj = obj + for attrib in self.path_to_project: + project_obj = getattr(project_obj, attrib) + + if request.method == "GET": + return has_project_perm(request.user, project_obj, self.get_permission) + + elif request.method == "PUT": + return has_project_perm(request.user, project_obj, self.put_permission) + + elif request.method == "DELETE": + return has_project_perm(request.user, project_obj, self.delete_permission) + + return False + + diff --git a/greenmine/scrum/api.py b/greenmine/scrum/api.py index 329a3547..3e6b8ffd 100644 --- a/greenmine/scrum/api.py +++ b/greenmine/scrum/api.py @@ -73,6 +73,7 @@ class UserStoryList(SimpleFilterMixin, generics.ListCreateAPIView): class UserStoryDetail(generics.RetrieveUpdateDestroyAPIView): model = UserStory serializer_class = UserStorySerializer + permission_classes = (UserStoryDetailPermission,) class ChangeList(generics.ListCreateAPIView): @@ -86,6 +87,7 @@ class ChangeList(generics.ListCreateAPIView): class ChangeDetail(generics.RetrieveUpdateDestroyAPIView): model = Change serializer_class = ChangeSerializer + permission_classes = (ChangeDetailPermission,) class ChangeAttachmentList(generics.ListCreateAPIView): @@ -99,6 +101,7 @@ class ChangeAttachmentList(generics.ListCreateAPIView): class ChangeAttachmentDetail(generics.RetrieveUpdateDestroyAPIView): model = ChangeAttachment serializer_class = ChangeAttachmentSerializer + permission_classes = (ChangeAttachmentDetailPermission,) class IssueList(generics.ListCreateAPIView): @@ -113,6 +116,7 @@ class IssueList(generics.ListCreateAPIView): class IssueDetail(generics.RetrieveUpdateDestroyAPIView): model = Issue serializer_class = IssueSerializer + permission_classes = (IssueDetailPermission,) class TaskList(generics.ListCreateAPIView): @@ -127,6 +131,7 @@ class TaskList(generics.ListCreateAPIView): class TaskDetail(generics.RetrieveUpdateDestroyAPIView): model = Task serializer_class = TaskSerializer + permission_classes = (TaskDetailPermission,) class SeverityList(generics.ListCreateAPIView): @@ -141,6 +146,7 @@ class SeverityList(generics.ListCreateAPIView): class SeverityDetail(generics.RetrieveUpdateDestroyAPIView): model = Severity serializer_class = SeveritySerializer + permission_classes = (SeverityDetailPermission,) class IssueStatusList(generics.ListCreateAPIView): @@ -155,6 +161,7 @@ class IssueStatusList(generics.ListCreateAPIView): class IssueStatusDetail(generics.RetrieveUpdateDestroyAPIView): model = IssueStatus serializer_class = IssueStatusSerializer + permission_classes = (IssueStatusDetailPermission,) class TaskStatusList(SimpleFilterMixin, generics.ListCreateAPIView): @@ -169,6 +176,7 @@ class TaskStatusList(SimpleFilterMixin, generics.ListCreateAPIView): class TaskStatusDetail(generics.RetrieveUpdateDestroyAPIView): model = TaskStatus serializer_class = TaskStatusSerializer + permission_classes = (TaskStatusDetailPermission,) class UserStoryStatusList(generics.ListCreateAPIView): @@ -183,6 +191,7 @@ class UserStoryStatusList(generics.ListCreateAPIView): class UserStoryStatusDetail(generics.RetrieveUpdateDestroyAPIView): model = UserStoryStatus serializer_class = UserStoryStatusSerializer + permission_classes = (UserStoryStatusDetailPermission,) class PriorityList(generics.ListCreateAPIView): @@ -197,6 +206,7 @@ class PriorityList(generics.ListCreateAPIView): class PriorityDetail(generics.RetrieveUpdateDestroyAPIView): model = Priority serializer_class = PrioritySerializer + permission_classes = (PriorityDetailPermission,) class IssueTypeList(generics.ListCreateAPIView): @@ -211,6 +221,7 @@ class IssueTypeList(generics.ListCreateAPIView): class IssueTypeDetail(generics.RetrieveUpdateDestroyAPIView): model = IssueType serializer_class = IssueTypeSerializer + permission_classes = (IssueTypeDetailPermission,) class PointsList(generics.ListCreateAPIView): @@ -225,3 +236,4 @@ class PointsList(generics.ListCreateAPIView): class PointsDetail(generics.RetrieveUpdateDestroyAPIView): model = Points serializer_class = PointsSerializer + permission_classes = (PointsDetailPermission,) diff --git a/greenmine/scrum/permissions.py b/greenmine/scrum/permissions.py index bc4d20a0..df8178e3 100644 --- a/greenmine/scrum/permissions.py +++ b/greenmine/scrum/permissions.py @@ -1,43 +1,4 @@ -from rest_framework import permissions - -from greenmine.scrum.models import Membership - -def has_project_perm(user, project, perm): - if user.is_authenticated(): - try: - membership = Membership.objects.get(project=project, user=user) - if membership.role.permissions.filter(codename=perm).count() > 0: - return True - except Membership.DoesNotExist: - pass - return False - - -class BaseDetailPermission(permissions.BasePermission): - get_permission = None - put_permission = None - delete_permission = None - safe_methods = ['HEAD', 'OPTIONS'] - path_to_project = [] - - def has_object_permission(self, request, view, obj): - if request.method in self.safe_methods: - return True - - project_obj = obj - for attrib in self.path_to_project: - project_obj = getattr(project_obj, attrib) - - if request.method == "GET": - return has_project_perm(request.user, project_obj, self.get_permission) - - elif request.method == "PUT": - return has_project_perm(request.user, project_obj, self.put_permission) - - elif request.method == "DELETE": - return has_project_perm(request.user, project_obj, self.delete_permission) - - return False +from greenmine.base.permissions import BaseDetailPermission class ProjectDetailPermission(BaseDetailPermission): get_permission = "can_view_project" @@ -59,3 +20,80 @@ class UserStoryDetailPermission(BaseDetailPermission): delete_permission = "can_delete_userstory" safe_methods = ['HEAD', 'OPTIONS'] path_to_project = ['project'] + +class TaskDetailPermission(BaseDetailPermission): + get_permission = "can_view_task" + put_permission = "can_change_task" + delete_permission = "can_delete_task" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class IssueDetailPermission(BaseDetailPermission): + get_permission = "can_view_issue" + put_permission = "can_change_issue" + delete_permission = "can_delete_issue" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class ChangeDetailPermission(BaseDetailPermission): + get_permission = "can_view_change" + put_permission = "can_change_change" + delete_permission = "can_delete_change" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class ChangeAttachmentDetailPermission(BaseDetailPermission): + get_permission = "can_view_changeattachment" + put_permission = "can_change_changeattachment" + delete_permission = "can_delete_changeattachment" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['change', 'project'] + +class SeverityDetailPermission(BaseDetailPermission): + get_permission = "can_view_severity" + put_permission = "can_severity_severity" + delete_permission = "can_delete_severity" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class IssueStatusDetailPermission(BaseDetailPermission): + get_permission = "can_view_issuestatus" + put_permission = "can_severity_issuestatus" + delete_permission = "can_delete_issuestatus" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class TaskStatusDetailPermission(BaseDetailPermission): + get_permission = "can_view_taskstatus" + put_permission = "can_severity_taskstatus" + delete_permission = "can_delete_taskstatus" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class UserStoryStatusDetailPermission(BaseDetailPermission): + get_permission = "can_view_userstorystatus" + put_permission = "can_severity_userstorystatus" + delete_permission = "can_delete_userstorystatus" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class PriorityDetailPermission(BaseDetailPermission): + get_permission = "can_view_priority" + put_permission = "can_severity_priority" + delete_permission = "can_delete_priority" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class IssueTypeDetailPermission(BaseDetailPermission): + get_permission = "can_view_issuetype" + put_permission = "can_severity_issuetype" + delete_permission = "can_delete_issuetype" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project'] + +class PointsDetailPermission(BaseDetailPermission): + get_permission = "can_view_points" + put_permission = "can_severity_points" + delete_permission = "can_delete_points" + safe_methods = ['HEAD', 'OPTIONS'] + path_to_project = ['project']