feat(notifications): notify membership access changes

This commit is contained in:
2026-04-25 11:51:45 +03:30
parent 0ca3255270
commit 48bf4f5c19
5 changed files with 819 additions and 78 deletions

View File

@@ -5,11 +5,17 @@ from rest_framework.response import Response
from rest_framework.filters import OrderingFilter, SearchFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from apps.workspaces.api.permissions import IsWorkspaceOwner, IsWorkspaceAdmin
from apps.workspaces.api.serializers import WorkspaceMembershipSerializer, WorkspaceSerializer
from apps.workspaces.api.filters import WorkspaceFilter, WorkspaceMembershipFilter
from rest_framework.permissions import IsAuthenticated
from apps.notifications.membership_events import (
notify_workspace_membership_added,
notify_workspace_membership_deactivated,
notify_workspace_membership_removed,
notify_workspace_membership_role_changed,
)
from apps.workspaces.api.permissions import IsWorkspaceOwner, IsWorkspaceAdmin
from apps.workspaces.api.serializers import WorkspaceMembershipSerializer, WorkspaceSerializer
from apps.workspaces.api.filters import WorkspaceFilter, WorkspaceMembershipFilter
from apps.workspaces.models import Workspace, WorkspaceMembership
from core.paginations.limit_offset import CustomLimitOffsetPagination
@@ -79,7 +85,7 @@ class WorkspaceMembershipViewSet(ModelViewSet):
return [IsAuthenticated()]
def create(self, request, *args, **kwargs):
def create(self, request, *args, **kwargs):
"""
Overridden to check permissions manually.
Because the membership object doesn't exist yet, standard DRF object-level
@@ -101,4 +107,75 @@ class WorkspaceMembershipViewSet(ModelViewSet):
status=status.HTTP_403_FORBIDDEN
)
return super().create(request, *args, **kwargs)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
membership = serializer.save()
notify_workspace_membership_added(
actor=request.user,
recipient=membership.user,
workspace=membership.workspace,
role=membership.role,
)
return Response(
WorkspaceMembershipSerializer(membership, context=self.get_serializer_context()).data,
status=status.HTTP_201_CREATED,
)
def update(self, request, *args, **kwargs):
partial = kwargs.pop("partial", False)
membership = self.get_object()
previous_role = membership.role
previous_is_active = membership.is_active
serializer = self.get_serializer(membership, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
updated_membership = serializer.save()
if not previous_is_active and updated_membership.is_active:
notify_workspace_membership_added(
actor=request.user,
recipient=updated_membership.user,
workspace=updated_membership.workspace,
role=updated_membership.role,
)
elif previous_is_active and not updated_membership.is_active:
notify_workspace_membership_deactivated(
actor=request.user,
recipient=updated_membership.user,
workspace=updated_membership.workspace,
role=previous_role,
)
elif previous_role != updated_membership.role:
notify_workspace_membership_role_changed(
actor=request.user,
recipient=updated_membership.user,
workspace=updated_membership.workspace,
previous_role=previous_role,
new_role=updated_membership.role,
)
return Response(
WorkspaceMembershipSerializer(
updated_membership,
context=self.get_serializer_context(),
).data,
status=status.HTTP_200_OK,
)
def partial_update(self, request, *args, **kwargs):
kwargs["partial"] = True
return self.update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
membership = self.get_object()
recipient = membership.user
workspace = membership.workspace
role = membership.role
membership.delete()
notify_workspace_membership_removed(
actor=request.user,
recipient=recipient,
workspace=workspace,
role=role,
)
return Response(status=status.HTTP_204_NO_CONTENT)