mirror of
https://github.com/pretix/pretix.git
synced 2025-12-21 16:42:26 +00:00
Add option to copy shop URL and generate QR code (#3215)
Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
@@ -16,6 +16,42 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</small>
|
</small>
|
||||||
</h1>
|
</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 %}
|
{% if has_overpaid_orders %}
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
{% blocktrans trimmed %}
|
{% blocktrans trimmed %}
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ urlpatterns = [
|
|||||||
re_path(r'^search/payments/$', search.PaymentSearch.as_view(), name='search.payments'),
|
re_path(r'^search/payments/$', search.PaymentSearch.as_view(), name='search.payments'),
|
||||||
re_path(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
|
re_path(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
|
||||||
re_path(r'^$', dashboards.event_index, name='event.index'),
|
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'^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'^logs/embed$', dashboards.event_index_log_lazy, name='event.index.logs'),
|
||||||
re_path(r'^live/$', event.EventLive.as_view(), name='event.live'),
|
re_path(r'^live/$', event.EventLive.as_view(), name='event.live'),
|
||||||
|
|||||||
@@ -38,10 +38,13 @@ import operator
|
|||||||
import re
|
import re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from io import BytesIO
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from urllib.parse import urlsplit
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import bleach
|
import bleach
|
||||||
|
import qrcode
|
||||||
|
import qrcode.image.svg
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
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.mailsetup import MailSettingsSetupView
|
||||||
from pretix.control.views.user import RecentAuthenticationRequiredMixin
|
from pretix.control.views.user import RecentAuthenticationRequiredMixin
|
||||||
from pretix.helpers.database import rolledback_transaction
|
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.plugins.stripe.payment import StripeSettingsHolder
|
||||||
from pretix.presale.style import regenerate_css
|
from pretix.presale.style import regenerate_css
|
||||||
|
|
||||||
@@ -1504,3 +1507,35 @@ class QuickSetupView(FormView):
|
|||||||
},
|
},
|
||||||
] if self.request.method != "POST" else []
|
] 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
|
||||||
|
|||||||
@@ -139,12 +139,18 @@ p.bigger {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.helper-position-relative {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
.helper-display-block {
|
.helper-display-block {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
.helper-display-inline {
|
.helper-display-inline {
|
||||||
display: inline !important;
|
display: inline !important;
|
||||||
}
|
}
|
||||||
|
.helper-display-inline-block {
|
||||||
|
display: inline-block !important;
|
||||||
|
}
|
||||||
.helper-display-none-soft {
|
.helper-display-none-soft {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ setup(
|
|||||||
'python-u2flib-server==4.*',
|
'python-u2flib-server==4.*',
|
||||||
'pytz',
|
'pytz',
|
||||||
'pyuca',
|
'pyuca',
|
||||||
|
'qrcode==7.4.*',
|
||||||
'redis==4.5.*,>=4.5.4',
|
'redis==4.5.*,>=4.5.4',
|
||||||
'reportlab==3.6.*',
|
'reportlab==3.6.*',
|
||||||
'requests==2.28.*',
|
'requests==2.28.*',
|
||||||
|
|||||||
@@ -142,6 +142,10 @@ def logged_in_client(client, event):
|
|||||||
('/control/events/add', 200),
|
('/control/events/add', 200),
|
||||||
|
|
||||||
('/control/event/{orga}/{event}/', 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}/live/', 200),
|
||||||
('/control/event/{orga}/{event}/dangerzone/', 200),
|
('/control/event/{orga}/{event}/dangerzone/', 200),
|
||||||
('/control/event/{orga}/{event}/cancel/', 200),
|
('/control/event/{orga}/{event}/cancel/', 200),
|
||||||
|
|||||||
Reference in New Issue
Block a user