Decouple CachedTicket from CachedFile

This commit is contained in:
Raphael Michel
2016-12-21 18:37:12 +01:00
parent ad60dadee4
commit 77e917345c
7 changed files with 111 additions and 48 deletions

View File

@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2016-12-21 17:20
from __future__ import unicode_literals
from django.db import migrations, models
import pretix.base.models.orders
def invalidate_ticket_cache(apps, schema_editor):
CachedTicket = apps.get_model('pretixbase', 'CachedTicket')
for ct in CachedTicket.objects.all():
try:
if ct.cachedfile:
ct.cachedfile.delete()
if ct.cachedfile.file:
ct.cachedfile.file.delete(False)
except models.Model.DoesNotExist:
pass
ct.delete()
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0050_orderposition_positionid'),
]
operations = [
migrations.RunPython(
invalidate_ticket_cache, migrations.RunPython.noop
),
migrations.RemoveField(
model_name='cachedticket',
name='cachedfile',
),
migrations.AddField(
model_name='cachedticket',
name='extension',
field=models.CharField(default='', max_length=255),
preserve_default=False,
),
migrations.AddField(
model_name='cachedticket',
name='file',
field=models.FileField(blank=True, null=True, upload_to=pretix.base.models.orders.cachedticket_name),
),
migrations.AddField(
model_name='cachedticket',
name='type',
field=models.CharField(default='', max_length=255),
preserve_default=False,
),
]

View File

@@ -15,7 +15,7 @@ from django.utils.timezone import make_aware, now
from django.utils.translation import ugettext_lazy as _
from ..decimal import round_decimal
from .base import CachedFile, LoggedModel
from .base import LoggedModel
from .event import Event
from .items import Item, ItemVariation, Question, QuestionOption, Quota
@@ -565,16 +565,28 @@ class InvoiceAddress(models.Model):
vat_id = models.CharField(max_length=255, blank=True, verbose_name=_('VAT ID'))
def cachedticket_name(instance, filename: str) -> str:
secret = get_random_string(length=16, allowed_chars=string.ascii_letters + string.digits)
return 'tickets/{org}/{ev}/{code}-{no}-{prov}-{secret}.pdf'.format(
org=instance.order_position.order.event.organizer.slug,
ev=instance.order_position.order.event.slug,
prov=instance.provider,
no=instance.order_position.positionid,
code=instance.order_position.order.code,
secret=secret
)
class CachedTicket(models.Model):
order_position = models.ForeignKey(OrderPosition, on_delete=models.CASCADE)
cachedfile = models.ForeignKey(CachedFile, on_delete=models.CASCADE, null=True)
provider = models.CharField(max_length=255)
type = models.CharField(max_length=255)
extension = models.CharField(max_length=255)
file = models.FileField(null=True, blank=True, upload_to=cachedticket_name)
@receiver(post_delete, sender=CachedTicket)
def cached_file_delete(sender, instance, **kwargs):
try:
if instance.cachedfile:
instance.cachedfile.delete()
except CachedFile.DoesNotExist:
pass
def cachedticket_delete(sender, instance, **kwargs):
if instance.file:
# Pass false so FileField doesn't save the model.
instance.file.delete(False)

View File

@@ -1,13 +1,11 @@
from datetime import timedelta
import os
from django.core.files.base import ContentFile
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from pretix.base.i18n import language
from pretix.base.models import (
CachedFile, CachedTicket, Event, Order, OrderPosition, cachedfile_name,
)
from pretix.base.models import CachedTicket, Event, Order, OrderPosition
from pretix.base.services.async import ProfiledTask
from pretix.base.signals import register_ticket_outputs
from pretix.celery import app
@@ -17,23 +15,21 @@ from pretix.helpers.database import rolledback_transaction
@app.task(base=ProfiledTask)
def generate(order_position: str, provider: str):
order_position = OrderPosition.objects.select_related('order', 'order__event').get(id=order_position)
ct = CachedTicket.objects.get_or_create(order_position=order_position, provider=provider)[0]
if not ct.cachedfile:
cf = CachedFile()
cf.date = now()
cf.expires = order_position.order.event.date_from + timedelta(days=30)
cf.save()
ct.cachedfile = cf
ct.save()
try:
ct = CachedTicket.objects.get(order_position=order_position, provider=provider)
except CachedTicket.DoesNotExist:
ct = CachedTicket(order_position=order_position, provider=provider)
with language(order_position.order.locale):
responses = register_ticket_outputs.send(order_position.order.event)
for receiver, response in responses:
prov = response(order_position.order.event)
if prov.identifier == provider:
ct.cachedfile.filename, ct.cachedfile.type, data = prov.generate(order_position)
ct.cachedfile.file.save(cachedfile_name(ct.cachedfile, ct.cachedfile.filename), ContentFile(data))
ct.cachedfile.save()
filename, ct.type, data = prov.generate(order_position)
path, ext = os.path.splitext(filename)
ct.extension = ext
ct.save()
ct.file.save(filename, ContentFile(data))
class DummyRollbackException(Exception):

View File

@@ -32,7 +32,8 @@ class BaseTicketOutput:
def generate(self, order: OrderPosition) -> Tuple[str, str, str]:
"""
This method should generate the download file and return a tuple consisting of a
filename, a file type and file content.
filename, a file type and file content. The extension will be taken from the filename
which is otherwise ignored.
"""
raise NotImplementedError()

View File

@@ -1,5 +1,3 @@
import os
from django.http import FileResponse, Http404, HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property
@@ -23,8 +21,7 @@ class DownloadView(TemplateView):
return HttpResponse('1' if self.object.file else '0')
elif self.object.file:
resp = FileResponse(self.object.file.file, content_type=self.object.type)
_, ext = os.path.splitext(self.object.filename)
resp['Content-Disposition'] = 'attachment; filename="{}{}"'.format(self.object.id, ext)
resp['Content-Disposition'] = 'attachment; filename="{}"'.format(self.object.filename)
return resp
else:
return super().get(request, *args, **kwargs)