diff --git a/doc/development/api/general.rst b/doc/development/api/general.rst index 9e744c0c60..3bfa10ba4d 100644 --- a/doc/development/api/general.rst +++ b/doc/development/api/general.rst @@ -49,7 +49,7 @@ Backend .. automodule:: pretix.control.signals :members: nav_event, html_head, html_page_start, quota_detail_html, nav_topbar, nav_global, nav_organizer, nav_event_settings, - order_info, event_settings_widget, oauth_application_registered, order_position_buttons, nav_item, subevent_forms + order_info, event_settings_widget, oauth_application_registered, order_position_buttons, subevent_forms, item_formsets .. automodule:: pretix.base.signals diff --git a/doc/spelling_wordlist.txt b/doc/spelling_wordlist.txt index 0df17f0a7c..1d3eab6dde 100644 --- a/doc/spelling_wordlist.txt +++ b/doc/spelling_wordlist.txt @@ -36,6 +36,8 @@ eu filename filesystem fontawesome +formset +formsets frontend frontpage gettext diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index 1afd83c941..3057139668 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -325,7 +325,7 @@ class EventSettingsForm(SettingsForm): ) timezone = forms.ChoiceField( choices=((a, a) for a in common_timezones), - label=_("Default timezone"), + label=_("Event timezone"), ) locales = forms.MultipleChoiceField( choices=settings.LANGUAGES, @@ -441,6 +441,96 @@ class EventSettingsForm(SettingsForm): required=False, help_text=_("We'll show this publicly to allow attendees to contact you.") ) + show_variations_expanded = forms.BooleanField( + label=_("Show variations of a product expanded by default"), + required=False + ) + hide_sold_out = forms.BooleanField( + label=_("Hide all products that are sold out"), + required=False + ) + meta_noindex = forms.BooleanField( + label=_('Ask search engines not to index the ticket shop'), + required=False + ) + redirect_to_checkout_directly = forms.BooleanField( + label=_('Directly redirect to check-out after a product has been added to the cart.'), + required=False + ) + frontpage_subevent_ordering = forms.ChoiceField( + label=pgettext('subevent', 'Date ordering'), + choices=[ + ('date_ascending', _('Event start time')), + ('date_descending', _('Event start time (descending)')), + ('name_ascending', _('Name')), + ('name_descending', _('Name (descending)')), + ], # When adding a new ordering, remember to also define it in the event model + ) + logo_image = ExtFileField( + label=_('Logo image'), + ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"), + required=False, + help_text=_('If you provide a logo image, we will by default not show your events name and date ' + 'in the page header. We will show your logo with a maximal height of 120 pixels.') + ) + frontpage_text = I18nFormField( + label=_("Frontpage text"), + required=False, + widget=I18nTextarea + ) + presale_has_ended_text = I18nFormField( + label=_("End of presale text"), + required=False, + widget=I18nTextarea, + widget_kwargs={'attrs': {'rows': '2'}}, + help_text=_("This text will be shown above the ticket shop once the designated sales timeframe for this event " + "is over. You can use it to describe other options to get a ticket, such as a box office.") + ) + voucher_explanation_text = I18nFormField( + label=_("Voucher explanation"), + required=False, + widget=I18nTextarea, + widget_kwargs={'attrs': {'rows': '2'}}, + help_text=_("This text will be shown next to the input for a voucher code. You can use it e.g. to explain " + "how to obtain a voucher code.") + ) + primary_color = forms.CharField( + label=_("Primary color"), + required=False, + validators=[ + RegexValidator(regex='^#[0-9a-fA-F]{6}$', + message=_('Please enter the hexadecimal code of a color, e.g. #990000.')), + ], + widget=forms.TextInput(attrs={'class': 'colorpickerfield'}) + ) + theme_color_success = forms.CharField( + label=_("Accent color for success"), + help_text=_("We strongly suggest to use a shade of green."), + required=False, + validators=[ + RegexValidator(regex='^#[0-9a-fA-F]{6}$', + message=_('Please enter the hexadecimal code of a color, e.g. #990000.')), + ], + widget=forms.TextInput(attrs={'class': 'colorpickerfield'}) + ) + theme_color_danger = forms.CharField( + label=_("Accent color for errors"), + help_text=_("We strongly suggest to use a dark shade of red."), + required=False, + validators=[ + RegexValidator(regex='^#[0-9a-fA-F]{6}$', + message=_('Please enter the hexadecimal code of a color, e.g. #990000.')), + ], + widget=forms.TextInput(attrs={'class': 'colorpickerfield'}) + ) + primary_font = forms.ChoiceField( + label=_('Font'), + choices=[ + ('Open Sans', 'Open Sans') + ], + widget=FontSelect, + help_text=_('Only respected by modern browsers.') + ) def clean(self): data = super().clean() @@ -459,6 +549,7 @@ class EventSettingsForm(SettingsForm): return data def __init__(self, *args, **kwargs): + event = kwargs['obj'] super().__init__(*args, **kwargs) self.fields['confirm_text'].widget.attrs['rows'] = '3' self.fields['confirm_text'].widget.attrs['placeholder'] = _( @@ -479,6 +570,11 @@ class EventSettingsForm(SettingsForm): )) for k, v in PERSON_NAME_TITLE_GROUPS.items() ] + if not event.has_subevents: + del self.fields['frontpage_subevent_ordering'] + self.fields['primary_font'].choices += [ + (a, a) for a in get_fonts() + ] class CancelSettingsForm(SettingsForm): @@ -1137,108 +1233,6 @@ class MailSettingsForm(SettingsForm): raise ValidationError(_('You can activate either SSL or STARTTLS security, but not both at the same time.')) -class DisplaySettingsForm(SettingsForm): - primary_color = forms.CharField( - label=_("Primary color"), - required=False, - validators=[ - RegexValidator(regex='^#[0-9a-fA-F]{6}$', - message=_('Please enter the hexadecimal code of a color, e.g. #990000.')), - ], - widget=forms.TextInput(attrs={'class': 'colorpickerfield'}) - ) - theme_color_success = forms.CharField( - label=_("Accent color for success"), - help_text=_("We strongly suggest to use a shade of green."), - required=False, - validators=[ - RegexValidator(regex='^#[0-9a-fA-F]{6}$', - message=_('Please enter the hexadecimal code of a color, e.g. #990000.')), - ], - widget=forms.TextInput(attrs={'class': 'colorpickerfield'}) - ) - theme_color_danger = forms.CharField( - label=_("Accent color for errors"), - help_text=_("We strongly suggest to use a dark shade of red."), - required=False, - validators=[ - RegexValidator(regex='^#[0-9a-fA-F]{6}$', - message=_('Please enter the hexadecimal code of a color, e.g. #990000.')), - ], - widget=forms.TextInput(attrs={'class': 'colorpickerfield'}) - ) - logo_image = ExtFileField( - label=_('Logo image'), - ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"), - required=False, - help_text=_('If you provide a logo image, we will by default not show your events name and date ' - 'in the page header. We will show your logo with a maximal height of 120 pixels.') - ) - primary_font = forms.ChoiceField( - label=_('Font'), - choices=[ - ('Open Sans', 'Open Sans') - ], - widget=FontSelect, - help_text=_('Only respected by modern browsers.') - ) - frontpage_text = I18nFormField( - label=_("Frontpage text"), - required=False, - widget=I18nTextarea - ) - presale_has_ended_text = I18nFormField( - label=_("End of presale text"), - required=False, - widget=I18nTextarea, - widget_kwargs={'attrs': {'rows': '2'}}, - help_text=_("This text will be shown above the ticket shop once the designated sales timeframe for this event " - "is over. You can use it to describe other options to get a ticket, such as a box office.") - ) - voucher_explanation_text = I18nFormField( - label=_("Voucher explanation"), - required=False, - widget=I18nTextarea, - widget_kwargs={'attrs': {'rows': '2'}}, - help_text=_("This text will be shown next to the input for a voucher code. You can use it e.g. to explain " - "how to obtain a voucher code.") - ) - show_variations_expanded = forms.BooleanField( - label=_("Show variations of a product expanded by default"), - required=False - ) - hide_sold_out = forms.BooleanField( - label=_("Hide all products that are sold out"), - required=False - ) - frontpage_subevent_ordering = forms.ChoiceField( - label=pgettext('subevent', 'Date ordering'), - choices=[ - ('date_ascending', _('Event start time')), - ('date_descending', _('Event start time (descending)')), - ('name_ascending', _('Name')), - ('name_descending', _('Name (descending)')), - ], # When adding a new ordering, remember to also define it in the event model - ) - meta_noindex = forms.BooleanField( - label=_('Ask search engines not to index the ticket shop'), - required=False - ) - redirect_to_checkout_directly = forms.BooleanField( - label=_('Directly redirect to check-out after a product has been added to the cart.'), - required=False - ) - - def __init__(self, *args, **kwargs): - event = kwargs['obj'] - super().__init__(*args, **kwargs) - self.fields['primary_font'].choices += [ - (a, a) for a in get_fonts() - ] - if not event.has_subevents: - del self.fields['frontpage_subevent_ordering'] - - class TicketSettingsForm(SettingsForm): ticket_download = forms.BooleanField( label=_("Use feature"), diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py index 51087c8719..b977b174ce 100644 --- a/src/pretix/control/forms/item.py +++ b/src/pretix/control/forms/item.py @@ -460,6 +460,9 @@ class ItemUpdateForm(I18nModelForm): class ItemVariationsFormSet(I18nFormSet): + template = "pretixcontrol/item/include_variations.html" + title = _('Variations') + def clean(self): super().clean() for f in self.forms: @@ -516,6 +519,9 @@ class ItemVariationForm(I18nModelForm): class ItemAddOnsFormSet(I18nFormSet): + title = _('Add-ons') + template = "pretixcontrol/item/include_addons.html" + def __init__(self, *args, **kwargs): self.event = kwargs.get('event') super().__init__(*args, **kwargs) @@ -581,6 +587,9 @@ class ItemAddOnForm(I18nModelForm): class ItemBundleFormSet(I18nFormSet): + template = "pretixcontrol/item/include_bundles.html" + title = _('Bundled products') + def __init__(self, *args, **kwargs): self.event = kwargs.get('event') self.item = kwargs.pop('item') diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py index a427c6f7de..8649a00066 100644 --- a/src/pretix/control/forms/organizer.py +++ b/src/pretix/control/forms/organizer.py @@ -201,9 +201,6 @@ class OrganizerSettingsForm(SettingsForm): widget=I18nTextarea, help_text=_('Not displayed anywhere by default, but if you want to, you can use this e.g. in ticket templates.') ) - - -class OrganizerDisplaySettingsForm(SettingsForm): primary_color = forms.CharField( label=_("Primary color"), required=False, diff --git a/src/pretix/control/navigation.py b/src/pretix/control/navigation.py index 0a9e7aa1aa..8428741693 100644 --- a/src/pretix/control/navigation.py +++ b/src/pretix/control/navigation.py @@ -48,14 +48,6 @@ def get_event_navigation(request: HttpRequest): }), 'active': url.url_name == 'event.settings.plugins', }, - { - 'label': _('Display'), - 'url': reverse('control:event.settings.display', kwargs={ - 'event': request.event.slug, - 'organizer': request.event.organizer.slug, - }), - 'active': url.url_name == 'event.settings.display', - }, { 'label': _('Tickets'), 'url': reverse('control:event.settings.tickets', kwargs={ @@ -78,7 +70,7 @@ def get_event_navigation(request: HttpRequest): 'event': request.event.slug, 'organizer': request.event.organizer.slug, }), - 'active': url.url_name == 'event.settings.tax', + 'active': url.url_name.startswith('event.settings.tax'), }, { 'label': _('Invoicing'), @@ -425,13 +417,6 @@ def get_organizer_navigation(request): }), 'active': url.url_name == 'organizer.edit', }, - { - 'label': _('Display'), - 'url': reverse('control:organizer.display', kwargs={ - 'organizer': request.organizer.slug - }), - 'active': url.url_name == 'organizer.display', - }, ] }) if 'can_change_teams' in request.orgapermset: diff --git a/src/pretix/control/signals.py b/src/pretix/control/signals.py index f9eb4ba9b1..af87986eb8 100644 --- a/src/pretix/control/signals.py +++ b/src/pretix/control/signals.py @@ -237,24 +237,6 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve A second keyword argument ``request`` will contain the request object. """ -nav_item = EventPluginSignal( - providing_args=['request', 'item'] -) -""" -This signal is sent out to include tab links on the settings page of an item. -Receivers are expected to return a list of dictionaries. The dictionaries -should contain at least the keys ``label`` and ``url``. You should also return -an ``active`` key with a boolean set to ``True``, when this item should be marked -as active. - -If your linked view should stay in the tab-like context of this page, we recommend -that you use ``pretix.control.views.item.ItemDetailMixin`` for your view -and your template inherits from ``pretixcontrol/item/base.html``. - -As with all plugin signals, the ``sender`` keyword argument will contain the event. -A second keyword argument ``request`` will contain the request object. -""" - event_settings_widget = EventPluginSignal( providing_args=['request'] ) @@ -279,6 +261,24 @@ styles. It is advisable to set a prefix for your form to avoid clashes with othe As with all plugin signals, the ``sender`` keyword argument will contain the event. """ +item_formsets = EventPluginSignal( + providing_args=['request', 'item'] +) +""" +This signal allows you to return additional formsets that should be rendered on the product +modification page. You are passed ``request`` and ``item`` arguments and are expected to return +an instance of a formset class that you bind yourself when appropriate. Your formset will be +executed as part of the standard validation and rendering cycle and rendered using default +bootstrap styles. It is advisable to set a prefix for your formset to avoid clashes with other +plugins. + +Your formset needs to have two special properties: ``template`` with a template that will be +included to render the formset and ``title`` that will be used as a headline. Your template +will be passed a ``formset`` variable with your formset. + +As with all plugin signals, the ``sender`` keyword argument will contain the event. +""" + subevent_forms = EventPluginSignal( providing_args=['request', 'subevent'] ) diff --git a/src/pretix/control/templates/pretixcontrol/base.html b/src/pretix/control/templates/pretixcontrol/base.html index c6ed2c525d..ff9bf22771 100644 --- a/src/pretix/control/templates/pretixcontrol/base.html +++ b/src/pretix/control/templates/pretixcontrol/base.html @@ -47,6 +47,7 @@ + diff --git a/src/pretix/control/templates/pretixcontrol/event/cancel.html b/src/pretix/control/templates/pretixcontrol/event/cancel.html index 004e701b42..59288aa387 100644 --- a/src/pretix/control/templates/pretixcontrol/event/cancel.html +++ b/src/pretix/control/templates/pretixcontrol/event/cancel.html @@ -6,31 +6,33 @@