Event API: Add new clone_from parameter

This commit is contained in:
Raphael Michel
2021-05-25 21:15:18 +02:00
parent 179a450ae5
commit cb42457683
3 changed files with 153 additions and 9 deletions
+9 -1
View File
@@ -80,6 +80,10 @@ Endpoints
The events resource can now be filtered by meta data attributes.
.. versionchanged:: 4.0
The ``clone_from`` parameter has been added to the event creation endpoint.
.. http:get:: /api/v1/organizers/(organizer)/events/
Returns a list of all events within a given organizer the authenticated user/token has access to.
@@ -321,6 +325,9 @@ Endpoints
}
:param organizer: The ``slug`` field of the organizer of the event to create.
:query clone_from: Set to ``event_slug`` to clone data (settings, products, …) from an event with this slug in the
same organizer or to ``organizer_slug/event_slug`` to clone from an event within a different
organizer.
:statuscode 201: no error
:statuscode 400: The event could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
@@ -335,7 +342,8 @@ Endpoints
If the ``plugins``, ``has_subevents`` and/or ``is_public`` fields are present in the post body this will determine their
value. Otherwise their value will be copied from the existing event.
Please note that you can only copy from events under the same organizer.
Please note that you can only copy from events under the same organizer this way. Use the ``clone_from`` parameter
when creating a new event for this instead.
Permission required: "Can create events"
+47 -3
View File
@@ -39,7 +39,7 @@ from django.utils.timezone import now
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import filters, serializers, views, viewsets
from rest_framework.exceptions import PermissionDenied
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.response import Response
from pretix.api.auth.permission import EventCRUDPermission
@@ -120,6 +120,13 @@ class EventViewSet(viewsets.ModelViewSet):
ordering_fields = ('date_from', 'slug')
filterset_class = EventFilter
def get_copy_from_queryset(self):
if isinstance(self.request.auth, (TeamAPIToken, Device)):
return self.request.auth.get_events_with_any_permission()
elif self.request.user.is_authenticated:
return self.request.user.get_events_with_any_permission(self.request)
return Event.objects.none()
def get_queryset(self):
if isinstance(self.request.auth, (TeamAPIToken, Device)):
qs = self.request.auth.get_events_with_any_permission()
@@ -173,8 +180,45 @@ class EventViewSet(viewsets.ModelViewSet):
)
def perform_create(self, serializer):
serializer.save(organizer=self.request.organizer)
serializer.instance.set_defaults()
copy_from = None
if 'clone_from' in self.request.GET:
src = self.request.GET.get('clone_from')
try:
if '/' in src:
copy_from = self.get_copy_from_queryset().get(
organizer__slug=src.split('/')[0],
slug=src.split('/')[1]
)
else:
copy_from = self.get_copy_from_queryset().get(
organizer=self.request.organizer,
slug=src
)
except Event.DoesNotExist:
raise ValidationError('Event to copy from was not found')
print(copy_from, self.request.GET)
new_event = serializer.save(organizer=self.request.organizer)
if copy_from:
new_event.copy_data_from(copy_from)
if 'plugins' in serializer.validated_data:
new_event.set_active_plugins(serializer.validated_data['plugins'])
if 'is_public' in serializer.validated_data:
new_event.is_public = serializer.validated_data['is_public']
if 'testmode' in serializer.validated_data:
new_event.testmode = serializer.validated_data['testmode']
if 'sales_channels' in serializer.validated_data:
new_event.sales_channels = serializer.validated_data['sales_channels']
if 'has_subevents' in serializer.validated_data:
new_event.has_subevents = serializer.validated_data['has_subevents']
new_event.save()
if 'timezone' in serializer.validated_data:
new_event.settings.timezone = serializer.validated_data['timezone']
else:
serializer.instance.set_defaults()
serializer.instance.log_action(
'pretix.event.added',
user=self.request.user,
+97 -5
View File
@@ -40,12 +40,13 @@ from unittest import mock
import pytest
from django.conf import settings
from django.core.files.base import ContentFile
from django.utils.timezone import now
from django_countries.fields import Country
from django_scopes import scopes_disabled
from pytz import UTC
from pretix.base.models import (
Event, InvoiceAddress, Order, OrderPosition, SeatingPlan,
Event, InvoiceAddress, Order, OrderPosition, Organizer, SeatingPlan,
)
from pretix.base.models.orders import OrderFee
from pretix.testutils.mock import mocker_context
@@ -351,9 +352,13 @@ def test_event_create(team, token_client, organizer, event, meta_prop):
@pytest.mark.django_db
def test_event_create_with_clone(token_client, organizer, event, meta_prop):
@pytest.mark.parametrize("urlstyle", [
'/api/v1/organizers/{}/events/{}/clone/',
'/api/v1/organizers/{}/events/?clone_from={}',
])
def test_event_create_with_clone(token_client, organizer, event, meta_prop, urlstyle):
resp = token_client.post(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
urlstyle.format(organizer.slug, event.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
@@ -393,7 +398,7 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop):
assert cloned_event.settings.timezone == "Europe/Vienna"
resp = token_client.post(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
urlstyle.format(organizer.slug, event.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
@@ -425,7 +430,7 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop):
).exists()
resp = token_client.post(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
urlstyle.format(organizer.slug, event.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
@@ -451,6 +456,93 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop):
assert cloned_event.plugins == ""
@pytest.mark.django_db
def test_event_create_with_clone_unknown_source(user, user_client, organizer, event):
with scopes_disabled():
target_org = Organizer.objects.create(name='Dummy', slug='dummy2')
target_org.events.create(slug='bar', name='bar', date_from=now())
resp = user_client.post(
'/api/v1/organizers/{}/events/?clone_from={}/{}'.format(organizer.slug, 'dummy2', 'bar'),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"testmode": True,
"currency": "EUR",
"date_from": "2018-12-27T10:00:00Z",
"date_to": "2018-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2030",
"plugins": [
"pretix.plugins.ticketoutputpdf"
],
"timezone": "Europe/Vienna"
},
format='json'
)
assert resp.status_code == 400
@pytest.mark.django_db
def test_event_create_with_clone_across_organizers(user, user_client, organizer, event, taxrule):
with scopes_disabled():
target_org = Organizer.objects.create(name='Dummy', slug='dummy2')
team = target_org.teams.create(
name="Test-Team",
can_change_teams=True,
can_manage_gift_cards=True,
can_change_items=True,
can_create_events=True,
can_change_event_settings=True,
can_change_vouchers=True,
can_view_vouchers=True,
can_change_orders=True,
can_manage_customers=True,
can_change_organizer_settings=True
)
team.members.add(user)
resp = user_client.post(
'/api/v1/organizers/{}/events/?clone_from={}/{}'.format(target_org.slug, organizer.slug, event.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"testmode": True,
"currency": "EUR",
"date_from": "2018-12-27T10:00:00Z",
"date_to": "2018-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2030",
"plugins": [
"pretix.plugins.ticketoutputpdf"
],
"timezone": "Europe/Vienna"
},
format='json'
)
assert resp.status_code == 201
with scopes_disabled():
cloned_event = Event.objects.get(organizer=target_org.pk, slug='2030')
assert cloned_event.plugins == 'pretix.plugins.ticketoutputpdf'
assert cloned_event.is_public is False
assert cloned_event.testmode
assert cloned_event.settings.timezone == "Europe/Vienna"
assert cloned_event.tax_rules.exists()
@pytest.mark.django_db
def test_event_put_with_clone(token_client, organizer, event, meta_prop):
resp = token_client.put(