diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py
index 94e234ad77..400fa07dc3 100644
--- a/src/pretix/base/models/event.py
+++ b/src/pretix/base/models/event.py
@@ -67,7 +67,9 @@ 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 will be used in order codes, invoice numbers, links and bank transfer references."),
+ "We recommend some kind of abbreviation or a date with less than 10 characters that can be easily "
+ "remembered, but you can also choose to use a random value. "
+ "This will be used in URLs, order codes, invoice numbers, and bank transfer references."),
validators=[
RegexValidator(
regex="^[a-zA-Z0-9.-]+$",
diff --git a/src/pretix/control/templates/pretixcontrol/events/create_basics.html b/src/pretix/control/templates/pretixcontrol/events/create_basics.html
index 4af38085d5..cf54d1a79e 100644
--- a/src/pretix/control/templates/pretixcontrol/events/create_basics.html
+++ b/src/pretix/control/templates/pretixcontrol/events/create_basics.html
@@ -5,7 +5,9 @@
{% trans "General information" %}
{% bootstrap_field form.name layout="horizontal" %}
- {% bootstrap_field form.slug layout="horizontal" %}
+ {% trans "Random" as rndlabel %}
+ {% url "control:events.add.slugrng" organizer=organizer.slug as rngurl %}
+ {% bootstrap_field form.slug layout="horizontal" addon_after=''|add:rndlabel|add:' ' addon_after_class='input-group-btn' %}
{% bootstrap_field form.date_from layout="horizontal" %}
{% bootstrap_field form.date_to layout="horizontal" %}
{% bootstrap_field form.location layout="horizontal" %}
diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py
index 24ce890ca0..b6c4daac27 100644
--- a/src/pretix/control/urls.py
+++ b/src/pretix/control/urls.py
@@ -43,6 +43,7 @@ urlpatterns = [
name='organizer.team.edit'),
url(r'^organizer/(?P[^/]+)/team/(?P[^/]+)/delete$', organizer.TeamDeleteView.as_view(),
name='organizer.team.delete'),
+ url(r'^organizer/(?P[^/]+)/slugrng', main.SlugRNG.as_view(), name='events.add.slugrng'),
url(r'^events/$', main.EventList.as_view(), name='events'),
url(r'^events/add$', main.EventWizard.as_view(), name='events.add'),
url(r'^events/typeahead/$', typeahead.event_list, name='events.typeahead'),
diff --git a/src/pretix/control/views/main.py b/src/pretix/control/views/main.py
index e61a414c3b..d5ad490eac 100644
--- a/src/pretix/control/views/main.py
+++ b/src/pretix/control/views/main.py
@@ -2,9 +2,12 @@ from django.conf import settings
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.db import transaction
+from django.http import JsonResponse
from django.shortcuts import redirect
+from django.utils.crypto import get_random_string
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
+from django.views import View
from django.views.generic import ListView
from formtools.wizard.views import SessionWizardView
@@ -13,6 +16,7 @@ from pretix.control.forms.event import (
EventWizardBasicsForm, EventWizardCopyForm, EventWizardFoundationForm,
)
from pretix.control.forms.filter import EventFilterForm
+from pretix.control.permissions import OrganizerPermissionRequiredMixin
class EventList(ListView):
@@ -61,6 +65,8 @@ class EventWizard(SessionWizardView):
def get_context_data(self, form, **kwargs):
ctx = super().get_context_data(form, **kwargs)
ctx['has_organizer'] = self.request.user.teams.filter(can_create_events=True).exists()
+ if self.steps.current == 'basics':
+ ctx['organizer'] = self.get_cleaned_data_for_step('foundation').get('organizer')
return ctx
def get_form_kwargs(self, step=None):
@@ -121,3 +127,16 @@ class EventWizard(SessionWizardView):
'organizer': event.organizer.slug,
'event': event.slug,
}))
+
+
+class SlugRNG(OrganizerPermissionRequiredMixin, View):
+
+ def get(self, request, *args, **kwargs):
+ # See Order.assign_code
+ charset = list('abcdefghjklmnpqrstuvwxyz3789')
+ for i in range(100):
+ val = get_random_string(length=settings.ENTROPY['order_code'], allowed_chars=charset)
+ if not self.request.organizer.events.filter(slug__iexact=val).exists():
+ break
+
+ return JsonResponse({'slug': val})
diff --git a/src/pretix/static/pretixcontrol/js/ui/main.js b/src/pretix/static/pretixcontrol/js/ui/main.js
index 14e995d184..e3ca74085c 100644
--- a/src/pretix/static/pretixcontrol/js/ui/main.js
+++ b/src/pretix/static/pretixcontrol/js/ui/main.js
@@ -102,6 +102,15 @@ $(function () {
question_page_toggle_view();
}
+ // Event wizard
+ $("#event-slug-random-generate").click(function () {
+ var url = $(this).attr("data-rng-url");
+ $("#id_basics-slug").val("Generating...");
+ $.getJSON(url, function (data) {
+ $("#id_basics-slug").val(data.slug);
+ });
+ });
+
// Vouchers
$("#voucher-bulk-codes-generate").click(function () {
var num = $("#voucher-bulk-codes-num").val();
diff --git a/src/pretix/static/pretixcontrol/scss/_forms.scss b/src/pretix/static/pretixcontrol/scss/_forms.scss
index d191d4cfb8..e49a757084 100644
--- a/src/pretix/static/pretixcontrol/scss/_forms.scss
+++ b/src/pretix/static/pretixcontrol/scss/_forms.scss
@@ -151,3 +151,6 @@ pre.mail-preview {
width: 1% !important;
}
}
+.input-group-btn .btn {
+ padding-bottom: 7px;
+}