This commit is contained in:
Kara Engelhardt
2026-03-20 12:46:48 +01:00
parent cfcd0f4206
commit a521956aca
7 changed files with 179 additions and 79 deletions

View File

@@ -4,7 +4,23 @@ import enum
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from i18nfield.strings import LazyI18nString
from .models import WalletLayout
class WalletPlatform:
identifier: str
name: str
def get_layout_qs(self):
return WalletLayout.objects.filter(platform=self.identifier)
class ApplePlatform(WalletPlatform):
identifier = "apple"
name = _("Apple")
class GooglePlatform(WalletPlatform):
identifier = "apple"
name = _("Google")
class PlaceholderFieldType(enum.Enum):
TEXT = "text"
CODE = "qr"
@@ -108,6 +124,7 @@ class GoogleWalletEventTicket(PassStyle):
]
AVAILABLE_PLATFORMS = {"apple": ApplePlatform, "google": GooglePlatform}
AVAILABLE_STYLES = [AppleWalletEventTicket(), GoogleWalletEventTicket()]
def get_platforms_with_styles():
@@ -127,7 +144,7 @@ def get_platform_styles(platform):
return platform_styles
def get_platforms():
return sorted(set(style.platform for style in AVAILABLE_STYLES))
return AVAILABLE_PLATFORMS
class PassLayout:
style: PassStyle

View File

@@ -1,6 +1,8 @@
{% extends "pretixcontrol/event/base.html" %}
{% load i18n %}
{% load money %}
{% load bootstrap3 %}
{% block title %}{% trans "Wallet layouts" %}{% endblock %}
{% block content %}
<pre><code>{{ styles }}</code></pre>
@@ -9,7 +11,7 @@
{{ variables|json_script:"variables" }}
<form method="post">
{% csrf_token %}
{{form}}
{% bootstrap_form form %}
<button type="submit" class="btn btn-default">
{% trans "Submit " %}
</button>

View File

@@ -5,62 +5,76 @@
{% block content %}
<h1>{% trans "Wallet layouts" %}</h1>
<div class="tabbed-form">
{% for platform in platforms %}
{% for platform in platforms.values %}
<fieldset>
<legend>{{platform}}</legend>
<legend>{{platform.name}}</legend>
{% if platforms.get_layout_qs|length == 0 %}
<div class="empty-collection">
<p>
{% blocktrans trimmed %}
You haven't created any layouts yet.
{% endblocktrans %}
</p>
{% if "event.settings.general:write" in request.eventpermset %}
<a href="{% url "plugins:wallet:add" organizer=request.event.organizer.slug event=request.event.slug platform=platform.identifier %}"
class="btn btn-primary btn-lg"><i class="fa fa-plus"></i> {% trans "Create a new layout" %}
</a>
{% endif %}
</div>
{% else %}
<div class="table-responsive">
<table class="table table-hover table-quotas">
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Default" %}</th>
<th class="action-col-2"></th>
</tr>
</thead>
<tbody>
{% for l in platforms.get_layout_qs %}
<tr>
<td>
{% if "can_change_event_settings" in request.eventpermset %}
<strong><a href="{% url "plugins:ticketoutputpdf:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
{{ l.name }}
</a></strong>
{% else %}
<strong>{{ l.name }}</strong>
{% endif %}
</td>
<td>
{% if l.default %}
<span class="text-success">
<span class="fa fa-check"></span>
{% trans "Default" %}
</span>
{% elif "can_change_event_settings" in request.eventpermset %}
<form class="form-inline" method="post"
action="{% url "plugins:ticketoutputpdf:default" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
{% csrf_token %}
<button class="btn btn-default btn-sm">
{% trans "Make default" %}
</button>
</form>
{% endif %}
</td>
<td class="text-right flip">
{% if "can_change_event_settings" in request.eventpermset %}
<a href="{% url "plugins:ticketoutputpdf:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
<a href="{% url "plugins:ticketoutputpdf:add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ l.id }}"
class="btn btn-default btn-sm" title="{% trans "Clone" %}" data-toggle="tooltip"><i class="fa fa-copy"></i></a>
<a href="{% url "plugins:ticketoutputpdf:delete" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</fieldset>
{% endfor %}
</div>
{% comment %} <div class="table-responsive">
<table class="table table-hover table-quotas">
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Default" %}</th>
<th class="action-col-2"></th>
</tr>
</thead>
<tbody>
{% for l in layouts %}
<tr>
<td>
{% if "can_change_event_settings" in request.eventpermset %}
<strong><a href="{% url "plugins:ticketoutputpdf:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
{{ l.name }}
</a></strong>
{% else %}
<strong>{{ l.name }}</strong>
{% endif %}
</td>
<td>
{% if l.default %}
<span class="text-success">
<span class="fa fa-check"></span>
{% trans "Default" %}
</span>
{% elif "can_change_event_settings" in request.eventpermset %}
<form class="form-inline" method="post"
action="{% url "plugins:ticketoutputpdf:default" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
{% csrf_token %}
<button class="btn btn-default btn-sm">
{% trans "Make default" %}
</button>
</form>
{% endif %}
</td>
<td class="text-right flip">
{% if "can_change_event_settings" in request.eventpermset %}
<a href="{% url "plugins:ticketoutputpdf:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
<a href="{% url "plugins:ticketoutputpdf:add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ l.id }}"
class="btn btn-default btn-sm" title="{% trans "Clone" %}" data-toggle="tooltip"><i class="fa fa-copy"></i></a>
<a href="{% url "plugins:ticketoutputpdf:delete" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endcomment %}
{% include "pretixcontrol/pagination.html" %}
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% load i18n %}
<p>
<a class="btn btn-primary btn-lg" target="_blank"
href="{% url "plugins:wallet:index" organizer=request.organizer.slug event=request.event.slug %}">
<span class="fa fa-paint-brush"></span>
{% trans "Edit layouts" %}
</a>
</p>

