oncall-engine/engine/apps/api/views/shift_swap.py
Joey Orlando 74b919ee3e
shift swap requests model + CRUD endpoints (#2597)
# What this PR does

This PR should allow us to start working on _most_ of the remaining
tasks for this feature set.
- Adds a basic `ShiftSwapRequest` model + CRUD endpoints. 
- Adds a `POST /api/internal/v1/shift_swaps/<id>/take` endpoint which
allows a benefactor to take a request (only when certain conditions
about the ssr are met)

Closes #2587 

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required) will be done in #2589
- [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required) (will update once we ship the finalized feature set)
2023-07-21 19:35:19 +00:00

90 lines
3.7 KiB
Python

import logging
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from apps.api.permissions import IsOwner, RBACPermission
from apps.api.serializers.shift_swap import ShiftSwapRequestSerializer
from apps.auth_token.auth import PluginAuthentication
from apps.mobile_app.auth import MobileAppAuthTokenAuthentication
from apps.schedules import exceptions
from apps.schedules.models import ShiftSwapRequest
from common.api_helpers.exceptions import BadRequest
from common.api_helpers.mixins import PublicPrimaryKeyMixin
from common.api_helpers.paginators import FiftyPageSizePaginator
from common.insight_log import EntityEvent, write_resource_insight_log
logger = logging.getLogger(__name__)
class ShiftSwapViewSet(PublicPrimaryKeyMixin, ModelViewSet):
authentication_classes = (PluginAuthentication, MobileAppAuthTokenAuthentication)
permission_classes = (IsAuthenticated, RBACPermission)
rbac_permissions = {
# TODO: add note to public documentation about these permissions also giving access to shift swaps
# unless we want to make a separate resource type for them?
"metadata": [RBACPermission.Permissions.SCHEDULES_READ],
"list": [RBACPermission.Permissions.SCHEDULES_READ],
"retrieve": [RBACPermission.Permissions.SCHEDULES_READ],
"create": [RBACPermission.Permissions.SCHEDULES_WRITE],
"update": [RBACPermission.Permissions.SCHEDULES_WRITE],
"partial_update": [RBACPermission.Permissions.SCHEDULES_WRITE],
"destroy": [RBACPermission.Permissions.SCHEDULES_WRITE],
"take": [RBACPermission.Permissions.SCHEDULES_WRITE],
}
is_beneficiary = IsOwner(ownership_field="beneficiary")
rbac_object_permissions = {
is_beneficiary: [
"update",
"partial_update",
"destroy",
],
}
model = ShiftSwapRequest
serializer_class = ShiftSwapRequestSerializer
pagination_class = FiftyPageSizePaginator
def get_queryset(self):
queryset = ShiftSwapRequest.objects.filter(schedule__organization=self.request.auth.organization)
return self.serializer_class.setup_eager_loading(queryset)
def perform_destroy(self, instance):
super().perform_destroy(instance)
write_resource_insight_log(instance=instance, author=self.request.user, event=EntityEvent.DELETED)
def perform_create(self, serializer):
beneficiary = self.request.user
serializer.save(beneficiary=beneficiary)
write_resource_insight_log(instance=serializer.instance, author=beneficiary, event=EntityEvent.CREATED)
def perform_update(self, serializer):
prev_state = serializer.instance.insight_logs_serialized
serializer.save()
new_state = serializer.instance.insight_logs_serialized
write_resource_insight_log(
instance=serializer.instance,
author=self.request.user,
event=EntityEvent.UPDATED,
prev_state=prev_state,
new_state=new_state,
)
@action(methods=["post"], detail=True)
def take(self, request, pk) -> Response:
shift_swap = self.get_object()
try:
shift_swap.take(request.user)
except exceptions.ShiftSwapRequestNotOpenForTaking:
raise BadRequest(detail="The shift swap request is not in a state which allows it to be taken")
except exceptions.BeneficiaryCannotTakeOwnShiftSwapRequest:
raise BadRequest(detail="A shift swap request cannot be created and taken by the same user")
return Response(ShiftSwapRequestSerializer(shift_swap).data, status=status.HTTP_200_OK)