feat(permissions): centralize workspace role capability checks

This commit is contained in:
2026-04-25 18:48:50 +03:30
parent 5f9d413a57
commit f960ca8221
14 changed files with 925 additions and 222 deletions

View File

@@ -24,6 +24,7 @@ from apps.time_entries.services.time_entries import (
update_time_entry,
stop_time_entry
)
from apps.workspaces.services import TIME_ENTRIES_MANAGE_OWN, has_workspace_capability
class TimeEntryViewSet(ModelViewSet):
@@ -150,11 +151,16 @@ class TimeEntryViewSet(ModelViewSet):
output_serializer = TimeEntrySerializer(entry)
return Response(output_serializer.data, status=status.HTTP_201_CREATED)
def update(self, request, *args, **kwargs):
partial = kwargs.pop("partial", False)
entry = self.get_object()
serializer = self.get_serializer(data=request.data, partial=partial)
def update(self, request, *args, **kwargs):
partial = kwargs.pop("partial", False)
entry = self.get_object()
if not has_workspace_capability(request.user, entry.workspace, TIME_ENTRIES_MANAGE_OWN):
return Response(
{"detail": "You do not have permission to manage time entries in this workspace."},
status=status.HTTP_403_FORBIDDEN,
)
serializer = self.get_serializer(data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
updated_entry = update_time_entry(
@@ -166,11 +172,16 @@ class TimeEntryViewSet(ModelViewSet):
return Response(output_serializer.data, status=status.HTTP_200_OK)
@action(detail=True, methods=["post"])
def stop(self, request, pk=None):
def stop(self, request, pk=None):
"""
Dedicated endpoint to stop an actively running timer.
"""
entry = self.get_object()
entry = self.get_object()
if not has_workspace_capability(request.user, entry.workspace, TIME_ENTRIES_MANAGE_OWN):
return Response(
{"detail": "You do not have permission to manage time entries in this workspace."},
status=status.HTTP_403_FORBIDDEN,
)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
@@ -181,11 +192,16 @@ class TimeEntryViewSet(ModelViewSet):
output_serializer = TimeEntrySerializer(stopped_entry)
return Response(output_serializer.data, status=status.HTTP_200_OK)
def destroy(self, request, *args, **kwargs):
def destroy(self, request, *args, **kwargs):
"""
Soft deletes the time entry.
"""
entry = self.get_object()
entry.is_deleted = True
entry = self.get_object()
if not has_workspace_capability(request.user, entry.workspace, TIME_ENTRIES_MANAGE_OWN):
return Response(
{"detail": "You do not have permission to manage time entries in this workspace."},
status=status.HTTP_403_FORBIDDEN,
)
entry.is_deleted = True
entry.save(update_fields=["is_deleted", "updated_at"])
return Response(status=status.HTTP_204_NO_CONTENT)