Add a second UI option to clone events

This commit is contained in:
Raphael Michel
2019-02-26 13:07:02 +01:00
parent c278687487
commit b20d1e8373
4 changed files with 133 additions and 4 deletions

View File

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

View File

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

View File

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

View File

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