diff --git a/src/pretix/base/__init__.py b/src/pretix/base/__init__.py index 89086bc87f..48435281d9 100644 --- a/src/pretix/base/__init__.py +++ b/src/pretix/base/__init__.py @@ -8,7 +8,7 @@ class PretixBaseConfig(AppConfig): def ready(self): from . import exporter # NOQA from . import payment # NOQA - from .services import export, mail # NOQA + from .services import export, mail, tickets # NOQA try: from .celery import app as celery_app # NOQA diff --git a/src/pretix/base/services/export.py b/src/pretix/base/services/export.py index ccfeba7b54..90807a5cfd 100644 --- a/src/pretix/base/services/export.py +++ b/src/pretix/base/services/export.py @@ -14,6 +14,7 @@ def export(event, fileid, provider, form_data): if ex.identifier == provider: file.filename, file.type, data = ex.render(form_data) file.file.save(cachedfile_name(file, file.filename), ContentFile(data)) + file.save() if settings.HAS_CELERY: diff --git a/src/pretix/base/services/tickets.py b/src/pretix/base/services/tickets.py new file mode 100644 index 0000000000..264deb9c25 --- /dev/null +++ b/src/pretix/base/services/tickets.py @@ -0,0 +1,34 @@ +from datetime import timedelta +from django.conf import settings +from django.core.files.base import ContentFile +from django.utils.timezone import now + +from pretix.base.models import CachedFile, cachedfile_name, Order, CachedTicket +from pretix.base.signals import register_ticket_outputs + + +def generate(order, provider): + order = Order.objects.current.select_related('event').get(identity=order) + ct = CachedTicket.objects.get_or_create(order=order, provider=provider)[0] + if not ct.cachedfile: + cf = CachedFile() + cf.date = now() + cf.expires = order.event.date_from + timedelta(days=30) + cf.save() + ct.cachedfile = cf + ct.save() + + responses = register_ticket_outputs.send(order.event) + for receiver, response in responses: + prov = response(order.event) + if prov.identifier == provider: + ct.cachedfile.filename, ct.cachedfile.type, data = prov.generate(order) + ct.cachedfile.file.save(cachedfile_name(ct.cachedfile, ct.cachedfile.filename), ContentFile(data)) + ct.cachedfile.save() + + +if settings.HAS_CELERY: + from pretix.celery import app + + generate_task = app.task(generate) + generate = lambda *args, **kwargs: generate_task.apply_async(args=args, kwargs=kwargs) diff --git a/src/pretix/base/ticketoutput.py b/src/pretix/base/ticketoutput.py index 680bd8cd5b..a7f17d73d3 100644 --- a/src/pretix/base/ticketoutput.py +++ b/src/pretix/base/ticketoutput.py @@ -28,9 +28,10 @@ class BaseTicketOutput: """ return self.settings.get('_enabled', as_type=bool) - def generate(self, request: HttpRequest, order: Order) -> HttpResponse: + def generate(self, order: Order) -> tuple: """ - This method should generate the download file and return it to the user. + This method should generate the download file and return a tuple consisting of a + filename, a file type and file content. """ raise NotImplementedError() diff --git a/src/pretix/plugins/ticketoutputpdf/ticketoutput.py b/src/pretix/plugins/ticketoutputpdf/ticketoutput.py index 256c1784a2..ecadd11a6d 100644 --- a/src/pretix/plugins/ticketoutputpdf/ticketoutput.py +++ b/src/pretix/plugins/ticketoutputpdf/ticketoutput.py @@ -20,7 +20,7 @@ class PdfTicketOutput(BaseTicketOutput): download_button_text = _('Download PDF') download_button_icon = 'fa-print' - def generate(self, request, order): + def generate(self, order): from reportlab.graphics.shapes import Drawing from reportlab.pdfgen import canvas from reportlab.lib import pagesizes, units @@ -28,9 +28,6 @@ class PdfTicketOutput(BaseTicketOutput): from reportlab.graphics import renderPDF from PyPDF2 import PdfFileWriter, PdfFileReader - response = HttpResponse(content_type='application/pdf') - response['Content-Disposition'] = 'inline; filename="order%s%s.pdf"' % (request.event.slug, order.code) - pagesize = self.settings.get('pagesize', default='A4') if hasattr(pagesizes, pagesize): pagesize = getattr(pagesizes, pagesize) @@ -55,7 +52,7 @@ class PdfTicketOutput(BaseTicketOutput): p.setFont("Helvetica", event_s) event_x = self.settings.get('event_x', default=15, as_type=float) event_y = self.settings.get('event_y', default=235, as_type=float) - p.drawString(event_x * units.mm, event_y * units.mm, str(request.event.name)) + p.drawString(event_x * units.mm, event_y * units.mm, str(self.event.name)) name_s = self.settings.get('name_s', default=17, as_type=float) if name_s: @@ -72,7 +69,7 @@ class PdfTicketOutput(BaseTicketOutput): p.setFont("Helvetica", price_s) price_x = self.settings.get('price_x', default=15, as_type=float) price_y = self.settings.get('price_y', default=210, as_type=float) - p.drawString(price_x * units.mm, price_y * units.mm, "%s %s" % (str(op.price), request.event.currency)) + p.drawString(price_x * units.mm, price_y * units.mm, "%s %s" % (str(op.price), self.event.currency)) qr_s = self.settings.get('qr_s', default=80, as_type=float) if qr_s: @@ -107,8 +104,10 @@ class PdfTicketOutput(BaseTicketOutput): bg_page.mergePage(page) output.addPage(bg_page) - output.write(response) - return response + outbuffer = BytesIO() + output.write(outbuffer) + outbuffer.seek(0) + return 'order%s%s.pdf' % (self.event.slug, order.code), 'application/pdf', outbuffer.read() @property def settings_form_fields(self) -> dict: diff --git a/src/pretix/presale/views/order.py b/src/pretix/presale/views/order.py index 67b09ee02e..ac86c1b36d 100644 --- a/src/pretix/presale/views/order.py +++ b/src/pretix/presale/views/order.py @@ -1,3 +1,4 @@ +from datetime import timedelta from django.contrib import messages from django.core.urlresolvers import reverse from django.http import HttpResponseForbidden, HttpResponseNotFound @@ -7,7 +8,8 @@ from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from django.views.generic import TemplateView, View -from pretix.base.models import Order, OrderPosition +from pretix.base.models import Order, OrderPosition, CachedTicket, CachedFile +from pretix.base.services.tickets import generate from pretix.base.signals import ( register_payment_providers, register_ticket_outputs, ) @@ -277,4 +279,19 @@ class OrderDownload(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin, and now() < self.request.event.settings.ticket_download_date)): messages.error(request, _('Ticket download is not (yet) enabled.')) return redirect(self.get_order_url()) - return self.output.generate(request, self.order) + + try: + ct = CachedTicket.objects.get(order=self.order, provider=self.output.identifier) + except CachedTicket.DoesNotExist: + ct = CachedTicket(order=self.order, provider=self.output.identifier) + try: + ct.cachedfile + except CachedFile.DoesNotExist: + cf = CachedFile() + cf.date = now() + cf.expires = self.request.event.date_from + timedelta(days=30) + cf.save() + ct.cachedfile = cf + ct.save() + generate(self.order.identity, self.output.identifier) + return redirect(reverse('presale:cachedfile.download', kwargs={'id': ct.cachedfile.id}))