diff options
author | 2019-07-03 21:25:43 +0200 | |
---|---|---|
committer | 2019-07-03 21:25:43 +0200 | |
commit | 300c912d108ae2e35cb90983844ae5b785505d2e (patch) | |
tree | 97d0cb1ee0d03ea2db5fedfe81b37dea5e2cfdd4 /pydis_site/apps/api/viewsets | |
parent | Removing unused import (diff) |
Move end nomination operation to PATCH endpoint
Diffstat (limited to 'pydis_site/apps/api/viewsets')
-rw-r--r-- | pydis_site/apps/api/viewsets/bot/nomination.py | 108 |
1 files changed, 55 insertions, 53 deletions
diff --git a/pydis_site/apps/api/viewsets/bot/nomination.py b/pydis_site/apps/api/viewsets/bot/nomination.py index 2eec6275..fad16aa5 100644 --- a/pydis_site/apps/api/viewsets/bot/nomination.py +++ b/pydis_site/apps/api/viewsets/bot/nomination.py @@ -67,7 +67,7 @@ class NominationViewSet(CreateModelMixin, RetrieveModelMixin, ListModelMixin, Ge ... } ### Status codes - - 200: returned on succes + - 200: returned on success - 404: returned if a nomination with the given `id` could not be found ### POST /bot/nominations @@ -84,7 +84,7 @@ class NominationViewSet(CreateModelMixin, RetrieveModelMixin, ListModelMixin, Ge ... 'user': 409107086526644234 ... } - ### Response format + #### Response format See `GET /bot/nominations/<id:int>` #### Status codes @@ -95,53 +95,59 @@ class NominationViewSet(CreateModelMixin, RetrieveModelMixin, ListModelMixin, Ge - The request contained a field that cannot be set at creation. ### PATCH /bot/nominations/<id:int> - Update the nomination with the given `id` and return the updated nomination. - For active nominations, only the `reason` may be updated; for inactive - nominations, both the `reason` and `end_reason` may be updated. + Update or end the nomination with the given `id` and return the updated nomination. + + The PATCH route can be used for three distinct operations: + 1. Updating the `reason` of `active` nomination; + 2. Ending an `active` nomination; + 3. Updating the `end_reason` or `reason` field of an `inactive` nomination. + + While the response format and status codes are the same for all three operations (see + below), the request bodies vary depending on the operation. For all operations holds + that providing other valid fields is not allowed and invalid fields are ignored. + + ### 1. Updating the `reason` of `active` nomination #### Request body >>> { ... 'reason': 'He would make a great helper', - ... 'end_reason': 'He needs some time to mature his Python knowledge' ... } - ### Response format + #### Response format See `GET /bot/nominations/<id:int>` - ## Status codes + #### Status codes - 200: returned on success - 400: if a field in the request body is invalid or disallowed - 404: if an infraction with the given `id` could not be found - ### PATCH /bot/nominations/<id:int>/end_nomination - Ends an active nomination and returns the updated nomination. + ### 2. Ending an `active` nomination - The `end_reason` field is the only allowed and required field - for this operation. The nomination will automatically be marked as - `active = false` and the datetime of this operation will be added to - the `ended_at` field. + #### Request body + >>> { + ... 'active': False + ... 'end_reason': 'They've been added to the Helpers team', + ... } + + See operation 1 for the response format and status codes. + + ### 3. Updating the `end_reason` or `reason` field of an `inactive` nomination. #### Request body >>> { - ... 'end_reason': 'He needs some time to mature his Python knowledge' + ... 'reason': 'Updated reason for this nomination', + ... 'end_reason': 'Updated end_reason for this nomination', ... } - ### Response format - See `GET /bot/nominations/<id:int>` + Note: The request body may contain either or both fields. - #### Status codes - - 200: returned on success - - 400: returned on failure for the following reasons: - - `end_reason` is missing from the request body; - - Any other field is present in the request body; - - The nomination was already inactiive. - - 404: if an infraction with the given `id` could not be found + See operation 1 for the response format and status codes. """ serializer_class = NominationSerializer queryset = Nomination.objects.all() filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter) filter_fields = ('user__id', 'actor__id', 'active') - frozen_fields = ('id', 'actor', 'inserted_at', 'user', 'ended_at', 'active') + frozen_fields = ('id', 'actor', 'inserted_at', 'user', 'ended_at') frozen_on_create = ('ended_at', 'end_reason', 'active', 'inserted_at') def create(self, request, *args, **kwargs): @@ -180,43 +186,39 @@ class NominationViewSet(CreateModelMixin, RetrieveModelMixin, ListModelMixin, Ge raise ValidationError({field: ['This field cannot be updated.']}) instance = self.get_object() - - if instance.active and request.data.get('end_reason'): - raise ValidationError( - {'end_reason': ["An active nomination can't have an unnominate reason."]} - ) - serializer = self.get_serializer(instance, data=request.data, partial=True) serializer.is_valid(raise_exception=True) - serializer.save() - return Response(serializer.data) + data = serializer.validated_data - def update(self, request, *args, **kwargs): - """ - DRF action for ending an active nomination. + # There are three distinct PATCH scenarios we need to validate. + if instance.active and 'active' not in data: + # 1. We're updating an active nomination without ending it. + if request.data.get('end_reason'): + raise ValidationError( + {'end_reason': ["An active nomination can't have an end reason."]} + ) - Creates an API endpoint /bot/nominations/{id}/end_nomination to end a nomination. See - the class docstring for documentation. - """ - for field in request.data: - if field != "end_reason": - raise ValidationError({field: ['This field cannot be set at end_nomination.']}) + elif instance.active and not data.get('active'): + # 2. We're ending an active nomination. + if 'reason' in data: + raise ValidationError( + {'reason': ['This field cannot be set when ending a nomination.']} + ) + + if 'end_reason' not in request.data: + raise ValidationError( + {'end_reason': ['This field is required when ending a nomination.']} + ) + + instance.ended_at = timezone.now() - if "end_reason" not in request.data: + elif 'active' in data: + # 3. The `active` field is only allowed when ending a nomination. raise ValidationError( - {'end_reason': ['This field is required when ending a nomination.']} + {'active': ['This field can only be used to end a nomination']} ) - instance = self.get_object() - if not instance.active: - raise ValidationError({'active': ['A nomination must be active to be ended.']}) - - serializer = self.get_serializer(instance, data=request.data, partial=True) - serializer.is_valid(raise_exception=True) - instance.active = False - instance.ended_at = timezone.now() serializer.save() - instance.save() return Response(serializer.data) |