aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/api/viewsets
diff options
context:
space:
mode:
authorGravatar SebastiaanZ <[email protected]>2019-07-03 21:25:43 +0200
committerGravatar SebastiaanZ <[email protected]>2019-07-03 21:25:43 +0200
commit300c912d108ae2e35cb90983844ae5b785505d2e (patch)
tree97d0cb1ee0d03ea2db5fedfe81b37dea5e2cfdd4 /pydis_site/apps/api/viewsets
parentRemoving 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.py108
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)