mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Add a second UI option to clone events
This commit is contained in:
@@ -90,6 +90,11 @@
|
||||
<span class="fa fa-eraser"></span>
|
||||
{% trans "Delete personal data" %}
|
||||
</a>
|
||||
<a href="{% url "control:events.add" %}?clone={{ request.event.pk }}"
|
||||
class="btn btn-default btn-lg">
|
||||
<span class="fa fa-copy"></span>
|
||||
{% trans "Clone event" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -72,11 +72,13 @@
|
||||
<a href="?{% url_replace request 'ordering' '-sum_tickets_paid' %}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'sum_tickets_paid' %}"><i class="fa fa-caret-up"></i></a>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
<th>
|
||||
{% trans "Status" %}
|
||||
<a href="?{% url_replace request 'ordering' '-live' %}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'live' %}"><i class="fa fa-caret-up"></i></a>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -117,7 +119,7 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<td>
|
||||
{% if not e.live %}
|
||||
<span class="label label-danger">{% trans "Shop disabled" %}</span>
|
||||
{% elif e.presale_has_ended %}
|
||||
@@ -128,6 +130,12 @@
|
||||
<span class="label label-success">{% trans "On sale" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a href="{% url "control:events.add" %}?clone={{ e.pk }}" class="btn btn-sm btn-default"
|
||||
title="{% trans "Clone event" %}" data-toggle="tooltip">
|
||||
<span class="fa fa-copy"></span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.db import transaction
|
||||
from django.db.models import (
|
||||
F, IntegerField, Max, Min, OuterRef, Prefetch, Subquery, Sum,
|
||||
@@ -94,7 +95,10 @@ class EventList(PaginationMixin, ListView):
|
||||
|
||||
|
||||
def condition_copy(wizard):
|
||||
return EventWizardCopyForm.copy_from_queryset(wizard.request.user).exists()
|
||||
return (
|
||||
not wizard.clone_from and
|
||||
EventWizardCopyForm.copy_from_queryset(wizard.request.user).exists()
|
||||
)
|
||||
|
||||
|
||||
class EventWizard(SafeSessionWizardView):
|
||||
@@ -112,6 +116,49 @@ class EventWizard(SafeSessionWizardView):
|
||||
'copy': condition_copy
|
||||
}
|
||||
|
||||
def get_form_initial(self, step):
|
||||
initial = super().get_form_initial(step)
|
||||
if self.clone_from:
|
||||
if step == 'foundation':
|
||||
initial['organizer'] = self.clone_from.organizer
|
||||
initial['locales'] = self.clone_from.settings.locales
|
||||
initial['has_subevents'] = self.clone_from.has_subevents
|
||||
elif step == 'basics':
|
||||
initial['name'] = self.clone_from.name
|
||||
initial['slug'] = self.clone_from.slug + '-2'
|
||||
initial['currency'] = self.clone_from.currency
|
||||
initial['date_from'] = self.clone_from.date_from
|
||||
initial['date_to'] = self.clone_from.date_to
|
||||
initial['presale_start'] = self.clone_from.presale_start
|
||||
initial['presale_end'] = self.clone_from.presale_end
|
||||
initial['location'] = self.clone_from.location
|
||||
initial['timezone'] = self.clone_from.settings.timezone
|
||||
initial['locale'] = self.clone_from.settings.locale
|
||||
if self.clone_from.settings.tax_rate_default:
|
||||
initial['tax_rate'] = self.clone_from.settings.tax_rate_default.rate
|
||||
|
||||
return initial
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.clone_from = None
|
||||
if 'clone' in self.request.GET:
|
||||
try:
|
||||
clone_from = Event.objects.select_related('organizer').get(pk=self.request.GET.get("clone"))
|
||||
except Event.DoesNotExist:
|
||||
allow = False
|
||||
else:
|
||||
allow = (
|
||||
request.user.has_event_permission(clone_from.organizer, clone_from,
|
||||
'can_change_event_settings', request)
|
||||
and request.user.has_event_permission(clone_from.organizer, clone_from,
|
||||
'can_change_items', request)
|
||||
)
|
||||
if not allow:
|
||||
messages.error(self.request, _('You do not have permission to clone this event.'))
|
||||
else:
|
||||
self.clone_from = clone_from
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
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()
|
||||
@@ -193,6 +240,8 @@ class EventWizard(SafeSessionWizardView):
|
||||
if copy_data and copy_data['copy_from_event']:
|
||||
from_event = copy_data['copy_from_event']
|
||||
event.copy_data_from(from_event)
|
||||
elif self.clone_from:
|
||||
event.copy_data_from(self.clone_from)
|
||||
elif event.has_subevents:
|
||||
event.checkin_lists.create(
|
||||
name=str(se),
|
||||
@@ -216,7 +265,7 @@ class EventWizard(SafeSessionWizardView):
|
||||
event.settings.set('locale', basics_data['locale'])
|
||||
event.settings.set('locales', foundation_data['locales'])
|
||||
|
||||
if (copy_data and copy_data['copy_from_event']) or event.has_subevents:
|
||||
if (copy_data and copy_data['copy_from_event']) or self.clone_from or event.has_subevents:
|
||||
return redirect(reverse('control:event.settings', kwargs={
|
||||
'organizer': event.organizer.slug,
|
||||
'event': event.slug,
|
||||
|
||||
@@ -706,6 +706,73 @@ class EventsTest(SoupTest):
|
||||
assert ev.organizer == self.orga1
|
||||
assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'})
|
||||
assert Team.objects.filter(limit_events=ev, members=self.user).exists()
|
||||
assert ev.items.count() == 1
|
||||
|
||||
berlin_tz = timezone('Europe/Berlin')
|
||||
assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc)
|
||||
assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc)
|
||||
assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc)
|
||||
assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc)
|
||||
|
||||
assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1
|
||||
|
||||
def test_create_event_clone_success(self):
|
||||
tr = self.event1.tax_rules.create(
|
||||
rate=19, name="VAT"
|
||||
)
|
||||
self.event1.items.create(
|
||||
name='Early-bird ticket',
|
||||
category=None, default_price=23, tax_rule=tr,
|
||||
admission=True
|
||||
)
|
||||
self.event1.settings.tax_rate_default = tr
|
||||
doc = self.get_doc('/control/events/add?clone=' + str(self.event1.pk))
|
||||
tabletext = doc.select("form")[0].text
|
||||
self.assertIn("CCC", tabletext)
|
||||
self.assertNotIn("MRM", tabletext)
|
||||
|
||||
doc = self.post_doc('/control/events/add?clone=' + str(self.event1.pk), {
|
||||
'event_wizard-current_step': 'foundation',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'foundation-organizer': self.orga1.pk,
|
||||
'foundation-locales': ('en', 'de')
|
||||
})
|
||||
assert doc.select("#id_basics-date_from_0")[0]['value'] == '2013-12-26'
|
||||
|
||||
doc = self.post_doc('/control/events/add?clone=' + str(self.event1.pk), {
|
||||
'event_wizard-current_step': 'basics',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'basics-name_0': '33C3',
|
||||
'basics-name_1': '33C3',
|
||||
'basics-slug': '33c3',
|
||||
'basics-date_from_0': '2016-12-27',
|
||||
'basics-date_from_1': '10:00:00',
|
||||
'basics-date_to_0': '2016-12-30',
|
||||
'basics-date_to_1': '19:00:00',
|
||||
'basics-location_0': 'Hamburg',
|
||||
'basics-location_1': 'Hamburg',
|
||||
'basics-currency': 'EUR',
|
||||
'basics-tax_rate': '19.00',
|
||||
'basics-locale': 'en',
|
||||
'basics-timezone': 'Europe/Berlin',
|
||||
'basics-presale_start_0': '2016-11-01',
|
||||
'basics-presale_start_1': '10:00:00',
|
||||
'basics-presale_end_0': '2016-11-30',
|
||||
'basics-presale_end_1': '18:00:00',
|
||||
})
|
||||
|
||||
assert not doc.select("#id_copy-copy_from_event_1")
|
||||
|
||||
ev = Event.objects.get(slug='33c3')
|
||||
assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'})
|
||||
assert ev.settings.locales == ['en', 'de']
|
||||
assert ev.settings.locale == 'en'
|
||||
assert ev.currency == 'EUR'
|
||||
assert ev.settings.timezone == 'Europe/Berlin'
|
||||
assert ev.organizer == self.orga1
|
||||
assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'})
|
||||
assert Team.objects.filter(limit_events=ev, members=self.user).exists()
|
||||
assert ev.items.count() == 1
|
||||
|
||||
berlin_tz = timezone('Europe/Berlin')
|
||||
assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc)
|
||||
|
||||
Reference in New Issue
Block a user