105 lines
4.0 KiB
Python
105 lines
4.0 KiB
Python
from django.db.models import Q
|
|
from django.shortcuts import get_object_or_404
|
|
from rest_framework import status
|
|
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 apps.workspaces.models import Workspace, WorkspaceMembership
|
|
from core.paginations.limit_offset import CustomLimitOffsetPagination
|
|
|
|
|
|
class WorkspaceViewSet(ModelViewSet):
|
|
serializer_class = WorkspaceSerializer
|
|
pagination_class = CustomLimitOffsetPagination
|
|
filter_backends = (DjangoFilterBackend, OrderingFilter, SearchFilter)
|
|
filterset_class = WorkspaceFilter
|
|
search_fields = ("name", "description", "owner__username", "owner__email")
|
|
ordering_fields = ("created_at", "updated_at", "name")
|
|
ordering = ("-updated_at", "-created_at")
|
|
|
|
def get_queryset(self):
|
|
user = self.request.user
|
|
if not user.is_authenticated:
|
|
return Workspace.objects.none()
|
|
|
|
return Workspace.objects.filter(
|
|
Q(owner=user) |
|
|
Q(memberships__user=user, memberships__is_active=True)
|
|
).distinct()
|
|
|
|
def get_permissions(self):
|
|
if self.action in ["update", "partial_update"]:
|
|
return [IsAuthenticated(), IsWorkspaceAdmin()]
|
|
|
|
elif self.action == "destroy":
|
|
return [IsAuthenticated(), IsWorkspaceOwner()]
|
|
|
|
return [IsAuthenticated()]
|
|
|
|
def perform_create(self, serializer):
|
|
serializer.save(owner=self.request.user)
|
|
|
|
|
|
class WorkspaceMembershipViewSet(ModelViewSet):
|
|
serializer_class = WorkspaceMembershipSerializer
|
|
pagination_class = CustomLimitOffsetPagination
|
|
filter_backends = (DjangoFilterBackend, OrderingFilter, SearchFilter)
|
|
filterset_class = WorkspaceMembershipFilter
|
|
search_fields = (
|
|
"user__mobile",
|
|
"user__email",
|
|
"user__first_name",
|
|
"user__last_name",
|
|
"workspace__name"
|
|
)
|
|
ordering_fields = ("joined_at", "created_at", "role")
|
|
ordering = ("-created_at",)
|
|
|
|
def get_queryset(self):
|
|
user = self.request.user
|
|
if not user.is_authenticated:
|
|
return WorkspaceMembership.objects.none()
|
|
|
|
return WorkspaceMembership.objects.filter(
|
|
Q(workspace__owner=user) |
|
|
Q(workspace__memberships__user=user, workspace__memberships__is_active=True)
|
|
).distinct()
|
|
|
|
def get_permissions(self):
|
|
if self.action in ["update", "partial_update"]:
|
|
return [IsAuthenticated(), IsWorkspaceAdmin()]
|
|
if self.action in ["destroy"]:
|
|
return [IsAuthenticated(), IsWorkspaceOwner()]
|
|
|
|
return [IsAuthenticated()]
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
"""
|
|
Overridden to check permissions manually.
|
|
Because the membership object doesn't exist yet, standard DRF object-level
|
|
permissions won't catch payload-level workspace violations.
|
|
"""
|
|
workspace_id = request.data.get("workspace")
|
|
if not workspace_id:
|
|
return Response(
|
|
{"workspace": ["This field is required."]},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
workspace = get_object_or_404(Workspace, id=workspace_id)
|
|
|
|
permission = IsWorkspaceAdmin()
|
|
if not permission.has_object_permission(request, self, workspace):
|
|
return Response(
|
|
{"detail": "You must be a Workspace Admin or Owner to add members."},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
|
|
return super().create(request, *args, **kwargs)
|