mirror of
https://github.com/suitenumerique/messages.git
synced 2026-09-27 20:24:56 +02:00
✨(api) add endpoint to manage ThreadAccess
Allows creating, updating, and deleting access to threads based on user role.
This commit is contained in:
@@ -276,3 +276,70 @@ class IsAllowedToCreateMessage(IsAuthenticated):
|
||||
# return True
|
||||
#
|
||||
# return False
|
||||
|
||||
|
||||
class IsAllowedToManageThreadAccess(IsAuthenticated):
|
||||
"""Permission class for access to create, update, delete and list thread accesses."""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
# Get thread_id from URL kwargs instead of query params/data
|
||||
thread_id = view.kwargs.get("thread_id")
|
||||
if not thread_id:
|
||||
return False
|
||||
|
||||
# if create action, check if user has admin/editor access to the mailbox and the thread access role is editor
|
||||
if view.action == "create":
|
||||
# authenticated user wants to create a thread access for a specific thread
|
||||
# check if user has admin/editor access to the mailbox and the thread access role is editor already exists for them
|
||||
return (
|
||||
models.ThreadAccess.objects.select_related("mailbox")
|
||||
.filter(
|
||||
thread_id=thread_id,
|
||||
mailbox__accesses__user=request.user,
|
||||
mailbox__accesses__role__in=[
|
||||
enums.MailboxRoleChoices.ADMIN,
|
||||
enums.MailboxRoleChoices.EDITOR,
|
||||
],
|
||||
role=enums.ThreadAccessRoleChoices.EDITOR,
|
||||
)
|
||||
.exists()
|
||||
)
|
||||
elif view.action == "list":
|
||||
# list is only allowed for a user with access to the thread
|
||||
return (
|
||||
models.ThreadAccess.objects.select_related("mailbox")
|
||||
.filter(
|
||||
thread_id=thread_id,
|
||||
mailbox__accesses__user=request.user,
|
||||
mailbox__accesses__role__in=[
|
||||
enums.MailboxRoleChoices.ADMIN,
|
||||
enums.MailboxRoleChoices.EDITOR,
|
||||
],
|
||||
role=enums.ThreadAccessRoleChoices.EDITOR,
|
||||
)
|
||||
.exists()
|
||||
)
|
||||
else:
|
||||
return True # to proceed to object-level checks
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
"""Check if user has permission to access the specific object (ThreadAccess).
|
||||
Manage retrieve, update, destroy actions here.
|
||||
"""
|
||||
# Verify the thread access belongs to the thread in the URL
|
||||
if str(obj.thread.id) != view.kwargs.get("thread_id"):
|
||||
return False
|
||||
|
||||
return (
|
||||
models.ThreadAccess.objects.select_related("mailbox")
|
||||
.filter(
|
||||
thread=obj.thread,
|
||||
mailbox__accesses__user=request.user,
|
||||
mailbox__accesses__role__in=[
|
||||
enums.MailboxRoleChoices.ADMIN,
|
||||
enums.MailboxRoleChoices.EDITOR,
|
||||
],
|
||||
role=enums.ThreadAccessRoleChoices.EDITOR,
|
||||
)
|
||||
.exists()
|
||||
)
|
||||
|
||||
@@ -279,3 +279,12 @@ class MessageSerializer(serializers.ModelSerializer):
|
||||
"is_trashed",
|
||||
]
|
||||
read_only_fields = fields # Mark all as read-only
|
||||
|
||||
|
||||
class ThreadAccessSerializer(serializers.ModelSerializer):
|
||||
"""Serialize thread access information."""
|
||||
|
||||
class Meta:
|
||||
model = models.ThreadAccess
|
||||
fields = ["id", "thread", "mailbox", "role", "created_at", "updated_at"]
|
||||
read_only_fields = ["id", "created_at", "updated_at"]
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
"""API ViewSet for ThreadAccess model."""
|
||||
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import (
|
||||
OpenApiParameter,
|
||||
extend_schema,
|
||||
)
|
||||
from rest_framework import mixins, viewsets
|
||||
|
||||
from core import models
|
||||
|
||||
from .. import permissions, serializers
|
||||
|
||||
|
||||
@extend_schema(
|
||||
tags=["thread-access"],
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="mailbox_id",
|
||||
type=OpenApiTypes.UUID,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Filter thread accesses by mailbox ID.",
|
||||
required=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
class ThreadAccessViewSet(
|
||||
viewsets.GenericViewSet,
|
||||
mixins.ListModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
):
|
||||
"""ViewSet for ThreadAccess model."""
|
||||
|
||||
serializer_class = serializers.ThreadAccessSerializer
|
||||
permission_classes = [
|
||||
permissions.IsAuthenticated,
|
||||
permissions.IsAllowedToManageThreadAccess,
|
||||
]
|
||||
lookup_field = "id"
|
||||
lookup_url_kwarg = "id"
|
||||
queryset = models.ThreadAccess.objects.all()
|
||||
|
||||
def get_queryset(self):
|
||||
"""Restrict results to thread accesses for the specified thread."""
|
||||
# Get thread_id from URL kwargs (provided by nested router)
|
||||
thread_id = self.kwargs.get("thread_id")
|
||||
if not thread_id:
|
||||
return models.ThreadAccess.objects.none()
|
||||
|
||||
# Filter by thread_id from URL
|
||||
queryset = self.queryset.filter(thread_id=thread_id)
|
||||
|
||||
# Optional mailbox filter
|
||||
mailbox_id = self.request.GET.get("mailbox_id")
|
||||
if mailbox_id:
|
||||
queryset = queryset.filter(mailbox_id=mailbox_id)
|
||||
return queryset.distinct()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Create a new thread access."""
|
||||
request.data["thread"] = self.kwargs.get("thread_id")
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""List thread accesses for the specified thread."""
|
||||
return super().list(request, *args, **kwargs)
|
||||
Reference in New Issue
Block a user