Add option to copy shop URL and generate QR code (#3215)

Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
Raphael Michel
2023-04-06 10:04:11 +02:00
committed by GitHub
parent ddade60625
commit dda1368d81
6 changed files with 84 additions and 1 deletions

View File

@@ -16,6 +16,42 @@
{% endif %}
</small>
</h1>
<div class="helper-space-below">
{% trans "Shop URL:" %}
<span id="shop_url" class="text-muted">{% abseventurl request.event "presale:event.index" %}</span>
<button type="button" class="btn btn-default btn-xs btn-clipboard js-only" data-clipboard-target="#shop_url">
<i class="fa fa-clipboard" aria-hidden="true"></i>
<span class="sr-only">{% trans "Copy to clipboard" %}</span>
</button>
<div class="btn-group helper-display-inline-block">
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" title="{% trans "Create QR code" %}" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-qrcode" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li>
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="png" %}" target="_blank" download>
{% blocktrans with filetype="PNG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
</a>
</li>
<li>
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="svg" %}" target="_blank" download>
{% blocktrans with filetype="SVG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
</a>
</li>
<li>
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="jpeg" %}" target="_blank" download>
{% blocktrans with filetype="JPG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
</a>
</li>
<li>
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="gif" %}" target="_blank" download>
{% blocktrans with filetype="GIF" %}Download QR code as {{ filetype }} image{% endblocktrans %}
</a>
</li>
</ul>
</div>
<div class="clearfix"></div>
</div>
{% if has_overpaid_orders %}
<div class="alert alert-warning">
{% blocktrans trimmed %}

View File

@@ -231,6 +231,7 @@ urlpatterns = [
re_path(r'^search/payments/$', search.PaymentSearch.as_view(), name='search.payments'),
re_path(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
re_path(r'^$', dashboards.event_index, name='event.index'),
re_path(r'^qrcode.(?P<filetype>(png|jpeg|gif|svg))$', event.EventQRCode.as_view(), name='event.qrcode'),
re_path(r'^widgets.json$', dashboards.event_index_widgets_lazy, name='event.index.widgets'),
re_path(r'^logs/embed$', dashboards.event_index_log_lazy, name='event.index.logs'),
re_path(r'^live/$', event.EventLive.as_view(), name='event.live'),

View File

@@ -38,10 +38,13 @@ import operator
import re
from collections import OrderedDict
from decimal import Decimal
from io import BytesIO
from itertools import groupby
from urllib.parse import urlsplit
import bleach
import qrcode
import qrcode.image.svg
from django.apps import apps
from django.conf import settings
from django.contrib import messages
@@ -86,7 +89,7 @@ from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.control.views.mailsetup import MailSettingsSetupView
from pretix.control.views.user import RecentAuthenticationRequiredMixin
from pretix.helpers.database import rolledback_transaction
from pretix.multidomain.urlreverse import get_event_domain
from pretix.multidomain.urlreverse import build_absolute_uri, get_event_domain
from pretix.plugins.stripe.payment import StripeSettingsHolder
from pretix.presale.style import regenerate_css
@@ -1504,3 +1507,35 @@ class QuickSetupView(FormView):
},
] if self.request.method != "POST" else []
)
class EventQRCode(EventPermissionRequiredMixin, View):
permission = 'can_change_event_settings'
def get(self, request, *args, filetype, **kwargs):
url = build_absolute_uri(request.event, 'presale:event.index')
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_M,
box_size=10,
border=4,
)
qr.add_data(url)
qr.make(fit=True)
if filetype == 'svg':
factory = qrcode.image.svg.SvgPathImage
img = qrcode.make('Some data here', image_factory=factory)
r = HttpResponse(img.to_string(), content_type='image/svg+xml')
r['Content-Disposition'] = f'inline; filename="qrcode-{request.event.slug}.{filetype}"'
return r
elif filetype in ('jpeg', 'png', 'gif'):
img = qr.make_image(fill_color="black", back_color="white")
byte_io = BytesIO()
img.save(byte_io, filetype.upper())
byte_io.seek(0)
r = HttpResponse(byte_io.read(), content_type='image/' + filetype)
r['Content-Disposition'] = f'inline; filename="qrcode-{request.event.slug}.{filetype}"'
return r

View File

@@ -139,12 +139,18 @@ p.bigger {
font-size: 16px;
}
.helper-position-relative {
position: relative;
}
.helper-display-block {
display: block !important;
}
.helper-display-inline {
display: inline !important;
}
.helper-display-inline-block {
display: inline-block !important;
}
.helper-display-none-soft {
display: none;
}

View File

@@ -218,6 +218,7 @@ setup(
'python-u2flib-server==4.*',
'pytz',
'pyuca',
'qrcode==7.4.*',
'redis==4.5.*,>=4.5.4',
'reportlab==3.6.*',
'requests==2.28.*',

View File

@@ -142,6 +142,10 @@ def logged_in_client(client, event):
('/control/events/add', 200),
('/control/event/{orga}/{event}/', 200),
('/control/event/{orga}/{event}/qrcode.png', 200),
('/control/event/{orga}/{event}/qrcode.jpeg', 200),
('/control/event/{orga}/{event}/qrcode.svg', 200),
('/control/event/{orga}/{event}/qrcode.gif', 200),
('/control/event/{orga}/{event}/live/', 200),
('/control/event/{orga}/{event}/dangerzone/', 200),
('/control/event/{orga}/{event}/cancel/', 200),