feat(permissions): centralize workspace role capability checks
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -2,24 +2,23 @@
|
||||
from django.utils import timezone
|
||||
from rest_framework.exceptions import ValidationError, PermissionDenied
|
||||
|
||||
from apps.time_entries.models import TimeEntry
|
||||
from apps.time_entries.services.rates import resolve_rate
|
||||
from apps.workspaces.models import WorkspaceMembership
|
||||
|
||||
|
||||
def _verify_workspace_access(user, workspace_id):
|
||||
"""
|
||||
Ensures the user is an active member of the specified workspace.
|
||||
"""
|
||||
has_access = WorkspaceMembership.objects.filter(
|
||||
workspace_id=workspace_id,
|
||||
user=user,
|
||||
is_active=True,
|
||||
is_deleted=False
|
||||
).exists()
|
||||
|
||||
if not has_access:
|
||||
raise PermissionDenied("You do not have access to this workspace.")
|
||||
from apps.time_entries.models import TimeEntry
|
||||
from apps.time_entries.services.rates import resolve_rate
|
||||
from apps.workspaces.models import Workspace
|
||||
from apps.workspaces.services import TIME_ENTRIES_MANAGE_OWN, has_workspace_capability
|
||||
|
||||
|
||||
def _verify_workspace_access(user, workspace_id):
|
||||
"""
|
||||
Ensures the user is an active member of the specified workspace.
|
||||
"""
|
||||
workspace = Workspace.objects.filter(id=workspace_id, is_deleted=False).first()
|
||||
if not workspace or not has_workspace_capability(
|
||||
user,
|
||||
workspace,
|
||||
TIME_ENTRIES_MANAGE_OWN,
|
||||
):
|
||||
raise PermissionDenied("You do not have access to this workspace.")
|
||||
|
||||
|
||||
def create_time_entry(user, workspace_id, start_time, end_time=None, project=None, tags=None, description="", is_billable=False):
|
||||
|
||||
Reference in New Issue
Block a user