Skip to content

Commit

Permalink
Remove Event QR feature (fossasia#403)
Browse files Browse the repository at this point in the history
* remove event qr feature

---------

Co-authored-by: odkhang <odkhang>
  • Loading branch information
lcduong authored Oct 18, 2024
1 parent caae02b commit 34e66f1
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 289 deletions.
4 changes: 2 additions & 2 deletions src/pretix/base/forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ def run_validators(self, value):
class I18nMarkdownTextarea(i18nfield.forms.I18nTextarea):
def format_output(self, rendered_widgets) -> str:
markdown_note = _(
"You can use {markup_name} in this field."
).format(markup_name='<a href="https://en.wikipedia.org/wiki/Markdown" target="_blank">Markdown</a>')
"You can use {name} in this field."
).format(name='<a href="https://en.wikipedia.org/wiki/Markdown" target="_blank">Markdown</a>')
rendered_widgets.append(f'<div class="i18n-field-markdown-note">{markdown_note}</div>')
return super().format_output(rendered_widgets)

Expand Down

This file was deleted.

This file was deleted.

120 changes: 57 additions & 63 deletions src/pretix/control/templates/pretixcontrol/event/plugins.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@
{% load static %}
{% load bootstrap3 %}
{% block inside %}
<h1>{% trans "Available plugins" %}</h1>
<p>
{% blocktrans trimmed %}
On this page, you can select the plugins you would like to enable for your event. Plugins can add extra functionality,
integrate third-party services, or provide various customization options to enhance your event experience.
{% endblocktrans %}
</p>
<h1>{% trans "Installed plugins" %}</h1>
<form action="" method="post" class="form-horizontal form-plugins">
{% csrf_token %}
{% if "success" in request.GET %}
Expand All @@ -18,71 +12,71 @@ <h1>{% trans "Available plugins" %}</h1>
</div>
{% endif %}
<div class="tabbed-form">
{% for cat, catlabel, plist, has_pictures in plugins %}
{% for cat, catlabel, plist in plugins %}
<fieldset>
<legend>{{ catlabel }}</legend>
<div class="plugin-list">
{% for plugin in plist %}
<div class="plugin-container {% if plugin.featured %}featured-plugin{% endif %}">
{% if plugin.featured %}
<div class="panel panel-default">
<div class="panel-body">
{% endif %}
<div class="plugin-text">
{% if plugin.featured or plugin.experimental %}
<p class="text-muted">
{% if plugin.featured %}
<span class="fa fa-thumbs-up" aria-hidden="true"></span>
{% trans "Top recommendation" %}
{% endif %}
{% if plugin.experimental %}
<span class="fa fa-flask" aria-hidden="true"></span>
{% trans "Experimental feature" %}
{% endif %}
</p>
<div class="table-responsive">
<table class="table">
{% for plugin in plist %}
<tr class="{% if plugin.app.compatibility_errors %}warning{% elif plugin.module in plugins_active %}success{% else %}default{% endif %}">
<td>
<strong>{{ plugin.name }}</strong>
{% if plugin.author %}
<p class="meta text-muted">
{% blocktrans trimmed with v=plugin.version a=plugin.author %}
Version {{ v }} by <em>{{ a }}</em>
{% endblocktrans %}</p>
{% else %}
<p class="meta text-muted">
{% blocktrans trimmed with v=plugin.version a=plugin.author %}
Version {{ v }}
{% endblocktrans %}</p>
{% endif %}
{% if plugin.picture %}
<p><img src="{% static plugin.picture %}" class="plugin-picture"></p>
<p>{{ plugin.description }}</p>
{% if plugin.restricted and not request.user.is_staff %}
<span class="text-muted">
{% trans "This plugin needs to be enabled by a system administrator for your event." %}
</span>
{% endif %}
<h4>
{{ plugin.name }}
{% if show_meta %}
<span class="text-muted text-sm">{{ plugin.version }}</span>
{% endif %}
{% if plugin.module in plugins_active %}
<span class="label label-success">
<span class="fa fa-check" aria-hidden="true"></span>
{% trans "Active" %}
</span>
{% endif %}
</h4>
{% include "pretixcontrol/event/fragment_plugin_description.html" with plugin=plugin %}
</div>
{% if plugin.app.compatibility_errors %}
<div class="plugin-action">
<span class="text-muted">{% trans "Incompatible" %}</span>
</div>
{% elif plugin.restricted and plugin.module not in request.event.settings.allowed_restricted_plugins %}
<div class="plugin-action">
<span class="text-muted">{% trans "Not available" %}</span>
<div class="alert alert-warning">
{% trans "This plugin cannot be enabled for the following reasons:" %}
<ul>
{% for e in plugin.app.compatibility_errors %}
<li>{{ e }}</li>
{% endfor %}
</ul>
</div>
{% elif plugin.module in plugins_active %}
<div class="plugin-action flip">
<button class="btn btn-default{% if plugin.featured %} btn-lg{% endif %}" name="plugin:{{ plugin.module }}"
value="disable">{% trans "Disable" %}</button>
{% endif %}
{% if plugin.app.compatibility_warnings %}
<div class="alert alert-warning">
{% trans "This plugin reports the following problems:" %}
<ul>
{% for e in plugin.app.compatibility_warnings %}
<li>{{ e }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
</td>
<td class="text-right flip" width="20%">
{% if plugin.app.compatibility_errors %}
<button class="btn disabled btn-block btn-default"
disabled="disabled">{% trans "Incompatible" %}</button>
{% elif plugin.restricted and not staff_session %}
<button class="btn disabled btn-block btn-default"
disabled="disabled">{% trans "Not available" %}</button>
{% elif plugin.module in plugins_active %}
<button class="btn btn-default btn-block" name="plugin:{{ plugin.module }}"
value="disable">{% trans "Disable" %}</button>
{% else %}
<div class="plugin-action flip">
<button class="btn btn-primary{% if plugin.featured %} btn-lg{% endif %}" name="plugin:{{ plugin.module }}"
value="enable">{% trans "Enable" %}</button>
</div>
<button class="btn btn-default btn-block" name="plugin:{{ plugin.module }}"
value="enable">{% trans "Enable" %}</button>
{% endif %}
{% if plugin.featured %}
</div>
</div>
{% endif %}
</div>
{% endfor %}
</td>
</tr>
{% endfor %}
</table>
</div>
</fieldset>
{% endfor %}
Expand Down
1 change: 0 additions & 1 deletion src/pretix/control/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@
url(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
url(r'^$', dashboards.event_index, name='event.index'),
url(r'^widgets.json$', dashboards.event_index_widgets_lazy, name='event.index.widgets'),
url(r'^qrcode.(?P<filetype>(png|jpeg|gif|svg))$', event.EventQRCode.as_view(), name='event.qrcode'),
url(r'^live/$', event.EventLive.as_view(), name='event.live'),
url(r'^logs/$', event.EventLog.as_view(), name='event.log'),
url(r'^delete/$', event.EventDelete.as_view(), name='event.delete'),
Expand Down
111 changes: 7 additions & 104 deletions src/pretix/control/views/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@
import re
from collections import OrderedDict
from decimal import Decimal
from io import BytesIO
from itertools import groupby
from urllib.parse import urlparse, urlsplit
from urllib.parse import urlsplit

import qrcode
import qrcode.image.svg
from django.conf import settings
from django.contrib import messages
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.core.files import File
from django.db import transaction
from django.db.models import ProtectedError
Expand All @@ -23,7 +19,6 @@
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.timezone import now
from django.utils.translation import gettext, gettext_lazy as _
from django.views.generic import DeleteView, FormView, ListView
Expand Down Expand Up @@ -55,7 +50,7 @@
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.control.views.user import RecentAuthenticationRequiredMixin
from pretix.helpers.database import rolledback_transaction
from pretix.multidomain.urlreverse import build_absolute_uri, get_event_domain
from pretix.multidomain.urlreverse import get_event_domain
from pretix.presale.style import regenerate_css

from ...base.i18n import language
Expand Down Expand Up @@ -311,25 +306,15 @@ def get_context_data(self, *args, **kwargs) -> dict:
'FORMAT': _('Output and export formats'),
'API': _('API features'),
}
plugins_grouped = groupby(
sorted(
plugins,
key=lambda p: (
str(getattr(p, 'category', _('Other'))),
(0 if getattr(p, 'featured', False) else 1),
str(p.name).lower().replace('pretix ', '')
),
),
lambda p: str(getattr(p, 'category', _('Other')))
)
plugins_grouped = [(c, list(plist)) for c, plist in plugins_grouped]
context['plugins'] = sorted([
(c, labels.get(c, c), plist, any(getattr(p, 'picture', None) for p in plist))
(c, labels.get(c, c), list(plist))
for c, plist
in plugins_grouped
in groupby(
sorted(plugins, key=lambda p: str(getattr(p, 'category', _('Other')))),
lambda p: str(getattr(p, 'category', _('Other')))
)
], key=lambda c: (order.index(c[0]), c[1]) if c[0] in order else (999, str(c[1])))
context['plugins_active'] = self.object.get_plugins()
context['show_meta'] = settings.PRETIX_PLUGINS_SHOW_META
return context

def get(self, request, *args, **kwargs):
Expand Down Expand Up @@ -1461,85 +1446,3 @@ def formset(self):
},
] if self.request.method != "POST" else []
)


