New event creation wizard

This commit is contained in:
Raphael Michel
2017-01-01 18:44:45 +01:00
parent 47fb61b762
commit e6f731ad77
12 changed files with 182 additions and 183 deletions

View File

@@ -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):
"""

View File

@@ -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',

View File

@@ -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

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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'),

View File

@@ -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,
}))

View File

@@ -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

View File

@@ -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
"""