From a689d23bc86b37d8d24d426d066c59e682afe1d6 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 17 Jul 2024 13:02:01 +0300 Subject: [PATCH] added endpoint to switch leader --- projects/exceptions.py | 9 +++++++++ projects/urls.py | 2 ++ projects/views.py | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 projects/exceptions.py diff --git a/projects/exceptions.py b/projects/exceptions.py new file mode 100644 index 00000000..cc1306ce --- /dev/null +++ b/projects/exceptions.py @@ -0,0 +1,9 @@ +from rest_framework import status +from rest_framework.exceptions import APIException +from django.utils.translation import gettext_lazy as _ + + +class CollaboratorDoesNotExist(APIException): + status_code = status.HTTP_422_UNPROCESSABLE_ENTITY + default_detail = _("Not found.") + default_code = "not_found" diff --git a/projects/urls.py b/projects/urls.py index f19ab6b7..cc785712 100644 --- a/projects/urls.py +++ b/projects/urls.py @@ -15,6 +15,7 @@ ProjectSubscribe, ProjectUnsubscribe, ProjectSubscribers, + SwitchLeaderRole, ) 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/switch-leader/", SwitchLeaderRole.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..50f9a36f 100644 --- a/projects/views.py +++ b/projects/views.py @@ -1,6 +1,7 @@ import logging from django.contrib.auth import get_user_model +from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q from django_filters import rest_framework as filters from drf_yasg import openapi @@ -15,6 +16,7 @@ from core.serializers import SetLikedSerializer from core.services import add_view, set_like from partner_programs.models import PartnerProgram, PartnerProgramUserProfile +from projects.exceptions import CollaboratorDoesNotExist from projects.filters import ProjectFilter from projects.constants import VERBOSE_STEPS from projects.helpers import ( @@ -22,7 +24,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 +463,35 @@ def post(self, request, project_pk): return Response( {"detail": "Subscriber was successfully removed"}, status=status.HTTP_200_OK ) + + +class SwitchLeaderRole(generics.GenericAPIView): + permission_classes = [IsProjectLeader] + queryset = Project.objects.all().select_related("leader") + + def _get_new_leader(self, user_id: int, project: Project) -> Collaborator: + try: + return Collaborator.objects.select_related("user").get( + user_id=user_id, project=project + ) + except ObjectDoesNotExist: + raise CollaboratorDoesNotExist( + f"""Collaborator with user_id: {user_id} does not exist. Either user_id is not correct, or project_id + is not correct, or try adding this user to a project (as collaborator) before making them a leader. """ + ) + + def patch(self, request, pk: int): + project = self.get_object() + + new_leader_id = int(request.data["new_leader_id"]) + new_leader = self._get_new_leader(new_leader_id, project) + + if project.leader.id == new_leader_id: + return Response( + {"error": "User is already a leader of a project"}, + status=status.HTTP_422_UNPROCESSABLE_ENTITY, + ) + + project.leader = new_leader.user + project.save() + return Response(status=204)