diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst index 0f2bda20e..dd32ed93a 100644 --- a/doc/api/resources/orders.rst +++ b/doc/api/resources/orders.rst @@ -585,7 +585,7 @@ Updating order fields PATCH /api/v1/organizers/bigevents/events/sampleconf/orders/ABC12/ HTTP/1.1 Host: pretix.eu Accept: application/json, text/javascript - Content: application/json + Content-Type: application/json { "email": "other@example.org", @@ -611,8 +611,41 @@ Updating order fields :statuscode 200: no error :statuscode 400: The order could not be updated due to invalid submitted data. :statuscode 401: Authentication failure - :statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this - order. + :statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order. + +Generating new secrets +---------------------- + +.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/regenerate_secrets/ + + Triggers generation of new ``secret`` attributes for both the order and all order positions. + + **Example request**: + + .. sourcecode:: http + + POST /api/v1/organizers/bigevents/events/sampleconf/orders/ABC12/regenerate_secrets/ HTTP/1.1 + Host: pretix.eu + Accept: application/json, text/javascript + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Vary: Accept + Content-Type: application/json + + (Full order resource, see above.) + + :param organizer: The ``slug`` field of the organizer of the event + :param event: The ``slug`` field of the event + :param code: The ``code`` field of the order to update + + :statuscode 200: no error + :statuscode 400: The order could not be updated due to invalid submitted data. + :statuscode 401: Authentication failure + :statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order. Deleting orders --------------- @@ -765,7 +798,7 @@ Creating orders POST /api/v1/organizers/bigevents/events/sampleconf/orders/ HTTP/1.1 Host: pretix.eu Accept: application/json, text/javascript - Content: application/json + Content-Type: application/json { "email": "dummy@example.org", @@ -1115,8 +1148,8 @@ Order state operations :statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource. :statuscode 404: The requested order does not exist. -Invoice generation ------------------- +Generating invoices +------------------- .. http:post:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/create_invoice/ diff --git a/src/pretix/api/views/order.py b/src/pretix/api/views/order.py index 3b930ad8d..3431b59db 100644 --- a/src/pretix/api/views/order.py +++ b/src/pretix/api/views/order.py @@ -29,6 +29,7 @@ from pretix.api.serializers.order import ( from pretix.base.models import ( CachedCombinedTicket, CachedTicket, Device, Event, Invoice, Order, OrderPayment, OrderPosition, OrderRefund, Quota, TeamAPIToken, + generate_position_secret, generate_secret, ) from pretix.base.payment import PaymentException from pretix.base.services.invoices import ( @@ -341,6 +342,24 @@ class OrderViewSet(viewsets.ModelViewSet): status=status.HTTP_201_CREATED ) + @detail_route(methods=['POST']) + @transaction.atomic + def regenerate_secrets(self, request, **kwargs): + order = self.get_object() + order.secret = generate_secret() + for op in order.all_positions.all(): + op.secret = generate_position_secret() + op.save() + order.save(update_fields=['secret']) + CachedTicket.objects.filter(order_position__order=order).delete() + CachedCombinedTicket.objects.filter(order=order).delete() + order.log_action( + 'pretix.event.order.secret.changed', + user=self.request.user, + auth=self.request.auth, + ) + return self.retrieve(request, [], **kwargs) + @detail_route(methods=['POST']) def extend(self, request, **kwargs): new_date = request.data.get('expires', None) diff --git a/src/tests/api/test_orders.py b/src/tests/api/test_orders.py index cc6ceaa09..9395427b0 100644 --- a/src/tests/api/test_orders.py +++ b/src/tests/api/test_orders.py @@ -2688,3 +2688,18 @@ def test_order_create_invoice(token_client, organizer, event, order): ) assert resp.status_code == 400 assert resp.data == {'detail': 'You cannot generate an invoice for this order.'} + + +@pytest.mark.django_db +def test_order_regenerate_secrets(token_client, organizer, event, order): + s = order.secret + ps = order.positions.first().secret + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/orders/{}/regenerate_secrets/'.format( + organizer.slug, event.slug, order.code + ), format='json', data={} + ) + assert resp.status_code == 200 + order.refresh_from_db() + assert s != order.secret + assert ps != order.positions.first().secret