Fix #41 -- Drag-and-drop ticket editor

Undo/redo

Useful toolbox

Font selection

Add text content

Use hex for colors

JS-side dump and load

Save

Load layout, proper undo/redo

First steps to Python rendering

More PDF rendering

Copy and paste

Buttons for keyboard actions

Splash Screen

Block unbeforeunload in dirty state

Remove debugging output

Preview

Upload new PDFs via the editor

Fix bugs during PDF reload, link in settings form

New default ticket

Add OpenSans BI

Custom fonts, fix tests
This commit is contained in:
Raphael Michel
2017-05-05 12:19:16 +02:00
parent c98b0aac90
commit 0d3f5e0c32
27 changed files with 90428 additions and 165 deletions

View File

@@ -0,0 +1,138 @@
import json
import logging
import mimetypes
from datetime import timedelta
from django.core.files import File
from django.core.files.storage import default_storage
from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
from django.utils.crypto import get_random_string
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from django.views.generic import TemplateView
from pretix.base.i18n import language
from pretix.base.models import CachedFile
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.control.views import ChartContainingView
from pretix.helpers.database import rolledback_transaction
from pretix.plugins.ticketoutputpdf.signals import get_fonts
from .ticketoutput import PdfTicketOutput
logger = logging.getLogger(__name__)
class EditorView(EventPermissionRequiredMixin, ChartContainingView, TemplateView):
template_name = 'pretixplugins/ticketoutputpdf/index.html'
permission = 'can_change_settings'
accepted_formats = (
'application/pdf',
)
maxfilesize = 1024 * 1024 * 10
minfilesize = 10
def process_upload(self):
f = self.request.FILES.get('background')
error = False
if f.size > self.maxfilesize:
error = _('The uploaded PDF file is to large.')
if f.size < self.minfilesize:
error = _('The uploaded PDF file is to small.')
if mimetypes.guess_type(f.name)[0] not in self.accepted_formats:
error = _('Please only upload PDF files.')
# if there was an error, add error message to response_data and return
if error:
return error, None
return None, f
def post(self, request, *args, **kwargs):
if "background" in request.FILES:
error, fileobj = self.process_upload()
if error:
return JsonResponse({
"status": "error",
"error": error
})
c = CachedFile()
c.expires = now() + timedelta(days=7)
c.date = now()
c.filename = 'background.pdf'
c.type = 'application/pdf'
c.file = fileobj
c.save()
c.refresh_from_db()
return JsonResponse({
"status": "ok",
"id": c.id,
"url": c.file.url
})
cf = None
if request.POST.get("background", "").strip():
try:
cf = CachedFile.objects.get(id=request.POST.get("background"))
except CachedFile.DoesNotExist:
pass
if "preview" in request.POST:
with rolledback_transaction(), language(request.event.settings.locale):
item = request.event.items.create(name=_("Sample product"), default_price=42.23)
from pretix.base.models import Order
order = request.event.orders.create(status=Order.STATUS_PENDING, datetime=now(),
email='sample@pretix.eu',
expires=now(), code="PREVIEW1234", total=119)
p = order.positions.create(item=item, attendee_name=_("John Doe"), price=item.default_price)
prov = PdfTicketOutput(request.event,
override_layout=json.loads(request.POST.get("data")),
override_background=cf.file if cf else None)
fname, mimet, data = prov.generate(p)
resp = HttpResponse(data, content_type=mimet)
ftype = fname.split(".")[-1]
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="ticket-preview.{}"'.format(ftype)
return resp
elif "data" in request.POST:
if cf:
fexisting = request.event.settings.get('ticketoutput_pdf_layout', as_type=File)
if fexisting:
try:
default_storage.delete(fexisting.name)
except OSError: # pragma: no cover
logger.error('Deleting file %s failed.' % fexisting.name)
# Create new file
nonce = get_random_string(length=8)
fname = '%s-%s/%s/%s.%s.%s' % (
'event', 'settings', self.request.event.pk, 'ticketoutput_pdf_layout', nonce, 'pdf'
)
newname = default_storage.save(fname, cf.file)
request.event.settings.set('ticketoutput_pdf_background', 'file://' + newname)
request.event.settings.set('ticketoutput_pdf_layout', request.POST.get("data"))
return JsonResponse({'status': 'ok'})
return HttpResponseBadRequest()
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
prov = PdfTicketOutput(self.request.event)
ctx['fonts'] = get_fonts()
ctx['layout'] = json.dumps(
self.request.event.settings.get('ticketoutput_pdf_layout', as_type=list)
or prov._default_layout()
)
return ctx
class FontsCSSView(TemplateView):
content_type = 'text/css'
template_name = 'pretixplugins/ticketoutputpdf/webfonts.css'
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['fonts'] = get_fonts()
return ctx