mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Allow to set multiple confirm texts (#1735)
This commit is contained in:
@@ -565,7 +565,7 @@ class EventSettingsSerializer(serializers.Serializer):
|
||||
'attendee_addresses_required',
|
||||
'attendee_company_asked',
|
||||
'attendee_company_required',
|
||||
'confirm_text',
|
||||
'confirm_texts',
|
||||
'order_email_asked_twice',
|
||||
'payment_term_days',
|
||||
'payment_term_last',
|
||||
|
||||
27
src/pretix/base/migrations/0160_multiple_confirm_texts.py
Normal file
27
src/pretix/base/migrations/0160_multiple_confirm_texts.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 3.0.8 on 2020-07-31 10:05
|
||||
|
||||
import json
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def migrate_confirm_text(apps, schema_editor):
|
||||
# We now allow creating multiple confirm texts so we migrate the setting for that
|
||||
# from `confirm_text` to `confirm_texts`
|
||||
Event_SettingsStore = apps.get_model('pretixbase', 'Event_SettingsStore')
|
||||
for store in Event_SettingsStore.objects.filter(key="confirm_text"):
|
||||
values = json.dumps([json.loads(store.value)]) # convert single value to one-element list
|
||||
store.key = "confirm_texts"
|
||||
store.value = values
|
||||
store.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0159_mails_by_sales_channel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_confirm_text, migrations.RunPython.noop),
|
||||
]
|
||||
@@ -35,7 +35,7 @@ class RelativeDateWrapper:
|
||||
def __init__(self, data: Union[datetime.datetime, RelativeDate]):
|
||||
self.data = data
|
||||
|
||||
def date(self, event) -> datetime.datetime:
|
||||
def date(self, event) -> datetime.date:
|
||||
from .models import SubEvent
|
||||
|
||||
if isinstance(self.data, datetime.date):
|
||||
@@ -81,8 +81,8 @@ class RelativeDateWrapper:
|
||||
second=self.data.time.second
|
||||
)
|
||||
new_date = new_date.astimezone(tz)
|
||||
newoffset = new_date.utcoffset()
|
||||
new_date += oldoffset - newoffset
|
||||
new_offset = new_date.utcoffset()
|
||||
new_date += oldoffset - new_offset
|
||||
return new_date
|
||||
|
||||
def to_string(self) -> str:
|
||||
|
||||
@@ -27,7 +27,7 @@ from pretix.base.services.locking import LockTimeoutException, NoLockManager
|
||||
from pretix.base.services.pricing import get_price
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.base.services.tasks import ProfiledEventTask
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES, LazyI18nStringList
|
||||
from pretix.base.signals import validate_cart_addons
|
||||
from pretix.base.templatetags.rich_text import rich_text
|
||||
from pretix.celery_app import app
|
||||
@@ -1240,9 +1240,7 @@ def set_cart_addons(self, event: Event, addons: List[dict], cart_id: str=None, l
|
||||
|
||||
@receiver(checkout_confirm_messages, dispatch_uid="cart_confirm_messages")
|
||||
def confirm_messages(sender, *args, **kwargs):
|
||||
if not sender.settings.confirm_text:
|
||||
if not sender.settings.confirm_texts:
|
||||
return {}
|
||||
|
||||
return {
|
||||
'confirm_text': rich_text(str(sender.settings.confirm_text))
|
||||
}
|
||||
confirm_texts = sender.settings.get("confirm_texts", as_type=LazyI18nStringList)
|
||||
return {'confirm_text_%i' % index: rich_text(str(text)) for index, text in enumerate(confirm_texts)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
import operator
|
||||
from collections import OrderedDict, UserList
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
@@ -37,6 +38,20 @@ def country_choice_kwargs():
|
||||
}
|
||||
|
||||
|
||||
class LazyI18nStringList(UserList):
|
||||
def __init__(self, init_list=None):
|
||||
super().__init__()
|
||||
if init_list is not None:
|
||||
self.data = [v if isinstance(v, LazyI18nString) else LazyI18nString(v) for v in init_list]
|
||||
|
||||
def serialize(self):
|
||||
return json.dumps([s.data for s in self.data])
|
||||
|
||||
@classmethod
|
||||
def unserialize(cls, s):
|
||||
return cls(json.loads(s))
|
||||
|
||||
|
||||
DEFAULTS = {
|
||||
'max_items_per_order': {
|
||||
'default': '10',
|
||||
@@ -1127,18 +1142,11 @@ DEFAULTS = {
|
||||
),
|
||||
'serializer_class': serializers.URLField,
|
||||
},
|
||||
'confirm_text': {
|
||||
'default': None,
|
||||
'type': LazyI18nString,
|
||||
'form_class': I18nFormField,
|
||||
'serializer_class': I18nField,
|
||||
'form_kwargs': dict(
|
||||
label=_('Confirmation text'),
|
||||
help_text=_('This text needs to be confirmed by the user before a purchase is possible. You could for example '
|
||||
'link your terms of service here. If you use the Pages feature to publish your terms of service, '
|
||||
'you don\'t need this setting since you can configure it there.'),
|
||||
widget=I18nTextarea,
|
||||
)
|
||||
'confirm_texts': {
|
||||
'default': LazyI18nStringList(),
|
||||
'type': LazyI18nStringList,
|
||||
'serializer_class': serializers.ListField,
|
||||
'serializer_kwargs': lambda: dict(child=I18nField()),
|
||||
},
|
||||
'mail_html_renderer': {
|
||||
'default': 'classic',
|
||||
@@ -1939,6 +1947,9 @@ def i18n_uns(v):
|
||||
settings_hierarkey.add_type(LazyI18nString,
|
||||
serialize=lambda s: json.dumps(s.data),
|
||||
unserialize=i18n_uns)
|
||||
settings_hierarkey.add_type(LazyI18nStringList,
|
||||
serialize=operator.methodcaller("serialize"),
|
||||
unserialize=LazyI18nStringList.unserialize)
|
||||
settings_hierarkey.add_type(RelativeDateWrapper,
|
||||
serialize=lambda rdw: rdw.to_string(),
|
||||
unserialize=lambda s: RelativeDateWrapper.from_string(s))
|
||||
|
||||
@@ -518,7 +518,6 @@ class EventSettingsForm(SettingsForm):
|
||||
'attendee_company_required',
|
||||
'attendee_addresses_asked',
|
||||
'attendee_addresses_required',
|
||||
'confirm_text',
|
||||
'banner_text',
|
||||
'banner_text_bottom',
|
||||
'order_email_asked_twice',
|
||||
@@ -535,11 +534,6 @@ class EventSettingsForm(SettingsForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs['obj']
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['confirm_text'].widget.attrs['rows'] = '3'
|
||||
self.fields['confirm_text'].widget.attrs['placeholder'] = _(
|
||||
'e.g. I hereby confirm that I have read and agree with the event organizer\'s terms of service '
|
||||
'and agree with them.'
|
||||
)
|
||||
self.fields['name_scheme'].choices = (
|
||||
(k, _('Ask for {fields}, display like {example}').format(
|
||||
fields=' + '.join(str(vv[1]) for vv in v['fields']),
|
||||
@@ -1342,3 +1336,25 @@ class ItemMetaPropertyForm(forms.ModelForm):
|
||||
widgets = {
|
||||
'default': forms.TextInput()
|
||||
}
|
||||
|
||||
|
||||
class ConfirmTextForm(I18nForm):
|
||||
text = I18nFormField(
|
||||
widget=I18nTextarea,
|
||||
widget_kwargs={'attrs': {'rows': '2'}},
|
||||
)
|
||||
|
||||
|
||||
class BaseConfirmTextFormSet(I18nFormSetMixin, forms.BaseFormSet):
|
||||
def __init__(self, *args, **kwargs):
|
||||
event = kwargs.pop('event', None)
|
||||
if event:
|
||||
kwargs['locales'] = event.settings.get('locales')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
ConfirmTextFormset = formset_factory(
|
||||
ConfirmTextForm,
|
||||
formset=BaseConfirmTextFormSet,
|
||||
can_order=True, can_delete=True, extra=0
|
||||
)
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
{% bootstrap_field form.date_to layout="control" %}
|
||||
<div class="geodata-section">
|
||||
{% bootstrap_field form.location layout="control" %}
|
||||
<div class="form-group geodata-group" data-tiles="{{ global_settings.leaflet_tiles|default_if_none:"" }}" data-attrib="{{ global_settings.leaflet_tiles_attribution }}" data-icon="{% static "leaflet/images/marker-icon.png" %}" data-shadow="{% static "leaflet/images/marker-shadow.png" %}">
|
||||
<div class="form-group geodata-group"
|
||||
data-tiles="{{ global_settings.leaflet_tiles|default_if_none:"" }}"
|
||||
data-attrib="{{ global_settings.leaflet_tiles_attribution }}"
|
||||
data-icon="{% static "leaflet/images/marker-icon.png" %}"
|
||||
data-shadow="{% static "leaflet/images/marker-shadow.png" %}">
|
||||
<label class="col-md-3 control-label">
|
||||
{% trans "Geo coordinates" %}<br>
|
||||
<span class="optional">{% trans "Optional" %}</span>
|
||||
@@ -99,7 +103,77 @@
|
||||
{% bootstrap_field sform.frontpage_text layout="control" %}
|
||||
{% bootstrap_field sform.presale_has_ended_text layout="control" %}
|
||||
{% bootstrap_field sform.voucher_explanation_text layout="control" %}
|
||||
{% bootstrap_field sform.confirm_text layout="control" %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">
|
||||
{% trans "Confirmation text" %}<br>
|
||||
<span class="optional">{% trans "Optional" %}</span>
|
||||
</label>
|
||||
<div class="col-md-9">
|
||||
<div class="help-block">
|
||||
{% blocktrans trimmed %}
|
||||
These texts need to be confirmed by the user before a purchase is possible. You could
|
||||
for example link your terms of service here. If you use the Pages feature to publish
|
||||
your terms of service, you don't need this setting since you can configure it there.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
<div class="formset" data-formset data-formset-prefix="{{ confirm_texts_formset.prefix }}">
|
||||
{{ confirm_texts_formset.management_form }}
|
||||
{% bootstrap_formset_errors confirm_texts_formset %}
|
||||
<div data-formset-body>
|
||||
{% for form in confirm_texts_formset %}
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ form.id }}
|
||||
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field form.ORDER form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
{% bootstrap_form_errors form %}
|
||||
{% bootstrap_field form.text layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-2 text-right flip">
|
||||
<button type="button" class="btn" data-formset-move-up-button>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn" data-formset-move-down-button>
|
||||
<i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ confirm_texts_formset.empty_form.id }}
|
||||
{% bootstrap_field confirm_texts_formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field confirm_texts_formset.empty_form.ORDER form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
{% bootstrap_field confirm_texts_formset.empty_form.text layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-2 text-right flip">
|
||||
|
||||
<button type="button" class="btn" data-formset-move-up-button>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn" data-formset-move-down-button>
|
||||
<i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
<p>
|
||||
<button type="button" class="btn btn-default" data-formset-add>
|
||||
<i class="fa fa-plus"></i> {% trans "Add confirmation text" %}</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% bootstrap_field sform.checkout_email_helptext layout="control" %}
|
||||
{% bootstrap_field sform.banner_text layout="control" %}
|
||||
{% bootstrap_field sform.banner_text_bottom layout="control" %}
|
||||
@@ -161,17 +235,18 @@
|
||||
<legend>{% trans "Item metadata" %}</legend>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
You can here define a set of metadata properties (i.e. variables) that you can later set for your
|
||||
items and re-use in places like ticket layouts. This is an useful timesaver if you create lots and
|
||||
lots of items.
|
||||
You can here define a set of metadata properties (i.e. variables) that you can later set for
|
||||
your items and re-use in places like ticket layouts. This is an useful timesaver if you create
|
||||
lots and lots of items.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<div class="formset" data-formset data-formset-prefix="{{ formset.prefix }}">
|
||||
{{ formset.management_form }}
|
||||
{% bootstrap_formset_errors formset %}
|
||||
<div class="formset" data-formset
|
||||
data-formset-prefix="{{ item_meta_property_formset.prefix }}">
|
||||
{{ item_meta_property_formset.management_form }}
|
||||
{% bootstrap_formset_errors item_meta_property_formset %}
|
||||
<div data-formset-body>
|
||||
{% for form in formset %}
|
||||
<div class="row" data-formset-form>
|
||||
{% for form in item_meta_property_formset %}
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ form.id }}
|
||||
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
|
||||
@@ -192,16 +267,16 @@
|
||||
</div>
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="row" data-formset-form>
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ formset.empty_form.id }}
|
||||
{% bootstrap_field formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
{{ item_meta_property_formset.empty_form.id }}
|
||||
{% bootstrap_field item_meta_property_formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field formset.empty_form.name layout='inline' form_group_class="" %}
|
||||
{% bootstrap_field item_meta_property_formset.empty_form.name layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-5 col-lg-6">
|
||||
{% bootstrap_field formset.empty_form.default layout='inline' form_group_class="" %}
|
||||
{% bootstrap_field item_meta_property_formset.empty_form.default layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-2 col-lg-1 text-right flip">
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
@@ -223,12 +298,12 @@
|
||||
</button>
|
||||
<div class="pull-left">
|
||||
<a href="{% url "control:event.dangerzone" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-danger btn-lg">
|
||||
class="btn btn-danger btn-lg">
|
||||
<span class="fa fa-trash"></span>
|
||||
{% trans "Cancel or delete event" %}
|
||||
</a>
|
||||
<a href="{% url "control:events.add" %}?clone={{ request.event.pk }}"
|
||||
class="btn btn-default btn-lg">
|
||||
class="btn btn-default btn-lg">
|
||||
<span class="fa fa-copy"></span>
|
||||
{% trans "Clone event" %}
|
||||
</a>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
import operator
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
@@ -40,10 +41,11 @@ from pretix.base.services.invoices import build_preview_invoice_pdf
|
||||
from pretix.base.signals import register_ticket_outputs
|
||||
from pretix.base.templatetags.rich_text import markdown_compile_email
|
||||
from pretix.control.forms.event import (
|
||||
CancelSettingsForm, CommentForm, EventDeleteForm, EventMetaValueForm,
|
||||
EventSettingsForm, EventUpdateForm, InvoiceSettingsForm,
|
||||
ItemMetaPropertyForm, MailSettingsForm, PaymentSettingsForm, ProviderForm,
|
||||
QuickSetupForm, QuickSetupProductFormSet, TaxRuleForm, TaxRuleLineFormSet,
|
||||
CancelSettingsForm, CommentForm, ConfirmTextFormset, EventDeleteForm,
|
||||
EventMetaValueForm, EventSettingsForm, EventUpdateForm,
|
||||
InvoiceSettingsForm, ItemMetaPropertyForm, MailSettingsForm,
|
||||
PaymentSettingsForm, ProviderForm, QuickSetupForm,
|
||||
QuickSetupProductFormSet, TaxRuleForm, TaxRuleLineFormSet,
|
||||
TicketSettingsForm, WidgetCodeForm,
|
||||
)
|
||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||
@@ -54,6 +56,7 @@ from pretix.plugins.stripe.payment import StripeSettingsHolder
|
||||
from pretix.presale.style import regenerate_css
|
||||
|
||||
from ...base.models.items import ItemMetaProperty
|
||||
from ...base.settings import LazyI18nStringList
|
||||
from ..logdisplay import OVERVIEW_BANLIST
|
||||
from . import CreateView, PaginationMixin, UpdateView
|
||||
|
||||
@@ -140,7 +143,8 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['sform'] = self.sform
|
||||
context['meta_forms'] = self.meta_forms
|
||||
context['formset'] = self.formset
|
||||
context['item_meta_property_formset'] = self.item_meta_property_formset
|
||||
context['confirm_texts_formset'] = self.confirm_texts_formset
|
||||
return context
|
||||
|
||||
@transaction.atomic
|
||||
@@ -148,13 +152,15 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
self._save_decoupled(self.sform)
|
||||
self.sform.save()
|
||||
self.save_meta()
|
||||
self.save_formset(self.object)
|
||||
self.save_item_meta_property_formset(self.object)
|
||||
self.save_confirm_texts_formset(self.object)
|
||||
change_css = False
|
||||
|
||||
if self.sform.has_changed():
|
||||
self.request.event.log_action('pretix.event.settings', user=self.request.user, data={
|
||||
k: self.request.event.settings.get(k) for k in self.sform.changed_data
|
||||
})
|
||||
if self.sform.has_changed() or self.confirm_texts_formset.has_changed():
|
||||
data = {k: self.request.event.settings.get(k) for k in self.sform.changed_data}
|
||||
if self.confirm_texts_formset.has_changed():
|
||||
data.update(confirm_texts=self.confirm_texts_formset.cleaned_data)
|
||||
self.request.event.log_action('pretix.event.settings', user=self.request.user, data=data)
|
||||
display_properties = (
|
||||
'primary_color', 'theme_color_success', 'theme_color_danger', 'primary_font',
|
||||
'theme_color_background', 'theme_round_borders',
|
||||
@@ -194,7 +200,7 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
def post(self, request, *args, **kwargs):
|
||||
form = self.get_form()
|
||||
if form.is_valid() and self.sform.is_valid() and all([f.is_valid() for f in self.meta_forms]) and \
|
||||
self.formset.is_valid():
|
||||
self.item_meta_property_formset.is_valid() and self.confirm_texts_formset.is_valid():
|
||||
# reset timezone
|
||||
zone = timezone(self.sform.cleaned_data['timezone'])
|
||||
event = form.instance
|
||||
@@ -212,17 +218,17 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
return tz.localize(dt.replace(tzinfo=None)) if dt is not None else None
|
||||
|
||||
@cached_property
|
||||
def formset(self):
|
||||
def item_meta_property_formset(self):
|
||||
formsetclass = inlineformset_factory(
|
||||
Event, ItemMetaProperty,
|
||||
form=ItemMetaPropertyForm, can_order=False, can_delete=True, extra=0
|
||||
)
|
||||
return formsetclass(self.request.POST if self.request.method == "POST" else None,
|
||||
return formsetclass(self.request.POST if self.request.method == "POST" else None, prefix="item-meta-property",
|
||||
instance=self.object, queryset=self.object.item_meta_properties.all())
|
||||
|
||||
def save_formset(self, obj):
|
||||
for form in self.formset.initial_forms:
|
||||
if form in self.formset.deleted_forms:
|
||||
def save_item_meta_property_formset(self, obj):
|
||||
for form in self.item_meta_property_formset.initial_forms:
|
||||
if form in self.item_meta_property_formset.deleted_forms:
|
||||
if not form.instance.pk:
|
||||
continue
|
||||
form.instance.delete()
|
||||
@@ -230,14 +236,28 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
elif form.has_changed():
|
||||
form.save()
|
||||
|
||||
for form in self.formset.extra_forms:
|
||||
for form in self.item_meta_property_formset.extra_forms:
|
||||
if not form.has_changed():
|
||||
continue
|
||||
if self.formset._should_delete_form(form):
|
||||
if self.item_meta_property_formset._should_delete_form(form):
|
||||
continue
|
||||
form.instance.event = obj
|
||||
form.save()
|
||||
|
||||
@cached_property
|
||||
def confirm_texts_formset(self):
|
||||
initial = [{"text": text, "ORDER": order} for order, text in
|
||||
enumerate(self.object.settings.get("confirm_texts", as_type=LazyI18nStringList))]
|
||||
return ConfirmTextFormset(self.request.POST if self.request.method == "POST" else None, event=self.object,
|
||||
prefix="confirm-texts", initial=initial)
|
||||
|
||||
def save_confirm_texts_formset(self, obj):
|
||||
obj.settings.confirm_texts = LazyI18nStringList(
|
||||
form_data['text'].data
|
||||
for form_data in sorted(self.confirm_texts_formset.cleaned_data, key=operator.itemgetter("ORDER"))
|
||||
if not form_data.get("DELETE", False)
|
||||
)
|
||||
|
||||
|
||||
class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
|
||||
model = Event
|
||||
|
||||
@@ -54,6 +54,10 @@ div[data-formset-body], div[data-formset-form], div[data-nested-formset-form], d
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.formset-row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.submit-group {
|
||||
margin: 15px 0 0 0 !important;
|
||||
padding: 15px;
|
||||
|
||||
@@ -11,6 +11,7 @@ from pretix.base.models import Event, Organizer, Team, User
|
||||
class MailSettingPreviewTest(SoupTest):
|
||||
@scopes_disabled()
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
self.orga1 = Organizer.objects.create(name='CCC', slug='ccc')
|
||||
self.orga2 = Organizer.objects.create(name='MRM', slug='mrm')
|
||||
Reference in New Issue
Block a user