From bec27d375f9feb076dac894d7c47c343bd1cfec9 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 17 Jul 2024 12:16:54 +0300 Subject: [PATCH] added endpoint to delete collaborators --- projects/urls.py | 2 ++ projects/views.py | 51 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/projects/urls.py b/projects/urls.py index f19ab6b7..af23aba5 100644 --- a/projects/urls.py +++ b/projects/urls.py @@ -15,6 +15,7 @@ ProjectSubscribe, ProjectUnsubscribe, ProjectSubscribers, + DeleteProjectCollaborators, ) app_name = "projects" @@ -30,6 +31,7 @@ path("/news//set_viewed/", NewsDetailSetViewed.as_view()), path("/news//set_liked/", NewsDetailSetLiked.as_view()), path("/collaborators/", ProjectCollaborators.as_view()), + path("/collaborators/kick/", DeleteProjectCollaborators.as_view()), path("/", ProjectDetail.as_view()), path("/recommended_users", ProjectRecommendedUsers.as_view()), path("count/", ProjectCountView.as_view()), diff --git a/projects/views.py b/projects/views.py index 530252d9..a9224c24 100644 --- a/projects/views.py +++ b/projects/views.py @@ -1,7 +1,8 @@ import logging +from typing import Annotated from django.contrib.auth import get_user_model -from django.db.models import Q +from django.db.models import Q, QuerySet from django_filters import rest_framework as filters from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema @@ -22,7 +23,7 @@ check_related_fields_update, update_partner_program, ) -from projects.models import Project, Achievement, ProjectNews +from projects.models import Project, Achievement, ProjectNews, Collaborator from projects.pagination import ProjectNewsPagination, ProjectsPagination from projects.permissions import ( IsProjectLeaderOrReadOnlyForNonDrafts, @@ -461,3 +462,49 @@ def post(self, request, project_pk): return Response( {"detail": "Subscriber was successfully removed"}, status=status.HTTP_200_OK ) + + +class DeleteProjectCollaborators(generics.GenericAPIView): + permission_classes = [IsProjectLeader] + queryset = Project.objects.all().select_related("leader") + + def _project_data( + self, + ) -> tuple[Annotated[int, "ID проекта"], Annotated[int, "ID лидера проекта"]]: + project = self.get_object() + return project.id, project.leader.id + + def _collabs_queryset( + self, project_id: int, requested_ids: set[int], leader_id: int + ) -> QuerySet: + return ( + Collaborator.objects.filter( + user__id__in=requested_ids, project__id=project_id + ) + .exclude(user__id=leader_id) # чтоб случайно лидер сам себя не удалил + .values_list("id", flat=True) + ) + + def delete(self, request, pk: int) -> Response: + requested_collabs_ids: set[int] = set(request.data) + + project_id, leader_id = self._project_data() + existing_collabs_ids: set[int] = set( + self._collabs_queryset(project_id, requested_collabs_ids, leader_id) + ) + + if leader_id in requested_collabs_ids: + return Response( + {"error": f"User with id: {leader_id} is a leader of a project."}, + status=status.HTTP_422_UNPROCESSABLE_ENTITY, + ) + if unexisting_collabs := requested_collabs_ids - existing_collabs_ids: + return Response( + { + "error": f"Users with ids: {list(unexisting_collabs)} are not part of this project." + }, + status=status.HTTP_422_UNPROCESSABLE_ENTITY, + ) + + Collaborator.objects.filter(id__in=existing_collabs_ids).delete() + return Response(status=204)