# Django imports from django.db.models import Case, Count, IntegerField, Q, When from django.contrib.auth import logout from django.utils import timezone # Third party imports from rest_framework import status from rest_framework.response import Response # Module imports from plane.app.serializers import ( AccountSerializer, IssueActivitySerializer, ProfileSerializer, UserMeSerializer, UserMeSettingsSerializer, UserSerializer, ) from plane.app.views.base import BaseAPIView, BaseViewSet from plane.db.models import ( Account, IssueActivity, Profile, ProjectMember, User, WorkspaceMember, ) from plane.license.models import Instance, InstanceAdmin from plane.utils.cache import cache_response, invalidate_cache from plane.utils.paginator import BasePaginator from plane.authentication.utils.host import user_ip class UserEndpoint(BaseViewSet): serializer_class = UserSerializer model = User def get_object(self): return self.request.user @cache_response(60 * 60) def retrieve(self, request): serialized_data = UserMeSerializer(request.user).data return Response( serialized_data, status=status.HTTP_200_OK, ) @cache_response(60 * 60) def retrieve_user_settings(self, request): serialized_data = UserMeSettingsSerializer(request.user).data return Response(serialized_data, status=status.HTTP_200_OK) @cache_response(60 * 60) def retrieve_instance_admin(self, request): instance = Instance.objects.first() is_admin = InstanceAdmin.objects.filter( instance=instance, user=request.user ).exists() return Response( {"is_instance_admin": is_admin}, status=status.HTTP_200_OK ) @invalidate_cache( path="/api/users/me/", ) @invalidate_cache( path="/api/users/me/settings/", ) def partial_update(self, request, *args, **kwargs): return super().partial_update(request, *args, **kwargs) @invalidate_cache(path="/api/users/me/") def deactivate(self, request): # Check all workspace user is active user = self.get_object() # Instance admin check if InstanceAdmin.objects.filter(user=user).exists(): return Response( { "error": "You cannot deactivate your account since you are an instance admin" }, status=status.HTTP_400_BAD_REQUEST, ) projects_to_deactivate = [] workspaces_to_deactivate = [] projects = ProjectMember.objects.filter( member=request.user, is_active=True ).annotate( other_admin_exists=Count( Case( When( Q(role=20, is_active=True) & ~Q(member=request.user), then=1, ), default=0, output_field=IntegerField(), ) ), total_members=Count("id"), ) for project in projects: if project.other_admin_exists > 0 or (project.total_members == 1): project.is_active = False projects_to_deactivate.append(project) else: return Response( { "error": "You cannot deactivate account as you are the only admin in some projects." }, status=status.HTTP_400_BAD_REQUEST, ) workspaces = WorkspaceMember.objects.filter( member=request.user, is_active=True ).annotate( other_admin_exists=Count( Case( When( Q(role=20, is_active=True) & ~Q(member=request.user), then=1, ), default=0, output_field=IntegerField(), ) ), total_members=Count("id"), ) for workspace in workspaces: if workspace.other_admin_exists > 0 or ( workspace.total_members == 1 ): workspace.is_active = False workspaces_to_deactivate.append(workspace) else: return Response( { "error": "You cannot deactivate account as you are the only admin in some workspaces." }, status=status.HTTP_400_BAD_REQUEST, ) ProjectMember.objects.bulk_update( projects_to_deactivate, ["is_active"], batch_size=100 ) WorkspaceMember.objects.bulk_update( workspaces_to_deactivate, ["is_active"], batch_size=100 ) # Deactivate the user user.is_active = False # Profile updates profile = Profile.objects.get(user=user) profile.last_workspace_id = None profile.is_tour_completed = False profile.is_onboarded = False profile.onboarding_step = { "workspace_join": False, "profile_complete": False, "workspace_create": False, "workspace_invite": False, } profile.save() # User log out user.last_logout_ip = user_ip(request=request) user.last_logout_time = timezone.now() user.save() # Logout the user logout(request) return Response(status=status.HTTP_204_NO_CONTENT) class UpdateUserOnBoardedEndpoint(BaseAPIView): @invalidate_cache(path="/api/users/me/") def patch(self, request): profile = Profile.objects.get(user_id=request.user.id) profile.is_onboarded = request.data.get("is_onboarded", False) profile.save() return Response( {"message": "Updated successfully"}, status=status.HTTP_200_OK ) class UpdateUserTourCompletedEndpoint(BaseAPIView): @invalidate_cache(path="/api/users/me/") def patch(self, request): profile = Profile.objects.get(user_id=request.user.id) profile.is_tour_completed = request.data.get( "is_tour_completed", False ) profile.save() return Response( {"message": "Updated successfully"}, status=status.HTTP_200_OK ) class UserActivityEndpoint(BaseAPIView, BasePaginator): def get(self, request): queryset = IssueActivity.objects.filter( actor=request.user ).select_related("actor", "workspace", "issue", "project") return self.paginate( request=request, queryset=queryset, on_results=lambda issue_activities: IssueActivitySerializer( issue_activities, many=True ).data, ) class AccountEndpoint(BaseAPIView): def get(self, request, pk=None): if pk: account = Account.objects.get(pk=pk, user=request.user) serializer = AccountSerializer(account) return Response(serializer.data, status=status.HTTP_200_OK) account = Account.objects.filter(user=request.user) serializer = AccountSerializer(account, many=True) return Response( serializer.data, status=status.HTTP_200_OK, ) def delete(self, request, pk): account = Account.objects.get(pk=pk, user=request.user) account.delete() return Response(status=status.HTTP_204_NO_CONTENT) class ProfileEndpoint(BaseAPIView): def get(self, request): profile = Profile.objects.get(user=request.user) serializer = ProfileSerializer(profile) return Response(serializer.data, status=status.HTTP_200_OK) def patch(self, request): profile = Profile.objects.get(user=request.user) serializer = ProfileSerializer( profile, data=request.data, partial=True ) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)