class EventQRCode(EventPermissionRequiredMixin, View):
"""
Access the view to generate QR codes for event URLs. This class requires specific permissions for each event and
can produce QR codes in multiple formats (e.g. SVG, JPEG, PNG, GIF).
Attributes:
permission (str): Required permissions for accessing this view.
"""
permission = None

def get(self, request, *args, filetype, **kwargs):
"""
Handle GET requests to generate a QR code.
"""
# Build the base URL for the event
url = build_absolute_uri(request.event, 'presale:event.index')

# Check if a custom URL is provided and validate it
custom_url = request.GET.get("url")
if custom_url:
if url_has_allowed_host_and_scheme(custom_url, allowed_hosts=[urlparse(url).netloc]):
url = custom_url
else:
raise PermissionDenied("Untrusted URL")

# Create a QRCode object
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)

# Generate the QR code in the specified format
if filetype == 'svg':
return self._generate_svg_response(qr, request.event.slug, filetype)
elif filetype in ('jpeg', 'png', 'gif'):
return self._generate_image_response(qr, request.event.slug, filetype)
else:
raise ValueError(f"Unsupported file type: {filetype}")

def _generate_svg_response(self, qr, event_slug, filetype):
"""
Generate an SVG response for the QR code.
Parameters:
qr (QRCode): The QRCode object.
event_slug (str): The slug for the event to be included in the filename.
filetype (str): The desired file type (must be 'svg').
Returns:
The HTTP response that contains the SVG QR code.
"""
factory = qrcode.image.svg.SvgPathImage
img = qr.make_image(image_factory=factory)
response = HttpResponse(img.to_string(), content_type='image/svg+xml')
response['Content-Disposition'] = f'inline; filename="qrcode-{event_slug}.{filetype}"'
return response

def _generate_image_response(self, qr, event_slug, filetype):
"""
Generate an image response (JPEG, PNG, GIF) for the QR code.
Parameters:
qr (QRCode): The QRCode object.
event_slug (str): The event slug to be used in the filename.
filetype (str): The file type (jpeg, png, gif).
Returns:
HttpResponse: An HTTP response containing the image QR code.
"""
img = qr.make_image(fill_color="black", back_color="white")
byte_io = BytesIO()
img.save(byte_io, filetype.upper())
byte_io.seek(0)
response = HttpResponse(byte_io.read(), content_type=f'image/{filetype}')
response['Content-Disposition'] = f'inline; filename="qrcode-{event_slug}.{filetype}"'
return response
Loading

0 comments on commit 34e66f1

Please sign in to comment.