diff --git a/src/pretix/base/forms/__init__.py b/src/pretix/base/forms/__init__.py
index 038d81cdd..6b38ddb10 100644
--- a/src/pretix/base/forms/__init__.py
+++ b/src/pretix/base/forms/__init__.py
@@ -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):
"""
diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py
index 8ac9c2bb3..6904a8563 100644
--- a/src/pretix/base/models/event.py
+++ b/src/pretix/base/models/event.py
@@ -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',
diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py
index e8a0c56bb..e24db36a5 100644
--- a/src/pretix/control/forms/event.py
+++ b/src/pretix/control/forms/event.py
@@ -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
diff --git a/src/pretix/control/templates/pretixcontrol/events/create.html b/src/pretix/control/templates/pretixcontrol/events/create.html
deleted file mode 100644
index 64ef36a80..000000000
--- a/src/pretix/control/templates/pretixcontrol/events/create.html
+++ /dev/null
@@ -1,40 +0,0 @@
-{% extends "pretixcontrol/base.html" %}
-{% load i18n %}
-{% load bootstrap3 %}
-{% block title %}{% trans "Create a new event" %}{% endblock %}
-{% block content %}
-
{% trans "Create a new event" %}
-
-{% endblock %}
diff --git a/src/pretix/control/templates/pretixcontrol/events/create_base.html b/src/pretix/control/templates/pretixcontrol/events/create_base.html
new file mode 100644
index 000000000..cde3f3adf
--- /dev/null
+++ b/src/pretix/control/templates/pretixcontrol/events/create_base.html
@@ -0,0 +1,27 @@
+{% extends "pretixcontrol/base.html" %}
+{% load i18n %}
+{% load bootstrap3 %}
+{% block title %}{% trans "Create a new event" %}{% endblock %}
+{% block content %}
+ {% trans "Create a new event" %} {% blocktrans trimmed with step=wizard.steps.step1 %}
+ Step {{ step }}
+ {% endblocktrans %}
+
+{% endblock %}
diff --git a/src/pretix/control/templates/pretixcontrol/events/create_basics.html b/src/pretix/control/templates/pretixcontrol/events/create_basics.html
new file mode 100644
index 000000000..875d57532
--- /dev/null
+++ b/src/pretix/control/templates/pretixcontrol/events/create_basics.html
@@ -0,0 +1,23 @@
+{% extends "pretixcontrol/events/create_base.html" %}
+{% load i18n %}
+{% load bootstrap3 %}
+{% block form %}
+
+
+
+{% endblock %}
diff --git a/src/pretix/control/templates/pretixcontrol/events/create_foundation.html b/src/pretix/control/templates/pretixcontrol/events/create_foundation.html
new file mode 100644
index 000000000..2c5eafe5c
--- /dev/null
+++ b/src/pretix/control/templates/pretixcontrol/events/create_foundation.html
@@ -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 %}
diff --git a/src/pretix/control/templates/pretixcontrol/events/start.html b/src/pretix/control/templates/pretixcontrol/events/start.html
deleted file mode 100644
index d29a95766..000000000
--- a/src/pretix/control/templates/pretixcontrol/events/start.html
+++ /dev/null
@@ -1,30 +0,0 @@
-{% extends "pretixcontrol/base.html" %}
-{% load i18n %}
-{% block title %}{% trans "Create a new event" %}{% endblock %}
-{% block content %}
- {% trans "Create a new event" %}
- {% if organizers|length == 0 %}
-
- {% trans "You are not permitted to create new events in the name of any organizer." %}
-
- {% else %}
- {% trans "Please choose the organizer of this event from the list below." %}
-
-
-
- | {% trans "Organizer name" %} |
-
-
-
- {% for o in organizers %}
-
- |
- {{ o.name }}
- |
-
- {% endfor %}
-
-
- {% include "pretixcontrol/pagination.html" %}
- {% endif %}
-{% endblock %}
diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py
index fff0f5053..4603c4a15 100644
--- a/src/pretix/control/urls.py
+++ b/src/pretix/control/urls.py
@@ -33,8 +33,7 @@ urlpatterns = [
url(r'^organizers/add$', organizer.OrganizerCreate.as_view(), name='organizers.add'),
url(r'^organizer/(?P[^/]+)/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[^/]+)/add', main.EventCreate.as_view(), name='events.create'),
+ url(r'^events/add$', main.EventWizard.as_view(), name='events.add'),
url(r'^event/(?P[^/]+)/(?P[^/]+)/', include([
url(r'^$', dashboards.event_index, name='event.index'),
url(r'^live/$', event.EventLive.as_view(), name='event.live'),
diff --git a/src/pretix/control/views/main.py b/src/pretix/control/views/main.py
index 0c8795f3d..580f794ed 100644
--- a/src/pretix/control/views/main.py
+++ b/src/pretix/control/views/main.py
@@ -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,
+ }))
diff --git a/src/requirements/production.txt b/src/requirements/production.txt
index 978de2829..0e43d15b3 100644
--- a/src/requirements/production.txt
+++ b/src/requirements/production.txt
@@ -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
diff --git a/src/tests/control/test_permissions.py b/src/tests/control/test_permissions.py
index ff5ee8814..02bb90e0d 100644
--- a/src/tests/control/test_permissions.py
+++ b/src/tests/control/test_permissions.py
@@ -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
+"""