Files
pretix_original/src/tests/api/test_events.py
2021-09-15 16:28:57 +02:00

1415 lines
46 KiB
Python

#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Tobias Kunze, Ture Gjørup, pajowu
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
import copy
from datetime import datetime
from decimal import Decimal
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, Organizer, SeatingPlan,
)
from pretix.base.models.orders import OrderFee
from pretix.testutils.mock import mocker_context
@pytest.fixture
def variations(item):
v = []
v.append(item.variations.create(value="ChildA1"))
v.append(item.variations.create(value="ChildA2"))
return v
@pytest.fixture
def order(event, item, taxrule):
testtime = datetime(2017, 12, 1, 10, 0, 0, tzinfo=UTC)
with mock.patch('django.utils.timezone.now') as mock_now:
mock_now.return_value = testtime
o = Order.objects.create(
code='FOO', event=event, email='dummy@dummy.test',
status=Order.STATUS_PENDING, secret="k24fiuwvu8kxz3y1",
datetime=datetime(2017, 12, 1, 10, 0, 0, tzinfo=UTC),
expires=datetime(2017, 12, 10, 10, 0, 0, tzinfo=UTC),
total=23, locale='en'
)
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
tax_value=Decimal('0.05'), tax_rule=taxrule)
InvoiceAddress.objects.create(order=o, company="Sample company", country=Country('NZ'))
return o
@pytest.fixture
def order_position(item, order, taxrule, variations):
op = OrderPosition.objects.create(
order=order,
item=item,
variation=variations[0],
tax_rule=taxrule,
tax_rate=taxrule.rate,
tax_value=Decimal("3"),
price=Decimal("23"),
attendee_name_parts={'full_name': "Peter"},
secret="z3fsn8jyufm5kpk768q69gkbyr5f4h6w"
)
return op
TEST_EVENT_RES = {
"name": {"en": "Dummy"},
"live": False,
"testmode": False,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": None,
"date_admission": None,
"is_public": True,
"presale_start": None,
"presale_end": None,
"location": None,
"geo_lat": None,
"geo_lon": None,
"slug": "dummy",
"has_subevents": False,
"seating_plan": None,
"seat_category_mapping": {},
"meta_data": {"type": "Conference"},
'timezone': 'Europe/Berlin',
'plugins': [
'pretix.plugins.banktransfer',
'pretix.plugins.ticketoutputpdf'
],
'item_meta_properties': {
'day': 'Monday',
},
'sales_channels': ['web', 'bar', 'baz']
}
@pytest.fixture
def item(event):
return event.items.create(name="Budget Ticket", default_price=23)
@pytest.fixture
def free_item(event):
return event.items.create(name="Free Ticket", default_price=0)
@pytest.fixture
def free_quota(event, free_item):
q = event.quotas.create(name="Budget Quota", size=200)
q.items.add(free_item)
return q
@pytest.mark.django_db
def test_event_list(token_client, organizer, event):
resp = token_client.get('/api/v1/organizers/{}/events/'.format(organizer.slug))
assert resp.status_code == 200
assert TEST_EVENT_RES == resp.data['results'][0]
resp = token_client.get('/api/v1/organizers/{}/events/?live=true'.format(organizer.slug))
assert resp.status_code == 200
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?live=false'.format(organizer.slug))
assert resp.status_code == 200
assert [TEST_EVENT_RES] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?is_public=false'.format(organizer.slug))
assert resp.status_code == 200
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?is_public=true'.format(organizer.slug))
assert resp.status_code == 200
assert [TEST_EVENT_RES] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?has_subevents=true'.format(organizer.slug))
assert resp.status_code == 200
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?has_subevents=false'.format(organizer.slug))
assert resp.status_code == 200
assert [TEST_EVENT_RES] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?ends_after=2017-12-27T10:01:00Z'.format(organizer.slug))
assert resp.status_code == 200
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?ends_after=2017-12-27T09:59:59Z'.format(organizer.slug))
assert resp.status_code == 200
assert [TEST_EVENT_RES] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/?with_availability_for=web'.format(organizer.slug))
assert resp.status_code == 200
assert resp.data['results'][0]['best_availability_state'] is None
@pytest.mark.django_db
def test_event_list_filter(token_client, organizer, event):
resp = token_client.get('/api/v1/organizers/{}/events/?attr[type]=Conference'.format(organizer.slug))
assert resp.status_code == 200
assert resp.data['count'] == 1
resp = token_client.get('/api/v1/organizers/{}/events/?attr[type]='.format(organizer.slug))
assert resp.status_code == 200
assert resp.data['count'] == 0
@pytest.mark.django_db
def test_event_list_name_filter(token_client, organizer, event):
resp = token_client.get('/api/v1/organizers/{}/events/?search=Dummy'.format(organizer.slug))
assert resp.status_code == 200
assert resp.data['count'] == 1
resp = token_client.get('/api/v1/organizers/{}/events/?search=notdummy'.format(organizer.slug))
assert resp.status_code == 200
assert resp.data['count'] == 0
@pytest.mark.django_db
def test_event_get(token_client, organizer, event):
resp = token_client.get('/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug))
res = copy.copy(TEST_EVENT_RES)
res["valid_keys"] = {"pretix_sig1": []}
assert resp.status_code == 200
assert res == resp.data
@pytest.mark.django_db
def test_event_create(team, token_client, organizer, event, meta_prop):
meta_prop.allowed_values = "Conference\nWorkshop"
meta_prop.save()
team.can_change_organizer_settings = False
team.save()
organizer.meta_properties.create(
name="protected", protected=True
)
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2030",
"meta_data": {
meta_prop.name: "Conference",
"protected": "ignored",
},
"seat_category_mapping": {},
"timezone": "Europe/Amsterdam"
},
format='json'
)
assert resp.status_code == 201
with scopes_disabled():
assert not organizer.events.get(slug="2030").testmode
assert organizer.events.get(slug="2030").meta_values.filter(
property__name=meta_prop.name, value="Conference"
).exists()
assert not organizer.events.get(slug="2030").meta_values.filter(
property__name="protected"
).exists()
assert organizer.events.get(slug="2030").plugins == settings.PRETIX_PLUGINS_DEFAULT
assert organizer.events.get(slug="2030").settings.timezone == "Europe/Amsterdam"
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2020",
"meta_data": {
"foo": "bar"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"meta_data":["Meta data property \'foo\' does not exist."]}'
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2020",
"meta_data": {
meta_prop.name: "bar"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"meta_data":["Meta data property \'type\' does not allow value \'bar\'."]}'
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": event.slug,
"meta_data": {
"type": "Conference"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"slug":["This slug has already been used for a different event."]}'
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": True,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2031",
"meta_data": {
"type": "Conference"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"live":["Events cannot be created as \'live\'. Quotas and payment must be added ' \
'to the event before sales can go live."]}'
@pytest.mark.django_db
@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(
urlstyle.format(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",
"meta_data": {
"type": "Conference"
},
"plugins": [
"pretix.plugins.ticketoutputpdf"
],
"timezone": "Europe/Vienna"
},
format='json'
)
assert resp.status_code == 201
with scopes_disabled():
cloned_event = Event.objects.get(organizer=organizer.pk, slug='2030')
assert cloned_event.plugins == 'pretix.plugins.ticketoutputpdf'
assert cloned_event.is_public is False
assert cloned_event.testmode
assert organizer.events.get(slug="2030").meta_values.filter(
property__name=meta_prop.name, value="Conference"
).exists()
assert cloned_event.settings.timezone == "Europe/Vienna"
resp = token_client.post(
urlstyle.format(organizer.slug, event.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2018-12-27T10:00:00Z",
"date_to": "2018-12-28T10:00:00Z",
"date_admission": None,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2031",
"meta_data": {
"type": "Conference"
}
},
format='json'
)
assert resp.status_code == 201
with scopes_disabled():
cloned_event = Event.objects.get(organizer=organizer.pk, slug='2031')
assert cloned_event.plugins == "pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf"
assert cloned_event.is_public is True
assert organizer.events.get(slug="2031").meta_values.filter(
property__name=meta_prop.name, value="Conference"
).exists()
resp = token_client.post(
urlstyle.format(organizer.slug, event.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2018-12-27T10:00:00Z",
"date_to": "2018-12-28T10:00:00Z",
"date_admission": None,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2032",
"plugins": []
},
format='json'
)
assert resp.status_code == 201
with scopes_disabled():
cloned_event = Event.objects.get(organizer=organizer.pk, slug='2032')
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(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
{},
format='json'
)
assert resp.status_code == 405
@pytest.mark.django_db
def test_event_patch_with_clone(token_client, organizer, event, meta_prop):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
{},
format='json'
)
assert resp.status_code == 405
@pytest.mark.django_db
def test_event_delete_with_clone(token_client, organizer, event, meta_prop):
resp = token_client.delete(
'/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug),
{},
format='json'
)
assert resp.status_code == 405
@pytest.mark.django_db
def test_event_update(token_client, organizer, event, item, meta_prop):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"date_from": "2018-12-27T10:00:00Z",
"date_to": "2018-12-28T10:00:00Z",
"currency": "DKK",
},
format='json'
)
assert resp.status_code == 200
with scopes_disabled():
event = Event.objects.get(organizer=organizer.pk, slug=resp.data['slug'])
assert event.currency == "DKK"
assert organizer.events.get(slug=resp.data['slug']).meta_values.filter(
property__name=meta_prop.name, value="Conference"
).exists()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-26T10:00:00Z"
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"non_field_errors":["The event cannot end before it starts."]}'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"presale_start": "2017-12-27T10:00:00Z",
"presale_end": "2017-12-26T10:00:00Z"
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"non_field_errors":["The event\'s presale cannot end before it starts."]}'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"slug": "testing"
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"slug":["The event slug cannot be changed."]}'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"has_subevents": True
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"has_subevents":["Once created an event cannot change between an series and a ' \
'single event."]}'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"meta_data": {
meta_prop.name: "Workshop"
}
},
format='json'
)
assert resp.status_code == 200
with scopes_disabled():
assert organizer.events.get(slug=resp.data['slug']).meta_values.filter(
property__name=meta_prop.name, value="Workshop"
).exists()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"meta_data": {
}
},
format='json'
)
assert resp.status_code == 200
with scopes_disabled():
assert not organizer.events.get(slug=resp.data['slug']).meta_values.filter(
property__name=meta_prop.name
).exists()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"meta_data": {
"test": "test"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"meta_data":["Meta data property \'test\' does not exist."]}'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"item_meta_properties": {
"Foo": "Bar"
}
},
format='json'
)
assert resp.status_code == 200
with scopes_disabled():
assert organizer.events.get(slug=resp.data['slug']).item_meta_properties.filter(
name="Foo", default="Bar"
).exists()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"item_meta_properties": {
}
},
format='json'
)
assert resp.status_code == 200
with scopes_disabled():
assert not organizer.events.get(slug=resp.data['slug']).item_meta_properties.filter(
name="Foo"
).exists()
@pytest.mark.django_db
def test_event_test_mode(token_client, organizer, event):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"testmode": True
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.testmode
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"testmode": False
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert not event.testmode
@pytest.mark.django_db
def test_event_update_live_no_product(token_client, organizer, event):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"live": True
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"live":["You need to configure at least one quota to sell anything."]}'
@pytest.mark.django_db
def test_event_update_live_no_payment_method(token_client, organizer, event, item, free_quota):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"live": True
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"live":["You have configured at least one paid product but have not enabled any ' \
'payment methods."]}'
@pytest.mark.django_db
def test_event_update_live_free_product(token_client, organizer, event, free_item, free_quota):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"live": True
},
format='json'
)
assert resp.status_code == 200
@pytest.mark.django_db
def test_event_update_plugins(token_client, organizer, event, free_item, free_quota):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": [
"pretix.plugins.ticketoutputpdf",
]
},
format='json'
)
assert resp.status_code == 200
assert set(resp.data.get('plugins')) == {
"pretix.plugins.ticketoutputpdf",
}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": {
"pretix.plugins.banktransfer"
}
},
format='json'
)
assert resp.status_code == 200
assert resp.data.get('plugins') == [
"pretix.plugins.banktransfer"
]
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": {
"pretix.plugins.test"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"plugins":["Unknown plugin: \'pretix.plugins.test\'."]}'
@pytest.mark.django_db
def test_event_delete(token_client, organizer, event):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug))
assert resp.status_code == 204
with scopes_disabled():
assert not organizer.events.filter(pk=event.id).exists()
@pytest.mark.django_db
def test_event_with_order_position_not_delete(token_client, organizer, event, item, order_position):
resp = token_client.delete('/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug))
assert resp.status_code == 403
assert resp.content.decode() == '{"detail":"The event can not be deleted as it already contains orders. Please ' \
'set \'live\' to false to hide the event and take the shop offline instead."}'
with scopes_disabled():
assert organizer.events.filter(pk=event.id).exists()
@pytest.fixture
def seatingplan(event, organizer, item):
return SeatingPlan.objects.create(
name="Plan", organizer=organizer, layout="""{
"name": "Grosser Saal",
"categories": [
{
"name": "Stalls",
"color": "red"
}
],
"zones": [
{
"name": "Main Area",
"position": {
"x": 0,
"y": 0
},
"rows": [
{
"row_number": "0",
"seats": [
{
"seat_guid": "0-0",
"seat_number": "0-0",
"position": {
"x": 0,
"y": 0
},
"category": "Stalls"
},
{
"seat_guid": "0-1",
"seat_number": "0-1",
"position": {
"x": 33,
"y": 0
},
"category": "Stalls"
},
{
"seat_guid": "0-2",
"seat_number": "0-2",
"position": {
"x": 66,
"y": 0
},
"category": "Stalls"
}
],
"position": {
"x": 0,
"y": 0
}
}
]
}
],
"size": {
"width": 600,
"height": 400
}
}"""
)
@pytest.mark.django_db
def test_event_update_seating(token_client, organizer, event, item, seatingplan):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Stalls": item.pk
}
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.seating_plan == seatingplan
with scopes_disabled():
assert event.seats.count() == 3
assert event.seats.filter(product=item).count() == 3
m = event.seat_category_mappings.get()
assert m.layout_category == 'Stalls'
assert m.product == item
@pytest.mark.django_db
def test_event_update_seating_invalid_product(token_client, organizer, event, item, seatingplan):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Stalls": item.pk + 2
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"seat_category_mapping":["Item \'%d\' does not exist."]}' % (item.pk + 2)
@pytest.mark.django_db
def test_event_update_seating_change_mapping(token_client, organizer, event, item, seatingplan):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Stalls": item.pk
}
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.seating_plan == seatingplan
with scopes_disabled():
assert event.seats.count() == 3
assert event.seats.filter(product=item).count() == 3
m = event.seat_category_mappings.get()
assert m.layout_category == 'Stalls'
assert m.product == item
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seat_category_mapping": {
"VIP": item.pk,
}
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.seating_plan == seatingplan
with scopes_disabled():
assert event.seats.count() == 3
m = event.seat_category_mappings.get()
assert event.seats.filter(product=None).count() == 3
assert m.layout_category == 'VIP'
assert m.product == item
@pytest.mark.django_db
def test_remove_seating(token_client, organizer, event, item, seatingplan):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Stalls": item.pk
}
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.seating_plan == seatingplan
with scopes_disabled():
assert event.seats.count() == 3
assert event.seat_category_mappings.count() == 1
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": None
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.seating_plan is None
with scopes_disabled():
assert event.seats.count() == 0
assert event.seat_category_mappings.count() == 0
@pytest.mark.django_db
def test_remove_seating_forbidden(token_client, organizer, event, item, seatingplan, order_position):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Stalls": item.pk
}
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.seating_plan == seatingplan
with scopes_disabled():
assert event.seats.count() == 3
assert event.seat_category_mappings.count() == 1
order_position.seat = event.seats.first()
order_position.save()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": None
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"seating_plan":["You can not change the plan since seat \\"0-0\\" is not ' \
'present in the new plan and is already sold."]}'
@pytest.mark.django_db
def test_remove_seating_canceled_seat(token_client, organizer, event, item, seatingplan, order_position):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Stalls": item.pk
}
},
format='json'
)
assert resp.status_code == 200
event.refresh_from_db()
assert event.seating_plan == seatingplan
with scopes_disabled():
assert event.seats.count() == 3
assert event.seat_category_mappings.count() == 1
order_position.seat = event.seats.first()
order_position.canceled = True
order_position.save()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": None
},
format='json'
)
assert resp.status_code == 200
order_position.refresh_from_db()
assert order_position.seat is None
@pytest.mark.django_db
def test_no_seating_for_series(token_client, organizer, event, item, seatingplan, order_position):
event.has_subevents = True
event.save()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Stalls": item.pk
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"non_field_errors":["Event series should not directly be assigned a seating plan."]}'
@pytest.mark.django_db
def test_event_create_with_seating(token_client, organizer, event, meta_prop, seatingplan):
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2030",
"seating_plan": seatingplan.pk,
"meta_data": {
meta_prop.name: "Conference"
}
},
format='json'
)
assert resp.status_code == 201
with scopes_disabled():
event = Event.objects.get(slug=resp.data['slug'])
assert event.seating_plan == seatingplan
assert event.seats.count() == 3
assert event.seat_category_mappings.count() == 0
@pytest.mark.django_db
def test_event_create_with_seating_maps(token_client, organizer, event, meta_prop, seatingplan):
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "2017-12-27T10:00:00Z",
"date_to": "2017-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "2030",
"seating_plan": seatingplan.pk,
"seat_category_mapping": {
"Foo": 1,
},
"meta_data": {
meta_prop.name: "Conference"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"seat_category_mapping":["You cannot specify seat category mappings on event creation."]}'
@pytest.mark.django_db
def test_get_event_settings(token_client, organizer, event):
event.settings.imprint_url = "https://example.org"
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
)
assert resp.status_code == 200
assert resp.data['imprint_url'] == "https://example.org"
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/settings/?explain=true'.format(organizer.slug, event.slug),
)
assert resp.status_code == 200
assert resp.data['imprint_url'] == {
"value": "https://example.org",
"label": "Imprint URL",
"help_text": "This should point e.g. to a part of your website that has your contact details and legal "
"information."
}
@pytest.mark.django_db
def test_patch_event_settings(token_client, organizer, event):
with mocker_context() as mocker:
mocked = mocker.patch('pretix.presale.style.regenerate_css.apply_async')
organizer.settings.imprint_url = 'https://example.org'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'imprint_url': 'https://example.com',
'confirm_texts': [
{
'de': 'Ich bin mit den AGB einverstanden.'
}
]
},
format='json'
)
assert resp.status_code == 200
assert resp.data['imprint_url'] == "https://example.com"
event.settings.flush()
assert event.settings.imprint_url == 'https://example.com'
mocked.assert_not_called()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'primary_color': '#ff0000',
'theme_color_background': '#ff0000',
},
format='json'
)
assert resp.status_code == 200
event.settings.flush()
mocked.assert_any_call(args=(event.pk,))
assert event.settings.primary_color == '#ff0000'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'primary_color': None,
'theme_color_background': None,
},
format='json'
)
assert resp.status_code == 200
event.settings.flush()
assert event.settings.primary_color != '#ff0000'
assert 'primary_color' not in event.settings._cache()
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'imprint_url': None,
},
format='json'
)
assert resp.status_code == 200
assert resp.data['imprint_url'] == "https://example.org"
event.settings.flush()
assert event.settings.imprint_url == 'https://example.org'
resp = token_client.put(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'imprint_url': 'invalid'
},
format='json'
)
assert resp.status_code == 405
locales = event.settings.locales
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'locales': event.settings.locales + ['de', 'de-informal'],
},
format='json'
)
assert resp.status_code == 200
assert set(resp.data['locales']) == set(locales + ['de', 'de-informal'])
event.settings.flush()
assert set(event.settings.locales) == set(locales + ['de', 'de-informal'])
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'locales': locales,
},
format='json'
)
assert resp.status_code == 200
assert set(resp.data['locales']) == set(locales)
event.settings.flush()
assert set(event.settings.locales) == set(locales)
@pytest.mark.django_db
def test_patch_event_settings_validation(token_client, organizer, event):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'imprint_url': 'invalid'
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {
'imprint_url': ['Enter a valid URL.']
}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'invoice_address_required': True,
'invoice_address_asked': False,
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {
'invoice_address_required': ['You have to ask for invoice addresses if you want to make them required.']
}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'cancel_allow_user_until': 'RELDATE/3/12:00/foobar/',
'invoice_address_asked': False,
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {
'cancel_allow_user_until': ['Invalid relative date']
}
@pytest.mark.django_db
def test_patch_event_settings_file(token_client, organizer, event):
r = token_client.post(
'/api/v1/upload',
data={
'media_type': 'image/png',
'file': ContentFile('file.png', 'invalid png content')
},
format='upload',
HTTP_CONTENT_DISPOSITION='attachment; filename="file.png"',
)
assert r.status_code == 201
file_id_png = r.data['id']
r = token_client.post(
'/api/v1/upload',
data={
'media_type': 'application/pdf',
'file': ContentFile('file.pdf', 'invalid pdf content')
},
format='upload',
HTTP_CONTENT_DISPOSITION='attachment; filename="file.pdf"',
)
assert r.status_code == 201
file_id_pdf = r.data['id']
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'logo_image': 'invalid'
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {
'logo_image': ['The submitted file ID was not found.']
}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'logo_image': file_id_pdf
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {
'logo_image': ['The submitted file has a file type that is not allowed in this field.']
}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'logo_image': file_id_png
},
format='json'
)
assert resp.status_code == 200
assert resp.data['logo_image'].startswith('http')
assert '/pub/' in resp.data['logo_image']
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
{
'logo_image': None
},
format='json'
)
assert resp.status_code == 200
assert resp.data['logo_image'] is None