mirror of
https://github.com/pretix/pretix.git
synced 2026-04-26 23:52:35 +00:00
New event creation wizard
This commit is contained in:
@@ -23,11 +23,12 @@ class BaseI18nModelForm(BaseModelForm):
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
event = kwargs.pop('event', None)
|
||||
locales = kwargs.pop('locales', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
if event:
|
||||
if event or locales:
|
||||
for k, field in self.fields.items():
|
||||
if isinstance(field, I18nFormField):
|
||||
field.widget.enabled_langcodes = event.settings.get('locales')
|
||||
field.widget.enabled_langcodes = event.settings.get('locales') if event else locales
|
||||
|
||||
|
||||
class I18nModelForm(six.with_metaclass(ModelFormMetaclass, BaseI18nModelForm)):
|
||||
@@ -97,12 +98,14 @@ class SettingsForm(forms.Form):
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.obj = kwargs.pop('obj')
|
||||
self.obj = kwargs.pop('obj', None)
|
||||
self.locales = kwargs.pop('locales', None)
|
||||
kwargs['initial'] = self.obj.settings.freeze()
|
||||
super().__init__(*args, **kwargs)
|
||||
for k, field in self.fields.items():
|
||||
if isinstance(field, I18nFormField):
|
||||
field.widget.enabled_langcodes = self.obj.settings.get('locales')
|
||||
if self.obj or self.locales:
|
||||
for k, field in self.fields.items():
|
||||
if isinstance(field, I18nFormField):
|
||||
field.widget.enabled_langcodes = self.obj.settings.get('locales') if self.obj else self.locales
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
|
||||
@@ -63,7 +63,7 @@ class Event(LoggedModel):
|
||||
max_length=50, db_index=True,
|
||||
help_text=_(
|
||||
"Should be short, only contain lowercase letters and numbers, and must be unique among your events. "
|
||||
"This is being used in addresses and bank transfer references."),
|
||||
"This will be used in order codes, invoice numbers, links and bank transfer references."),
|
||||
validators=[
|
||||
RegexValidator(
|
||||
regex="^[a-zA-Z0-9.-]+$",
|
||||
@@ -71,7 +71,7 @@ class Event(LoggedModel):
|
||||
),
|
||||
EventSlugBlacklistValidator()
|
||||
],
|
||||
verbose_name=_("Slug"),
|
||||
verbose_name=_("Short form"),
|
||||
)
|
||||
live = models.BooleanField(default=False, verbose_name=_("Shop is live"))
|
||||
permitted = models.ManyToManyField(User, through='EventPermission',
|
||||
|
||||
@@ -2,19 +2,59 @@ from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import RegexValidator
|
||||
from django.utils.timezone import get_current_timezone_name
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from pytz import common_timezones
|
||||
|
||||
from pretix.base.forms import I18nModelForm, SettingsForm
|
||||
from pretix.base.i18n import I18nFormField, I18nTextarea
|
||||
from pretix.base.models import Event
|
||||
from pretix.base.models import Event, Organizer
|
||||
from pretix.control.forms import ExtFileField
|
||||
|
||||
|
||||
class EventCreateForm(I18nModelForm):
|
||||
class EventWizardFoundationForm(forms.Form):
|
||||
locales = forms.MultipleChoiceField(
|
||||
choices=settings.LANGUAGES,
|
||||
label=_("Use languages"),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
help_text=_('Choose all languages that your event should be available in.')
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop('user')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['organizer'] = forms.ModelChoiceField(
|
||||
label=_("Organizer"),
|
||||
queryset=Organizer.objects.filter(
|
||||
id__in=self.user.organizer_perms.filter(can_create_events=True).values_list('id', flat=True)
|
||||
),
|
||||
widget=forms.RadioSelect,
|
||||
empty_label=None,
|
||||
required=True
|
||||
)
|
||||
|
||||
def clean_slug(self):
|
||||
slug = self.cleaned_data['slug']
|
||||
if Event.objects.filter(slug=slug, organizer=self.organizer).exists():
|
||||
raise forms.ValidationError(
|
||||
self.error_messages['duplicate_slug'],
|
||||
code='duplicate_slug'
|
||||
)
|
||||
return slug
|
||||
|
||||
|
||||
class EventWizardBasicsForm(I18nModelForm):
|
||||
error_messages = {
|
||||
'duplicate_slug': _("You already used this slug for a different event. Please choose a new one."),
|
||||
}
|
||||
timezone = forms.ChoiceField(
|
||||
choices=((a, a) for a in common_timezones),
|
||||
label=_("Default timezone"),
|
||||
)
|
||||
locale = forms.ChoiceField(
|
||||
choices=settings.LANGUAGES,
|
||||
label=_("Default language"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Event
|
||||
@@ -36,7 +76,19 @@ class EventCreateForm(I18nModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.organizer = kwargs.pop('organizer')
|
||||
self.locales = kwargs.get('locales')
|
||||
kwargs.pop('user')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.initial['timezone'] = get_current_timezone_name()
|
||||
self.fields['locale'].choices = [(a, b) for a, b in settings.LANGUAGES if a in self.locales]
|
||||
|
||||
def clean(self):
|
||||
data = super().clean()
|
||||
if data['locale'] not in self.locales:
|
||||
raise ValidationError({
|
||||
'locale': _('Your default locale must also be enabled for your event (see box above).')
|
||||
})
|
||||
return data
|
||||
|
||||
def clean_slug(self):
|
||||
slug = self.cleaned_data['slug']
|
||||
@@ -48,29 +100,6 @@ class EventCreateForm(I18nModelForm):
|
||||
return slug
|
||||
|
||||
|
||||
class EventCreateSettingsForm(SettingsForm):
|
||||
timezone = forms.ChoiceField(
|
||||
choices=((a, a) for a in common_timezones),
|
||||
label=_("Default timezone"),
|
||||
)
|
||||
locales = forms.MultipleChoiceField(
|
||||
choices=settings.LANGUAGES,
|
||||
label=_("Available langauges"),
|
||||
)
|
||||
locale = forms.ChoiceField(
|
||||
choices=settings.LANGUAGES,
|
||||
label=_("Default language"),
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
data = super().clean()
|
||||
if data['locale'] not in data['locales']:
|
||||
raise ValidationError({
|
||||
'locale': _('Your default locale must also be enabled for your event (see box above).')
|
||||
})
|
||||
return data
|
||||
|
||||
|
||||
class EventUpdateForm(I18nModelForm):
|
||||
def clean_slug(self):
|
||||
return self.instance.slug
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
{% extends "pretixcontrol/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Create a new event" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans "Create a new event" %}</h1>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form_errors form %}
|
||||
<fieldset>
|
||||
<legend>{% trans "General information" %}</legend>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.slug layout="horizontal" %}
|
||||
{% bootstrap_field form.date_from layout="horizontal" %}
|
||||
{% bootstrap_field form.date_to layout="horizontal" %}
|
||||
{% bootstrap_field form.currency layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Display settings" %}</legend>
|
||||
{% bootstrap_field sform.locales layout="horizontal" %}
|
||||
{% bootstrap_field sform.locale layout="horizontal" %}
|
||||
{% bootstrap_field sform.timezone layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Timeline" %}</legend>
|
||||
{% bootstrap_field form.presale_start layout="horizontal" %}
|
||||
{% bootstrap_field form.presale_end layout="horizontal" %}
|
||||
</fieldset>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
You will be able to adjust further settings in the next step.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,27 @@
|
||||
{% extends "pretixcontrol/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Create a new event" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans "Create a new event" %} <small>{% blocktrans trimmed with step=wizard.steps.step1 %}
|
||||
Step {{ step }}
|
||||
{% endblocktrans %}</small></h1>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
{{ wizard.management_form }}
|
||||
{% bootstrap_form_errors form %}
|
||||
{% block form %}
|
||||
{% endblock %}
|
||||
<div class="form-group submit-group">
|
||||
{% if wizard.steps.prev %}
|
||||
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}"
|
||||
class="btn btn-default btn-lg pull-left">
|
||||
{% trans "Back" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Continue" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,23 @@
|
||||
{% extends "pretixcontrol/events/create_base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block form %}
|
||||
<fieldset>
|
||||
<legend>{% trans "General information" %}</legend>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.slug layout="horizontal" %}
|
||||
{% bootstrap_field form.date_from layout="horizontal" %}
|
||||
{% bootstrap_field form.date_to layout="horizontal" %}
|
||||
{% bootstrap_field form.currency layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Display settings" %}</legend>
|
||||
{% bootstrap_field form.locale layout="horizontal" %}
|
||||
{% bootstrap_field form.timezone layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Timeline" %}</legend>
|
||||
{% bootstrap_field form.presale_start layout="horizontal" %}
|
||||
{% bootstrap_field form.presale_end layout="horizontal" %}
|
||||
</fieldset>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,7 @@
|
||||
{% extends "pretixcontrol/events/create_base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block form %}
|
||||
{% bootstrap_field form.organizer layout="horizontal" %}
|
||||
{% bootstrap_field form.locales layout="horizontal" %}
|
||||
{% endblock %}
|
||||
@@ -1,30 +0,0 @@
|
||||
{% extends "pretixcontrol/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create a new event" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans "Create a new event" %}</h1>
|
||||
{% if organizers|length == 0 %}
|
||||
<div class="alert alert-info">
|
||||
{% trans "You are not permitted to create new events in the name of any organizer." %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p>{% trans "Please choose the organizer of this event from the list below." %}</p>
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Organizer name" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for o in organizers %}
|
||||
<tr>
|
||||
<td><strong>
|
||||
<a href="{% url "control:events.create" organizer=o.slug %}">{{ o.name }}</a>
|
||||
</strong></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -33,8 +33,7 @@ urlpatterns = [
|
||||
url(r'^organizers/add$', organizer.OrganizerCreate.as_view(), name='organizers.add'),
|
||||
url(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'),
|
||||
url(r'^events/$', main.EventList.as_view(), name='events'),
|
||||
url(r'^events/add$', main.EventCreateStart.as_view(), name='events.add'),
|
||||
url(r'^event/(?P<organizer>[^/]+)/add', main.EventCreate.as_view(), name='events.create'),
|
||||
url(r'^events/add$', main.EventWizard.as_view(), name='events.add'),
|
||||
url(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
|
||||
url(r'^$', dashboards.event_index, name='event.index'),
|
||||
url(r'^live/$', event.EventLive.as_view(), name='event.live'),
|
||||
|
||||
@@ -2,13 +2,15 @@ from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import transaction
|
||||
from django.utils.functional import cached_property
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import CreateView, ListView, TemplateView
|
||||
from django.views.generic import ListView
|
||||
from formtools.wizard.views import SessionWizardView
|
||||
|
||||
from pretix.base.models import Event, EventPermission, OrganizerPermission
|
||||
from pretix.control.forms.event import EventCreateForm, EventCreateSettingsForm
|
||||
from pretix.control.permissions import OrganizerPermissionRequiredMixin
|
||||
from pretix.base.models import Event, EventPermission
|
||||
from pretix.control.forms.event import (
|
||||
EventWizardBasicsForm, EventWizardFoundationForm,
|
||||
)
|
||||
|
||||
|
||||
class EventList(ListView):
|
||||
@@ -25,76 +27,55 @@ class EventList(ListView):
|
||||
)
|
||||
|
||||
|
||||
class EventCreateStart(TemplateView):
|
||||
template_name = 'pretixcontrol/events/start.html'
|
||||
class EventWizard(SessionWizardView):
|
||||
form_list = [
|
||||
('foundation', EventWizardFoundationForm),
|
||||
('basics', EventWizardBasicsForm),
|
||||
]
|
||||
templates = {
|
||||
'foundation': 'pretixcontrol/events/create_foundation.html',
|
||||
'basics': 'pretixcontrol/events/create_basics.html'
|
||||
}
|
||||
condition_dict = {
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['organizers'] = [
|
||||
p.organizer for p in OrganizerPermission.objects.filter(
|
||||
user=self.request.user, can_create_events=True
|
||||
).select_related("organizer")
|
||||
]
|
||||
return ctx
|
||||
}
|
||||
|
||||
|
||||
class EventCreate(OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = Event
|
||||
form_class = EventCreateForm
|
||||
template_name = 'pretixcontrol/events/create.html'
|
||||
context_object_name = 'event'
|
||||
permission = 'can_create_events'
|
||||
|
||||
@cached_property
|
||||
def sform(self):
|
||||
return EventCreateSettingsForm(
|
||||
obj=Event(),
|
||||
prefix='settings',
|
||||
data=self.request.POST if self.request.method == 'POST' else None
|
||||
)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
form = self.get_form()
|
||||
if form.is_valid() and self.sform.is_valid():
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['sform'] = self.sform
|
||||
return context
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = Event()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['organizer'] = self.request.organizer
|
||||
def get_form_kwargs(self, step=None):
|
||||
kwargs = {
|
||||
'user': self.request.user
|
||||
}
|
||||
if step != 'foundation':
|
||||
fdata = self.get_cleaned_data_for_step('foundation')
|
||||
kwargs.update(fdata)
|
||||
return kwargs
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
def get_template_names(self):
|
||||
return [self.templates[self.steps.current]]
|
||||
|
||||
def done(self, form_list, form_dict, **kwargs):
|
||||
foundation_data = self.get_cleaned_data_for_step('foundation')
|
||||
basics_data = self.get_cleaned_data_for_step('basics')
|
||||
|
||||
with transaction.atomic():
|
||||
event = form_dict['basics'].instance
|
||||
event.organizer = foundation_data['organizer']
|
||||
event.plugins = settings.PRETIX_PLUGINS_DEFAULT
|
||||
form_dict['basics'].save()
|
||||
EventPermission.objects.create(event=event, user=self.request.user)
|
||||
|
||||
event.settings.set('timezone', basics_data['timezone'])
|
||||
event.settings.set('locale', basics_data['locale'])
|
||||
event.settings.set('locales', foundation_data['locales'])
|
||||
|
||||
logdata = {}
|
||||
for f in form_list:
|
||||
logdata.update({
|
||||
k: v for k, v in f.cleaned_data.items()
|
||||
})
|
||||
event.log_action('pretix.event.settings', user=self.request.user, data=logdata)
|
||||
|
||||
messages.success(self.request, _('The new event has been created.'))
|
||||
form.instance.organizer = self.request.organizer
|
||||
ret = super().form_valid(form)
|
||||
EventPermission.objects.create(
|
||||
event=form.instance, user=self.request.user,
|
||||
)
|
||||
self.object = form.instance
|
||||
self.object.plugins = settings.PRETIX_PLUGINS_DEFAULT
|
||||
self.object.save()
|
||||
|
||||
self.sform.obj = form.instance
|
||||
self.sform.save()
|
||||
form.instance.log_action('pretix.event.settings', user=self.request.user, data={
|
||||
k: form.instance.settings.get(k) for k in self.sform.changed_data
|
||||
})
|
||||
return ret
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.settings', kwargs={
|
||||
'organizer': self.request.organizer.slug,
|
||||
'event': self.object.slug,
|
||||
})
|
||||
return redirect(reverse('control:event.settings', kwargs={
|
||||
'organizer': event.organizer.slug,
|
||||
'event': event.slug,
|
||||
}))
|
||||
|
||||
@@ -12,6 +12,7 @@ django-libsass
|
||||
libsass
|
||||
django-otp==0.3.*
|
||||
python-u2flib-server==4.*
|
||||
django-formtools==1.0
|
||||
# celery>=3.1,<3.2
|
||||
# until the following issue is fixed, we need our own celery version
|
||||
# https://github.com/celery/celery/pull/3199
|
||||
|
||||
@@ -3,9 +3,7 @@ from datetime import timedelta
|
||||
import pytest
|
||||
from django.utils.timezone import now
|
||||
|
||||
from pretix.base.models import (
|
||||
Event, EventPermission, Order, Organizer, OrganizerPermission, User,
|
||||
)
|
||||
from pretix.base.models import Event, EventPermission, Order, Organizer, User
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -74,7 +72,6 @@ event_urls = [
|
||||
|
||||
organizer_urls = [
|
||||
'organizer/abc/edit',
|
||||
'event/abc/add'
|
||||
]
|
||||
|
||||
|
||||
@@ -211,8 +208,9 @@ def test_wrong_organizer(perf_patch, client, env, url):
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
""" Disabled as tehre are currtnly no fitting URLs
|
||||
organizer_permission_urls = [
|
||||
("can_create_events", "event/dummy/add", 200),
|
||||
("can_create_events", "organizer/dummy/edit", 200),
|
||||
]
|
||||
|
||||
|
||||
@@ -242,3 +240,4 @@ def test_correct_organizer_permission(perf_patch, client, env, perm, url, code):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/' + url)
|
||||
assert response.status_code == code
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user