View File

@@ -24,34 +24,48 @@ from django.utils.translation import gettext_lazy as _
from pretix.base.ticketoutput import BaseTicketOutput
from pretix.base.models import Event
from pretix.base.settings import SettingsSandbox
from django.template.loader import render_to_string
logger = logging.getLogger('pretix.plugins.wallet')
logger = logging.getLogger("pretix.plugins.wallet")
class WalletSettingsHolder(BaseTicketOutput):
identifier = 'wallet'
verbose_name = _('Wallet Output')
identifier = "wallet"
verbose_name = _("Wallet Output")
is_meta = True
is_enabled = False
preview_allowed = False # TODO: implement own preview view or hide button for meta-outputs
preview_allowed = (
False # TODO: implement own preview view or hide button for meta-outputs
)
def settings_content_render(self, request) -> str:
return render_to_string(
"pretixplugins/wallet/settings_content.html", {"request": request}
)
class WalletOutput(BaseTicketOutput):
settings_form_fields = []
def __init__(self, event: Event):
super().__init__(event)
self.settings = SettingsSandbox('ticketoutput', WalletSettingsHolder.identifier, event)
self.settings = SettingsSandbox(
"ticketoutput", WalletSettingsHolder.identifier, event
)
class GoogleWalletTicketOutput(WalletOutput):
identifier = 'wallet_google'
verbose_name = _('Google')
identifier = "wallet_google"
verbose_name = _("Google")
download_button_text = "Add to Google Wallet"
class AppleWalletTicketOutput(WalletOutput):
identifier = 'wallet_apple'
verbose_name = _('Apple')
identifier = "wallet_apple"
verbose_name = _("Apple")
download_button_text = "Add to Apple Wallet"
OUTPUTS = [WalletSettingsHolder, GoogleWalletTicketOutput, AppleWalletTicketOutput]

View File

@@ -22,7 +22,8 @@
from django.urls import re_path
from .views import (
EditorView,
LayoutEditorView,
LayoutCreateView,
LayoutListView
)
@@ -30,7 +31,7 @@ urlpatterns = [
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/wallet/$',
LayoutListView.as_view(), name='index'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/wallet/edit/(?P<platform>[^/]+)/$',
EditorView.as_view(), name='edit'),
LayoutCreateView.as_view(), name='add'),
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/wallet/edit/(?P<platform>[^/]+)/(?P<layout>[^/]+)/$',
EditorView.as_view(), name='edit'),
LayoutEditorView.as_view(), name='edit'),
]

View File

@@ -3,7 +3,7 @@ from typing import Any
from django.http import Http404
from django.shortcuts import redirect
from django.urls import reverse
from django.views.generic import FormView, ListView, TemplateView
from django.views.generic import FormView, ListView, CreateView, UpdateView
from pretix.base.pdf import get_variables
from pretix.control.permissions import EventPermissionRequiredMixin
from .styles import PassLayout, get_platform_styles, get_platforms
@@ -12,8 +12,10 @@ import json
from django.utils.translation import gettext_lazy as _
from django import forms
from django.core.exceptions import ValidationError
from i18nfield.fields import I18nCharField
from i18nfield.forms import I18nModelForm
# TODO: should this even be a list view?
class LayoutListView(EventPermissionRequiredMixin, ListView):
model = WalletLayout
permission = "can_change_event_settings"
@@ -29,11 +31,19 @@ class LayoutListView(EventPermissionRequiredMixin, ListView):
return ctx
class EditorForm(forms.Form):
name = forms.CharField()
class LayoutEditForm(forms.ModelForm):
style = forms.TypedChoiceField()
layout = forms.JSONField(initial={})
def __init__(self, **kwargs):
self.platform = kwargs.pop('platform')
super().__init__(**kwargs)
class Meta:
model = WalletLayout
fields = ("name","style","layout")
def __init__(self, platform, **kwargs):
super().__init__(**kwargs)
self.platform = platform
@@ -60,13 +70,12 @@ class EditorForm(forms.Form):
)
layout.validate()
return self.cleaned_data
class EditorView(EventPermissionRequiredMixin, FormView):
class LayoutCreateView(EventPermissionRequiredMixin, FormView):
template_name = "pretixplugins/wallet/edit.html"
form_class = EditorForm
success_url = ""
permission = "can_change_event_settings"
form_class = LayoutEditForm
model = WalletLayout
permission = "can_change_event_settings" # TODO: new permission name
@property
def platform(self):
@@ -116,3 +125,38 @@ class EditorView(EventPermissionRequiredMixin, FormView):
},
)
)
class LayoutEditorView(EventPermissionRequiredMixin, UpdateView):
template_name = "pretixplugins/wallet/edit.html"
form_class = LayoutEditForm
success_url = ""
permission = "can_change_event_settings"
@property
def platform(self):
return self.kwargs["platform"]
def get_form_kwargs(self) -> dict[str, Any]:
kwargs = super().get_form_kwargs()
kwargs["platform"] = self.platform
return kwargs
def get_platform_styles(self):
if self.platform not in get_platforms():
raise Http404(
_("Unknown platform '{platform}'").format(platform=self.platform)
)
return get_platform_styles(self.platform)
def get_context_data(self, **kwargs) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
context["styles"] = {
id: style.asdict() for id, style in self.get_platform_styles().items()
}
context["variables"] = {
"text": {
varname: {"label": var["label"], "editor_sample": var["editor_sample"]}
for varname, var in get_variables(self.request.event).items()
}
}
return context