From 420649e10a01e9b5c22a18eb6181834cef2f4ea0 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Sat, 23 Mar 2019 13:33:57 +0100 Subject: [PATCH] Refs #654 -- REST API: Allow to resend order link --- doc/api/resources/orders.rst | 34 +++++++++++++++++++++++++++++- src/pretix/api/views/order.py | 14 ++++++++++++ src/pretix/base/models/orders.py | 27 ++++++++++++++++++++++++ src/pretix/control/views/orders.py | 32 +++++----------------------- src/tests/api/test_orders.py | 21 ++++++++++++++++++ 5 files changed, 100 insertions(+), 28 deletions(-) diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst index dd32ed93ab..76cee34dc2 100644 --- a/doc/api/resources/orders.rst +++ b/doc/api/resources/orders.rst @@ -1145,7 +1145,7 @@ Order state operations :statuscode 200: no error :statuscode 400: The order cannot be marked as denied since the current order status does not allow it. :statuscode 401: Authentication failure - :statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource. + :statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this resource. :statuscode 404: The requested order does not exist. Generating invoices @@ -1189,6 +1189,38 @@ Generating invoices :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. +Sending e-mails +--------------- + +.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/resend_link/ + + Sends an email to the buyer with the link to the order page. + + **Example request**: + + .. sourcecode:: http + + POST /api/v1/organizers/bigevents/events/sampleconf/orders/ABC12/resend_link/ HTTP/1.1 + Host: pretix.eu + Accept: application/json, text/javascript + + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 204 No Content + Vary: Accept + + :param organizer: The ``slug`` field of the organizer to modify + :param event: The ``slug`` field of the event to modify + :param code: The ``code`` field of the order to send an email for + :statuscode 200: no error + :statuscode 400: The order does not have an email address associated + :statuscode 401: Authentication failure + :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. + :statuscode 503: The email could not be sent. List of all order positions --------------------------- diff --git a/src/pretix/api/views/order.py b/src/pretix/api/views/order.py index 3431b59dbd..12d6c481ff 100644 --- a/src/pretix/api/views/order.py +++ b/src/pretix/api/views/order.py @@ -342,6 +342,20 @@ class OrderViewSet(viewsets.ModelViewSet): status=status.HTTP_201_CREATED ) + @detail_route(methods=['POST']) + def resend_link(self, request, **kwargs): + order = self.get_object() + if not order.email: + return Response({'detail': 'There is no email address associated with this order.'}, status=status.HTTP_400_BAD_REQUEST) + try: + order.resend_link(user=self.request.user, auth=self.request.auth) + except SendMailException: + return Response({'detail': _('There was an error sending the mail. Please try again later.')}, status=status.HTTP_503_SERVICE_UNAVAILABLE) + + return Response( + status=status.HTTP_204_NO_CONTENT + ) + @detail_route(methods=['POST']) @transaction.atomic def regenerate_secrets(self, request, **kwargs): diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 984eaf0185..3fc81c0408 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -715,6 +715,33 @@ class Order(LockModel, LoggedModel): } ) + def resend_link(self, user=None, auth=None): + from pretix.multidomain.urlreverse import build_absolute_uri + + with language(self.locale): + try: + invoice_name = self.invoice_address.name + invoice_company = self.invoice_address.company + except InvoiceAddress.DoesNotExist: + invoice_name = "" + invoice_company = "" + email_template = self.event.settings.mail_text_resend_link + email_context = { + 'event': self.event.name, + 'url': build_absolute_uri(self.event, 'presale:event.order', kwargs={ + 'order': self.code, + 'secret': self.secret + }), + 'invoice_name': invoice_name, + 'invoice_company': invoice_company, + } + email_subject = _('Your order: %(code)s') % {'code': self.code} + self.send_mail( + email_subject, email_template, email_context, + 'pretix.event.order.email.resend', user=user, auth=auth, + attach_tickets=True + ) + @property def positions_with_tickets(self): for op in self.positions.all(): diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index d21e81299c..6d0be55975 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -1055,33 +1055,11 @@ class OrderResendLink(OrderView): permission = 'can_change_orders' def post(self, *args, **kwargs): - with language(self.order.locale): - try: - try: - invoice_name = self.order.invoice_address.name - invoice_company = self.order.invoice_address.company - except InvoiceAddress.DoesNotExist: - invoice_name = "" - invoice_company = "" - email_template = self.order.event.settings.mail_text_resend_link - email_context = { - 'event': self.order.event.name, - 'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={ - 'order': self.order.code, - 'secret': self.order.secret - }), - 'invoice_name': invoice_name, - 'invoice_company': invoice_company, - } - email_subject = _('Your order: %(code)s') % {'code': self.order.code} - self.order.send_mail( - email_subject, email_template, email_context, - 'pretix.event.order.email.resend', user=self.request.user, - attach_tickets=True - ) - except SendMailException: - messages.error(self.request, _('There was an error sending the mail. Please try again later.')) - return redirect(self.get_order_url()) + try: + self.order.resend_link(user=self.request.user) + except SendMailException: + messages.error(self.request, _('There was an error sending the mail. Please try again later.')) + return redirect(self.get_order_url()) messages.success(self.request, _('The email has been queued to be sent.')) return redirect(self.get_order_url()) diff --git a/src/tests/api/test_orders.py b/src/tests/api/test_orders.py index 9395427b03..41b3fb70b3 100644 --- a/src/tests/api/test_orders.py +++ b/src/tests/api/test_orders.py @@ -2703,3 +2703,24 @@ def test_order_regenerate_secrets(token_client, organizer, event, order): order.refresh_from_db() assert s != order.secret assert ps != order.positions.first().secret + + +@pytest.mark.django_db +def test_order_resend_link(token_client, organizer, event, order): + djmail.outbox = [] + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/orders/{}/resend_link/'.format( + organizer.slug, event.slug, order.code + ), format='json', data={} + ) + assert resp.status_code == 204 + assert len(djmail.outbox) == 1 + + order.email = None + order.save() + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/orders/{}/resend_link/'.format( + organizer.slug, event.slug, order.code + ), format='json', data={} + ) + assert resp.status_code == 400