diff --git a/apiserver/plane/api/serializers/__init__.py b/apiserver/plane/api/serializers/__init__.py index 381891f2f..2ff210f98 100644 --- a/apiserver/plane/api/serializers/__init__.py +++ b/apiserver/plane/api/serializers/__init__.py @@ -21,6 +21,7 @@ from .project import ( ProjectIdentifierSerializer, ProjectFavoriteSerializer, ProjectLiteSerializer, + ProjectMemberLiteSerializer, ) from .state import StateSerializer, StateLiteSerializer from .view import IssueViewSerializer, IssueViewFavoriteSerializer diff --git a/apiserver/plane/api/serializers/project.py b/apiserver/plane/api/serializers/project.py index cbea7171a..f96be09ab 100644 --- a/apiserver/plane/api/serializers/project.py +++ b/apiserver/plane/api/serializers/project.py @@ -96,7 +96,6 @@ class ProjectMemberSerializer(BaseSerializer): workspace = WorkSpaceSerializer(read_only=True) project = ProjectSerializer(read_only=True) member = UserLiteSerializer(read_only=True) - is_subscribed = serializers.BooleanField(read_only=True) class Meta: model = ProjectMember @@ -135,3 +134,13 @@ class ProjectLiteSerializer(BaseSerializer): model = Project fields = ["id", "identifier", "name"] read_only_fields = fields + + +class ProjectMemberLiteSerializer(BaseSerializer): + member = UserLiteSerializer(read_only=True) + is_subscribed = serializers.BooleanField(read_only=True) + + class Meta: + model = ProjectMember + fields = ["member", "id", "is_subscribed"] + read_only_fields = fields diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 935377d46..f68219834 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -45,11 +45,13 @@ from plane.api.serializers import ( IssueAttachmentSerializer, IssueSubscriberSerializer, ProjectMemberSerializer, + ProjectMemberLiteSerializer, ) from plane.api.permissions import ( ProjectEntityPermission, WorkSpaceAdminPermission, ProjectMemberPermission, + ProjectLitePermission, ) from plane.db.models import ( Project, @@ -871,29 +873,17 @@ class IssueSubscriberViewSet(BaseViewSet): ProjectEntityPermission, ] - def list(self, request, slug, project_id, issue_id): - try: - members = ProjectMember.objects.filter( - workspace__slug=slug, project_id=project_id - ) - members = members.annotate( - is_subscribed=Exists( - IssueSubscriber.objects.filter( - workspace__slug=slug, - project_id=project_id, - issue_id=issue_id, - subscriber=OuterRef("member"), - ) - ) - ) - serializer = ProjectMemberSerializer(members, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) - except Exception as e: - capture_exception(e) - return Response( - {"error": e}, - status=status.HTTP_400_BAD_REQUEST, - ) + def get_permissions(self): + if self.action in ["subscribe", "unsubscribe", "subscription_status"]: + self.permission_classes = [ + ProjectLitePermission, + ] + else: + self.permission_classes = [ + ProjectEntityPermission, + ] + + return super(IssueSubscriberViewSet, self).get_permissions() def perform_create(self, serializer): serializer.save( @@ -913,6 +903,53 @@ class IssueSubscriberViewSet(BaseViewSet): .distinct() ) + def list(self, request, slug, project_id, issue_id): + try: + members = ProjectMember.objects.filter( + workspace__slug=slug, project_id=project_id + ).annotate( + is_subscribed=Exists( + IssueSubscriber.objects.filter( + workspace__slug=slug, + project_id=project_id, + issue_id=issue_id, + subscriber=OuterRef("member"), + ) + ) + ).select_related("member") + serializer = ProjectMemberLiteSerializer(members, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + except Exception as e: + capture_exception(e) + return Response( + {"error": e}, + status=status.HTTP_400_BAD_REQUEST, + ) + + def destroy(self, request, slug, project_id, issue_id, subscriber_id): + try: + issue_subscriber = IssueSubscriber.objects.get( + project=project_id, + subscriber=subscriber_id, + workspace__slug=slug, + issue=issue_id, + ) + issue_subscriber.delete() + return Response( + status=status.HTTP_204_NO_CONTENT, + ) + except IssueSubscriber.DoesNotExist: + return Response( + {"error": "User is not subscribed to this issue"}, + 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, + ) + def subscribe(self, request, slug, project_id, issue_id): try: if IssueSubscriber.objects.filter( @@ -979,27 +1016,3 @@ class IssueSubscriberViewSet(BaseViewSet): {"error": "Something went wrong, please try again later"}, status=status.HTTP_400_BAD_REQUEST, ) - - def destroy(self, request, slug, project_id, issue_id, subscriber_id): - try: - issue_subscriber = IssueSubscriber.objects.get( - project=project_id, - subscriber=subscriber_id, - workspace__slug=slug, - issue=issue_id, - ) - issue_subscriber.delete() - return Response( - status=status.HTTP_204_NO_CONTENT, - ) - except IssueSubscriber.DoesNotExist: - return Response( - {"error": "User is not subscribed to this issue"}, - 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/notification.py b/apiserver/plane/api/views/notification.py index 1ccd43212..6c3f3587b 100644 --- a/apiserver/plane/api/views/notification.py +++ b/apiserver/plane/api/views/notification.py @@ -1,3 +1,7 @@ +# Django imports +from django.db.models import Q +from django.utils import timezone + # Third party imports from rest_framework import status from rest_framework.response import Response @@ -24,6 +28,28 @@ class NotificationViewSet(BaseViewSet): .select_related("workspace") ) + def list(self, request, slug): + try: + order_by = request.GET.get("ordeer_by", "-created_at") + snoozed = request.GET.get("snoozed", "false") + notifications = Notification.objects.filter( + workspace__slug=slug, receiver=request.user + ).order_by(order_by) + + if snoozed == "false": + notifications = notifications.filter( + Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True), + ) + + serializer = NotificationSerializer(notifications, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + except Exception as e: + capture_exception(e) + return Response( + {"error": "Something went wrong please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + ) + def partial_update(self, request, slug, pk): try: notification = Notification.objects.get( @@ -34,7 +60,9 @@ class NotificationViewSet(BaseViewSet): "read_at": request.data.get("read_at", None), "snoozed_till": request.data.get("snoozed_till", None), } - serializer = NotificationSerializer(notification, data=notification_data, partial=True) + serializer = NotificationSerializer( + notification, data=notification_data, partial=True + ) if serializer.is_valid(): serializer.save()