From 754142afa2e2d1f7019722c60698192f126cf316 Mon Sep 17 00:00:00 2001 From: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com> Date: Thu, 8 Jun 2023 00:14:41 +0530 Subject: [PATCH] fix: workspace and project member user deletion (#1241) * fix: workspace and project member user deletion * fix: workspace member deletion * dev: add comments --- apiserver/plane/api/views/project.py | 86 +++++++++++++++++++------- apiserver/plane/api/views/workspace.py | 50 ++++++++++++--- 2 files changed, 103 insertions(+), 33 deletions(-) diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 194638f93..bdb758ac9 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -46,7 +46,7 @@ from plane.db.models import ( IssueViewFavorite, Page, IssueAssignee, - ModuleMember + ModuleMember, ) @@ -104,15 +104,13 @@ class ProjectViewSet(BaseViewSet): .values("count") ) .annotate( - total_cycles=Cycle.objects.filter( - project_id=OuterRef("id")) + total_cycles=Cycle.objects.filter(project_id=OuterRef("id")) .order_by() .annotate(count=Func(F("id"), function="Count")) .values("count") ) .annotate( - total_modules=Module.objects.filter( - project_id=OuterRef("id")) + total_modules=Module.objects.filter(project_id=OuterRef("id")) .order_by() .annotate(count=Func(F("id"), function="Count")) .values("count") @@ -322,8 +320,7 @@ class InviteProjectEndpoint(BaseAPIView): ) return Response( - ProjectMemberSerializer( - project_member).data, status=status.HTTP_200_OK + ProjectMemberSerializer(project_member).data, status=status.HTTP_200_OK ) except ValidationError: @@ -416,15 +413,22 @@ class ProjectMemberViewSet(BaseViewSet): def partial_update(self, request, slug, project_id, pk): try: project_member = ProjectMember.objects.get( - pk=pk, workspace__slug=slug, project_id=project_id) + pk=pk, workspace__slug=slug, project_id=project_id + ) if request.user.id == project_member.member_id: return Response( {"error": "You cannot update your own role"}, status=status.HTTP_400_BAD_REQUEST, ) # Check while updating user roles - requested_project_member = ProjectMember.objects.get(project_id=project_id, workspace__slug=slug, member=request.user) - if "role" in request.data and int(request.data.get("role", project_member.role)) > requested_project_member.role: + requested_project_member = ProjectMember.objects.get( + project_id=project_id, workspace__slug=slug, member=request.user + ) + if ( + "role" in request.data + and int(request.data.get("role", project_member.role)) + > requested_project_member.role + ): return Response( { "error": "You cannot update a role that is higher than your own role" @@ -447,36 +451,72 @@ class ProjectMemberViewSet(BaseViewSet): ) except Exception as e: capture_exception(e) - return Response({"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"error": "Something went wrong please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + ) def destroy(self, request, slug, project_id, pk): try: project_member = ProjectMember.objects.get( workspace__slug=slug, project_id=project_id, pk=pk ) + # check requesting user role + requesting_project_member = ProjectMember.objects.get( + workspace__slug=slug, member=request.user, project_id=project_id + ) + if requesting_project_member.role < project_member.role: + return Response( + {"error": "You cannot remove a user having role higher than yourself"}, + status=status.HTTP_400_BAD_REQUEST, + ) + # Remove all favorites - ProjectFavorite.objects.filter(workspace__slug=slug, project_id=project_id, user=project_member.member).delete() - CycleFavorite.objects.filter(workspace__slug=slug, project_id=project_id, user=project_member.member).delete() - ModuleFavorite.objects.filter(workspace__slug=slug, project_id=project_id, user=project_member.member).delete() - PageFavorite.objects.filter(workspace__slug=slug, project_id=project_id, user=project_member.member).delete() - IssueViewFavorite.objects.filter(workspace__slug=slug, project_id=project_id, user=project_member.member).delete() + ProjectFavorite.objects.filter( + workspace__slug=slug, project_id=project_id, user=project_member.member + ).delete() + CycleFavorite.objects.filter( + workspace__slug=slug, project_id=project_id, user=project_member.member + ).delete() + ModuleFavorite.objects.filter( + workspace__slug=slug, project_id=project_id, user=project_member.member + ).delete() + PageFavorite.objects.filter( + workspace__slug=slug, project_id=project_id, user=project_member.member + ).delete() + IssueViewFavorite.objects.filter( + workspace__slug=slug, project_id=project_id, user=project_member.member + ).delete() # Also remove issue from issue assigned IssueAssignee.objects.filter( - workspace__slug=slug, project_id=project_id, assignee=project_member.member + workspace__slug=slug, + project_id=project_id, + assignee=project_member.member, ).delete() # Remove if module member - ModuleMember.objects.filter(workspace__slug=slug, project_id=project_id, member=project_member.member).delete() + ModuleMember.objects.filter( + workspace__slug=slug, + project_id=project_id, + member=project_member.member, + ).delete() # Delete owned Pages - Page.objects.filter(workspace__slug=slug, project_id=project_id, owned_by=project_member.member).delete() + Page.objects.filter( + workspace__slug=slug, + project_id=project_id, + owned_by=project_member.member, + ).delete() project_member.delete() return Response(status=status.HTTP_204_NO_CONTENT) except ProjectMember.DoesNotExist: - return Response({"error": "Project Member does not exist"}, status=status.HTTP_400) + return Response( + {"error": "Project Member does not exist"}, status=status.HTTP_400 + ) except Exception as e: capture_exception(e) return Response({"error": "Something went wrong please try again later"}) + class AddMemberToProjectEndpoint(BaseAPIView): permission_classes = [ ProjectBasePermission, @@ -669,8 +709,7 @@ class ProjectIdentifierEndpoint(BaseAPIView): status=status.HTTP_400_BAD_REQUEST, ) - ProjectIdentifier.objects.filter( - name=name, workspace__slug=slug).delete() + ProjectIdentifier.objects.filter(name=name, workspace__slug=slug).delete() return Response( status=status.HTTP_204_NO_CONTENT, @@ -746,8 +785,7 @@ class ProjectUserViewsEndpoint(BaseAPIView): view_props = project_member.view_props default_props = project_member.default_props - project_member.view_props = request.data.get( - "view_props", view_props) + project_member.view_props = request.data.get("view_props", view_props) project_member.default_props = request.data.get( "default_props", default_props ) diff --git a/apiserver/plane/api/views/workspace.py b/apiserver/plane/api/views/workspace.py index 58249d9b6..2f3fcb558 100644 --- a/apiserver/plane/api/views/workspace.py +++ b/apiserver/plane/api/views/workspace.py @@ -442,10 +442,16 @@ class WorkSpaceMemberViewSet(BaseViewSet): ) # Get the requested user role - requested_workspace_member = WorkspaceMember.objects.get(workspace__slug=slug, member=request.user) + requested_workspace_member = WorkspaceMember.objects.get( + workspace__slug=slug, member=request.user + ) # Check if role is being updated # One cannot update role higher than his own role - if "role" in request.data and int(request.data.get("role", workspace_member.role)) > requested_workspace_member.role: + if ( + "role" in request.data + and int(request.data.get("role", workspace_member.role)) + > requested_workspace_member.role + ): return Response( { "error": "You cannot update a role that is higher than your own role" @@ -475,26 +481,52 @@ class WorkSpaceMemberViewSet(BaseViewSet): def destroy(self, request, slug, pk): try: + # Check the user role who is deleting the user workspace_member = WorkspaceMember.objects.get(workspace__slug=slug, pk=pk) + + # check requesting user role + requesting_workspace_member = WorkspaceMember.objects.get( + workspace__slug=slug, member=request.user + ) + if requesting_workspace_member.role < workspace_member.role: + return Response( + {"error": "You cannot remove a user having role higher than you"}, + status=status.HTTP_400_BAD_REQUEST, + ) + # Delete the user also from all the projects ProjectMember.objects.filter( workspace__slug=slug, member=workspace_member.member ).delete() # Remove all favorites - ProjectFavorite.objects.filter(workspace__slug=slug, user=workspace_member.member).delete() - CycleFavorite.objects.filter(workspace__slug=slug, user=workspace_member.member).delete() - ModuleFavorite.objects.filter(workspace__slug=slug, user=workspace_member.member).delete() - PageFavorite.objects.filter(workspace__slug=slug, user=workspace_member.member).delete() - IssueViewFavorite.objects.filter(workspace__slug=slug, user=workspace_member.member).delete() + ProjectFavorite.objects.filter( + workspace__slug=slug, user=workspace_member.member + ).delete() + CycleFavorite.objects.filter( + workspace__slug=slug, user=workspace_member.member + ).delete() + ModuleFavorite.objects.filter( + workspace__slug=slug, user=workspace_member.member + ).delete() + PageFavorite.objects.filter( + workspace__slug=slug, user=workspace_member.member + ).delete() + IssueViewFavorite.objects.filter( + workspace__slug=slug, user=workspace_member.member + ).delete() # Also remove issue from issue assigned IssueAssignee.objects.filter( workspace__slug=slug, assignee=workspace_member.member ).delete() # Remove if module member - ModuleMember.objects.filter(workspace__slug=slug, member=workspace_member.member).delete() + ModuleMember.objects.filter( + workspace__slug=slug, member=workspace_member.member + ).delete() # Delete owned Pages - Page.objects.filter(workspace__slug=slug, owned_by=workspace_member.member).delete() + Page.objects.filter( + workspace__slug=slug, owned_by=workspace_member.member + ).delete() workspace_member.delete() return Response(status=status.HTTP_204_NO_CONTENT)