From f4fa2e011a7e9b98c4a265fb76db8daba7eb31d4 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:55:06 +0530 Subject: [PATCH] feat: leave project and workspace endpoint (#2042) * feat: leave project and workspace endpoint * fix: argument error * dev: update endpoint status --- apiserver/plane/api/urls.py | 12 +++++ apiserver/plane/api/views/__init__.py | 2 + apiserver/plane/api/views/project.py | 66 +++++++++++++++++++------- apiserver/plane/api/views/workspace.py | 41 ++++++++++++++++ 4 files changed, 105 insertions(+), 16 deletions(-) diff --git a/apiserver/plane/api/urls.py b/apiserver/plane/api/urls.py index 1fb2b8e90..558b7f059 100644 --- a/apiserver/plane/api/urls.py +++ b/apiserver/plane/api/urls.py @@ -51,6 +51,7 @@ from plane.api.views import ( WorkspaceUserProfileEndpoint, WorkspaceUserProfileIssuesEndpoint, WorkspaceLabelsEndpoint, + LeaveWorkspaceEndpoint, ## End Workspaces # File Assets FileAssetEndpoint, @@ -68,6 +69,7 @@ from plane.api.views import ( UserProjectInvitationsViewset, ProjectIdentifierEndpoint, ProjectFavoritesViewSet, + LeaveProjectEndpoint, ## End Projects # Issues IssueViewSet, @@ -441,6 +443,11 @@ urlpatterns = [ WorkspaceLabelsEndpoint.as_view(), name="workspace-labels", ), + path( + "workspaces//members/leave/", + LeaveWorkspaceEndpoint.as_view(), + name="workspace-labels", + ), ## End Workspaces ## # Projects path( @@ -554,6 +561,11 @@ urlpatterns = [ ), name="project", ), + path( + "workspaces//projects//members/leave/", + LeaveProjectEndpoint.as_view(), + name="project", + ), # End Projects # States path( diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index b697741ae..71647bfea 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -16,6 +16,7 @@ from .project import ( ProjectDeployBoardPublicSettingsEndpoint, ProjectMemberEndpoint, WorkspaceProjectDeployBoardEndpoint, + LeaveProjectEndpoint, ) from .user import ( UserEndpoint, @@ -52,6 +53,7 @@ from .workspace import ( WorkspaceUserProfileIssuesEndpoint, WorkspaceLabelsEndpoint, WorkspaceMembersEndpoint, + LeaveWorkspaceEndpoint, ) from .state import StateViewSet from .view import IssueViewViewSet, ViewIssuesEndpoint, IssueViewFavoriteViewSet diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 97b06fce5..a83bbca25 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -11,14 +11,8 @@ from django.db.models import ( OuterRef, Func, F, - Max, - CharField, Func, Subquery, - Prefetch, - When, - Case, - Value, ) from django.core.validators import validate_email from django.conf import settings @@ -47,6 +41,7 @@ from plane.api.permissions import ( ProjectBasePermission, ProjectEntityPermission, ProjectMemberPermission, + ProjectLitePermission, ) from plane.db.models import ( @@ -71,16 +66,9 @@ from plane.db.models import ( ModuleMember, Inbox, ProjectDeployBoard, - Issue, - IssueReaction, - IssueLink, - IssueAttachment, - Label, ) from plane.bgtasks.project_invitation_task import project_invitation -from plane.utils.grouper import group_results -from plane.utils.issue_filters import issue_filters class ProjectViewSet(BaseViewSet): @@ -629,7 +617,7 @@ class ProjectMemberViewSet(BaseViewSet): return Response(status=status.HTTP_204_NO_CONTENT) except ProjectMember.DoesNotExist: return Response( - {"error": "Project Member does not exist"}, status=status.HTTP_400 + {"error": "Project Member does not exist"}, status=status.HTTP_400_BAD_REQUEST ) except Exception as e: capture_exception(e) @@ -1144,8 +1132,9 @@ class ProjectDeployBoardPublicSettingsEndpoint(BaseAPIView): class WorkspaceProjectDeployBoardEndpoint(BaseAPIView): - - permission_classes = [AllowAny,] + permission_classes = [ + AllowAny, + ] def get(self, request, slug): try: @@ -1176,3 +1165,48 @@ class WorkspaceProjectDeployBoardEndpoint(BaseAPIView): {"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST, ) + + +class LeaveProjectEndpoint(BaseAPIView): + permission_classes = [ + ProjectLitePermission, + ] + + def delete(self, request, slug, project_id): + try: + project_member = ProjectMember.objects.get( + workspace__slug=slug, + member=request.user, + project_id=project_id, + ) + + # Only Admin case + if ( + project_member.role == 20 + and ProjectMember.objects.filter( + workspace__slug=slug, + role=20, + project_id=project_id, + ).count() + == 1 + ): + return Response( + { + "error": "You cannot leave the project since you are the only admin of the project you should delete the project" + }, + status=status.HTTP_400_BAD_REQUEST, + ) + # Delete the member from workspace + project_member.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + except ProjectMember.DoesNotExist: + return Response( + {"error": "Workspace member does not exists"}, + status=status.HTTP_400_BAD_REQUEST, + ) + except Exception as e: + capture_exception(e) + return Response( + {"error": "Something went wrong please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + ) diff --git a/apiserver/plane/api/views/workspace.py b/apiserver/plane/api/views/workspace.py index cbf62548f..ce425185e 100644 --- a/apiserver/plane/api/views/workspace.py +++ b/apiserver/plane/api/views/workspace.py @@ -1473,3 +1473,44 @@ class WorkspaceMembersEndpoint(BaseAPIView): {"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST, ) + + +class LeaveWorkspaceEndpoint(BaseAPIView): + permission_classes = [ + WorkspaceEntityPermission, + ] + + def delete(self, request, slug): + try: + workspace_member = WorkspaceMember.objects.get( + workspace__slug=slug, member=request.user + ) + + # Only Admin case + if ( + workspace_member.role == 20 + and WorkspaceMember.objects.filter( + workspace__slug=slug, role=20 + ).count() + == 1 + ): + return Response( + { + "error": "You cannot leave the workspace since you are the only admin of the workspace you should delete the workspace" + }, + status=status.HTTP_400_BAD_REQUEST, + ) + # Delete the member from workspace + workspace_member.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + except WorkspaceMember.DoesNotExist: + return Response( + {"error": "Workspace member does not exists"}, + status=status.HTTP_400_BAD_REQUEST, + ) + except Exception as e: + capture_exception(e) + return Response( + {"error": "Something went wrong please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + )