mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Pluggable permissions (#5728)
* Data model draft * Refactor query and assignment usages of old permissions * Backend UI * API serializer * Big string replace * Docs, tests and fixes for teams api * Update docs for device auth * Eliminate old names * Make tests pass * Use new permissions, remove inconsistencies * Add test for translations * Show plugin permissions * Add permission for seating plans * Fix plugin activation * Fix failing test * Refactor to permission groups * Update doc/api/resources/devices.rst Co-authored-by: luelista <weller@rami.io> * Update doc/api/resources/events.rst Co-authored-by: luelista <weller@rami.io> * Update src/pretix/api/serializers/organizer.py Co-authored-by: luelista <weller@rami.io> * Fix typo * Fix python version compat * Replacement after rebase * Add proper permission handling for exports * Docs for exporters * Runtime linting of permission names * Fix typos * Show export page even without orders permission * More legacy compat * Do not strongly validate before plugins are loaded * Rebase migration * Add permission for outgoing mails * Review notes * Update doc/api/resources/teams.rst Co-authored-by: Richard Schreiber <schreiber@pretix.eu> * Clean up logic around exporters * Review and failures * Fix migration leading to forbidden combination * Handle permissions on event copying * Remove print-statements * Make test clearer * Review feedback * Add AnyPermissionOf * migration safety --------- Co-authored-by: luelista <weller@rami.io> Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
This commit is contained in:
@@ -106,17 +106,8 @@ def team(organizer):
|
||||
return Team.objects.create(
|
||||
organizer=organizer,
|
||||
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_manage_reusable_media=True,
|
||||
can_change_organizer_settings=True
|
||||
all_event_permissions=True,
|
||||
all_organizer_permissions=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -140,8 +131,9 @@ def user():
|
||||
@pytest.fixture
|
||||
@scopes_disabled()
|
||||
def user_client(client, team, user):
|
||||
team.can_view_orders = True
|
||||
team.can_view_vouchers = True
|
||||
if not team.all_event_permissions:
|
||||
team.limit_event_permissions["event.orders:read"] = True
|
||||
team.limit_event_permissions["event.vouchers:read"] = True
|
||||
team.all_events = True
|
||||
team.save()
|
||||
team.members.add(user)
|
||||
@@ -152,8 +144,9 @@ def user_client(client, team, user):
|
||||
@pytest.fixture
|
||||
@scopes_disabled()
|
||||
def token_client(client, team):
|
||||
team.can_view_orders = True
|
||||
team.can_view_vouchers = True
|
||||
if not team.all_event_permissions:
|
||||
team.limit_event_permissions["event.orders:read"] = True
|
||||
team.limit_event_permissions["event.vouchers:read"] = True
|
||||
team.all_events = True
|
||||
team.save()
|
||||
t = team.tokens.create(name='Foo')
|
||||
|
||||
@@ -1382,9 +1382,8 @@ def test_checkin_pdf_data_requires_permission(token_client, event, team, organiz
|
||||
))
|
||||
assert resp.data['results'][0].get('pdf_data')
|
||||
with scopes_disabled():
|
||||
team.can_view_orders = False
|
||||
team.can_change_orders = False
|
||||
team.can_checkin_orders = True
|
||||
team.limit_event_permissions = {"event.orders:checkin": True}
|
||||
team.all_event_permissions = False
|
||||
team.save()
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?search=z3fsn8jyu&pdf_data=true'.format(
|
||||
organizer.slug, event.slug, clist_all.pk
|
||||
|
||||
@@ -984,9 +984,8 @@ def test_search_multiple_lists(token_client, organizer, clist_all, clist_event2,
|
||||
@pytest.mark.django_db
|
||||
def test_without_permission(token_client, event, team, organizer, clist_all, order):
|
||||
with scopes_disabled():
|
||||
team.can_view_orders = False
|
||||
team.can_change_orders = False
|
||||
team.can_checkin_orders = False
|
||||
team.limit_event_permissions = {}
|
||||
team.all_event_permissions = False
|
||||
team.save()
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/checkinrpc/search/?list={}&search=dummy.test&ordering=attendee_name'.format(organizer.slug, clist_all.pk))
|
||||
@@ -1043,9 +1042,8 @@ def test_checkin_only_permission(token_client, event, team, organizer, clist_all
|
||||
assert resp.data['position'].get('pdf_data')
|
||||
|
||||
with scopes_disabled():
|
||||
team.can_view_orders = False
|
||||
team.can_change_orders = False
|
||||
team.can_checkin_orders = True
|
||||
team.limit_event_permissions = {"event.orders:checkin": True}
|
||||
team.all_event_permissions = False
|
||||
team.save()
|
||||
|
||||
# With limited permissions, I can not search with a 2-character query
|
||||
|
||||
@@ -243,7 +243,8 @@ def test_event_create(team, token_client, organizer, event, meta_prop):
|
||||
{"key": "Workshop", "label": {"en": "Workshop"}},
|
||||
]
|
||||
meta_prop.save()
|
||||
team.can_change_organizer_settings = False
|
||||
team.limit_organizer_permissions = {"organizer.events:create": True}
|
||||
team.all_organizer_permissions = False
|
||||
team.save()
|
||||
organizer.meta_properties.create(
|
||||
name="protected", protected=True
|
||||
@@ -576,21 +577,15 @@ def test_event_create_with_clone_unknown_source(user, user_client, organizer, ev
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_event_create_with_clone_across_organizers(user, user_client, organizer, event, taxrule):
|
||||
def test_event_create_with_clone_across_organizers(user, user_client, organizer, event, taxrule, team):
|
||||
team.all_event_permissions = True
|
||||
team.save()
|
||||
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
|
||||
all_event_permissions=True,
|
||||
all_organizer_permissions=True,
|
||||
)
|
||||
team.members.add(user)
|
||||
|
||||
@@ -629,6 +624,51 @@ def test_event_create_with_clone_across_organizers(user, user_client, organizer,
|
||||
assert cloned_event.tax_rules.exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_event_create_with_clone_across_organizers_lack_of_permission_on_source(user, user_client, team, organizer, event, taxrule):
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions = {
|
||||
"event.settings.general:write": True,
|
||||
}
|
||||
team.save()
|
||||
with scopes_disabled():
|
||||
target_org = Organizer.objects.create(name='Dummy', slug='dummy2')
|
||||
team = target_org.teams.create(
|
||||
name="Test-Team",
|
||||
all_event_permissions=True,
|
||||
all_organizer_permissions=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 == 403
|
||||
assert resp.data["detail"] == "Not sufficient permission on source event to copy"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_event_put_with_clone(token_client, organizer, event, meta_prop):
|
||||
resp = token_client.put(
|
||||
@@ -1394,7 +1434,14 @@ def test_get_event_settings(token_client, organizer, event):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_patch_event_settings(token_client, organizer, event):
|
||||
def test_patch_event_settings(token_client, organizer, event, team):
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions = {
|
||||
"event.settings.general:write": True,
|
||||
"event.settings.tax:write": True,
|
||||
}
|
||||
team.save()
|
||||
|
||||
organizer.settings.imprint_url = 'https://example.org'
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
|
||||
@@ -1510,6 +1557,29 @@ def test_patch_event_settings(token_client, organizer, event):
|
||||
event.settings.flush()
|
||||
assert set(event.settings.locales) == set(locales)
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
'display_net_prices': True,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
event.settings.flush()
|
||||
assert event.settings.display_net_prices
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
'invoice_address_asked': False,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {
|
||||
'invoice_address_asked': ['Setting this field requires permission event.settings.invoicing:write']
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_patch_event_settings_validation(token_client, organizer, event):
|
||||
|
||||
@@ -39,8 +39,11 @@ from datetime import time
|
||||
|
||||
import pytest
|
||||
from django.utils.timezone import now
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from pretix.base.models import CachedFile, User
|
||||
from pretix.base.models import (
|
||||
CachedFile, Event, ScheduledEventExport, ScheduledOrganizerExport, User,
|
||||
)
|
||||
|
||||
SAMPLE_EXPORTER_CONFIG = {
|
||||
"identifier": "orderlist",
|
||||
@@ -111,6 +114,10 @@ def test_org_list(token_client, organizer, event):
|
||||
"name": "events",
|
||||
"required": False
|
||||
})
|
||||
c['input_parameters'].insert(0, {
|
||||
"name": "all_events",
|
||||
"required": False
|
||||
})
|
||||
c['input_parameters'].remove({
|
||||
"name": "items",
|
||||
"required": False
|
||||
@@ -144,13 +151,6 @@ def test_org_validate_events(token_client, organizer, team, event):
|
||||
}, format='json')
|
||||
assert resp.status_code == 202
|
||||
|
||||
resp = token_client.post('/api/v1/organizers/{}/exporters/orderlist/run/'.format(organizer.slug), data={
|
||||
'_format': 'xlsx',
|
||||
'events': []
|
||||
}, format='json')
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"events": ["This list may not be empty."]}
|
||||
|
||||
resp = token_client.post('/api/v1/organizers/{}/exporters/orderlist/run/'.format(organizer.slug), data={
|
||||
'_format': 'xlsx',
|
||||
'events': ["nonexisting"]
|
||||
@@ -280,7 +280,8 @@ def test_org_level_export(token_client, organizer, team, event):
|
||||
}, format='json')
|
||||
assert resp.status_code == 202
|
||||
|
||||
team.can_manage_gift_cards = False
|
||||
team.limit_organizer_permissions = {"organizer.events:create": True}
|
||||
team.all_organizer_permissions = False
|
||||
team.save()
|
||||
|
||||
resp = token_client.post('/api/v1/organizers/{}/exporters/giftcardlist/run/'.format(organizer.slug), data={
|
||||
@@ -339,10 +340,12 @@ def test_event_scheduled_export_list_token(token_client, organizer, event, user,
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
team.can_change_event_settings = False
|
||||
team.limit_organizer_permissions = {"organizer.events:create": True}
|
||||
team.all_organizer_permissions = False
|
||||
team.all_event_permissions = False
|
||||
team.save()
|
||||
|
||||
# Token can no longer sees it an gets error message
|
||||
# Token can no longer sees it and gets error message
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/scheduled_exports/'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 403
|
||||
|
||||
@@ -361,7 +364,9 @@ def test_event_scheduled_export_list_user(user_client, organizer, event, user, t
|
||||
resp = user_client.get('/api/v1/organizers/{}/events/{}/scheduled_exports/'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
team.can_change_event_settings = False
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_event_permissions = {"event.orders:read": True}
|
||||
team.all_event_permissions = False
|
||||
team.save()
|
||||
|
||||
# Owner still can
|
||||
@@ -498,7 +503,8 @@ def test_org_scheduled_export_list_token(token_client, organizer, user, team, or
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
team.can_change_organizer_settings = False
|
||||
team.limit_organizer_permissions = {"organizer.events:create": True}
|
||||
team.all_organizer_permissions = False
|
||||
team.save()
|
||||
|
||||
# Token can no longer sees it an gets error message
|
||||
@@ -521,7 +527,8 @@ def test_org_scheduled_export_list_user(user_client, organizer, user, team, org_
|
||||
resp = user_client.get('/api/v1/organizers/{}/scheduled_exports/'.format(organizer.slug))
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
team.can_change_organizer_settings = False
|
||||
team.limit_organizer_permissions = {"organizer.events:create": True}
|
||||
team.all_organizer_permissions = False
|
||||
team.save()
|
||||
|
||||
# Owner still can
|
||||
@@ -817,3 +824,254 @@ def test_org_scheduled_export_validate_rrule(user_client, organizer, user):
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"schedule_rrule": ["BYEASTER not supported"]}
|
||||
|
||||
|
||||
def _get_and_patch_org_export(client, scheduled, can_see=True, can_edit=None):
|
||||
if can_edit is None:
|
||||
can_edit = can_see
|
||||
response = client.get(
|
||||
'/api/v1/organizers/{}/scheduled_exports/{}/'.format("dummy", scheduled.pk),
|
||||
)
|
||||
if can_see:
|
||||
assert response.status_code == 200
|
||||
else:
|
||||
assert response.status_code > 400
|
||||
assert can_edit is False # Check against useless test usage
|
||||
return True # No point in editing, we don't have a body
|
||||
|
||||
response = client.patch(
|
||||
'/api/v1/organizers/{}/scheduled_exports/{}/'.format("dummy", scheduled.pk),
|
||||
data=response.data,
|
||||
format='json',
|
||||
)
|
||||
if can_edit:
|
||||
assert response.status_code == 200
|
||||
else:
|
||||
assert response.status_code > 400 or (response.status_code == 400 and "export_identifier" in response.data)
|
||||
return True
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_organizer_edit_restrictions(client, event, organizer, user, team):
|
||||
# This tests the prevention of a possible privilege escalation where user A creates a scheduled export and
|
||||
# user B has settings permission (= they can see the export configuration), but not enough permission
|
||||
# to run the export themselves. Without this check, user B could modify the export and add themselves
|
||||
# as a recipient. Thereby, user B would gain access to data they can't have.
|
||||
user1_client = APIClient()
|
||||
user1_client.force_authenticate(user=user)
|
||||
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
|
||||
user2_client = APIClient()
|
||||
user2_client.force_authenticate(user=user2)
|
||||
team1_client = APIClient()
|
||||
t = team.tokens.create(name='Foo')
|
||||
team1_client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
|
||||
event1 = event
|
||||
event2 = Event.objects.create(
|
||||
organizer=organizer, name="Dummy", slug="dummy2",
|
||||
date_from=now(), plugins="pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy"
|
||||
)
|
||||
|
||||
team1 = team
|
||||
team1.all_organizer_permissions = False
|
||||
team1.all_event_permissions = False
|
||||
team1.all_events = False
|
||||
team1.limit_organizer_permissions = {"organizer.settings.general:write": True}
|
||||
team1.limit_event_permissions = {"event.orders:read": True, "event.settings.general:write": True}
|
||||
team1.save()
|
||||
team1.limit_events.add(event1)
|
||||
team1.members.add(user)
|
||||
|
||||
t = team.tokens.create(name='Foo')
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
|
||||
team2 = organizer.teams.create(
|
||||
all_organizer_permissions=False, all_event_permissions=False, all_events=False,
|
||||
limit_event_permissions={"event.orders:read": True},
|
||||
limit_organizer_permissions={"organizer.giftcards:read": True}
|
||||
)
|
||||
team2.limit_events.add(event2)
|
||||
team2.members.add(user2)
|
||||
|
||||
# Scenario 1
|
||||
# User 2 created an export for all events. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, but can't change it, because they
|
||||
# don't have access to all events.
|
||||
s1 = ScheduledOrganizerExport.objects.create(
|
||||
organizer=organizer,
|
||||
owner=user2,
|
||||
export_identifier="dummy_orders",
|
||||
export_form_data={"all_events": True, "events": []},
|
||||
mail_subject="Test",
|
||||
mail_template="Test",
|
||||
locale="en",
|
||||
schedule_rrule="DTSTART:20230118T000000\nRRULE:FREQ=DAILY;INTERVAL=1;WKST=MO",
|
||||
schedule_rrule_time=time(2, 30, 0)
|
||||
)
|
||||
user._teamcache = {}
|
||||
user2._teamcache = {}
|
||||
assert _get_and_patch_org_export(user2_client, s1)
|
||||
assert _get_and_patch_org_export(user1_client, s1, can_see=True, can_edit=False)
|
||||
assert _get_and_patch_org_export(team1_client, s1, can_see=True, can_edit=False)
|
||||
|
||||
# Scenario 2
|
||||
# User 2 created an export for all events. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, and change it, because they
|
||||
# have access to all events.
|
||||
team1.all_events = True
|
||||
team1.save()
|
||||
user._teamcache = {}
|
||||
user2._teamcache = {}
|
||||
assert _get_and_patch_org_export(user2_client, s1)
|
||||
assert _get_and_patch_org_export(user1_client, s1)
|
||||
assert _get_and_patch_org_export(team1_client, s1)
|
||||
|
||||
# Scenario 3
|
||||
# User 2 created an export for a specific event. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, but can't change it, because they
|
||||
# don't have access to that event.
|
||||
team1.all_events = False
|
||||
team1.save()
|
||||
s1.export_form_data = {"all_events": False, "events": [event2.pk]}
|
||||
s1.save()
|
||||
user._teamcache = {}
|
||||
user2._teamcache = {}
|
||||
assert _get_and_patch_org_export(user2_client, s1)
|
||||
assert _get_and_patch_org_export(user1_client, s1, can_see=True, can_edit=False)
|
||||
assert _get_and_patch_org_export(team1_client, s1, can_see=True, can_edit=False)
|
||||
|
||||
# Scenario 4
|
||||
# User 2 created an export for a specific event. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, and change it, because they
|
||||
# have access to that event.
|
||||
team1.limit_events.add(event2)
|
||||
user._teamcache = {}
|
||||
user2._teamcache = {}
|
||||
assert _get_and_patch_org_export(user2_client, s1)
|
||||
assert _get_and_patch_org_export(user1_client, s1)
|
||||
assert _get_and_patch_org_export(team1_client, s1)
|
||||
|
||||
# Scenario 5
|
||||
# User 2 created an export that requires a special permission on organizer level
|
||||
# user 1 can see it, because they have permission to see scheduled exports, but can't change it, because they lack
|
||||
# that special permission
|
||||
s2 = ScheduledOrganizerExport.objects.create(
|
||||
organizer=organizer,
|
||||
owner=user2,
|
||||
export_identifier="giftcardlist",
|
||||
mail_subject="Test",
|
||||
mail_template="Test",
|
||||
locale="en",
|
||||
schedule_rrule="DTSTART:20230118T000000\nRRULE:FREQ=DAILY;INTERVAL=1;WKST=MO",
|
||||
schedule_rrule_time=time(2, 30, 0)
|
||||
)
|
||||
user._teamcache = {}
|
||||
user2._teamcache = {}
|
||||
assert _get_and_patch_org_export(user2_client, s2)
|
||||
assert _get_and_patch_org_export(user1_client, s2, can_see=True, can_edit=False)
|
||||
assert _get_and_patch_org_export(team1_client, s2, can_see=True, can_edit=False)
|
||||
|
||||
# Scenario 6
|
||||
# User 2 created an export that requires a special permission on organizer level
|
||||
# user 1 can see it, because they have permission to see scheduled exports, and change it, because they have
|
||||
# that special permission
|
||||
team1.limit_organizer_permissions["organizer.giftcards:read"] = True
|
||||
team1.save()
|
||||
user._teamcache = {}
|
||||
assert _get_and_patch_org_export(user2_client, s2)
|
||||
assert _get_and_patch_org_export(team1_client, s2)
|
||||
assert _get_and_patch_org_export(user1_client, s2)
|
||||
|
||||
|
||||
def _get_and_patch_event_export(client, scheduled, can_see=True, can_edit=True):
|
||||
if can_edit is None:
|
||||
can_edit = can_see
|
||||
response = client.get(
|
||||
'/api/v1/organizers/{}/events/{}/scheduled_exports/{}/'.format("dummy", "dummy", scheduled.pk),
|
||||
)
|
||||
if can_see:
|
||||
assert response.status_code == 200
|
||||
else:
|
||||
assert response.status_code > 400
|
||||
assert can_edit is False # Check against useless test usage
|
||||
return True # No point in editing, we don't have a body
|
||||
|
||||
response = client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/scheduled_exports/{}/'.format("dummy", "dummy", scheduled.pk),
|
||||
data=response.data,
|
||||
format='json',
|
||||
)
|
||||
if can_edit:
|
||||
assert response.status_code == 200
|
||||
else:
|
||||
assert response.status_code > 400 or (response.status_code == 400 and "export_identifier" in response.data)
|
||||
return True
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_event_edit_restrictions(client, event, organizer, user, team):
|
||||
# This tests the prevention of a possible privilege escalation where user A creates a scheduled export and
|
||||
# user B has settings permission (= they can see the export configuration), but not enough permission
|
||||
# to run the export themselves. Without this check, user B could modify the export and add themselves
|
||||
# as a recipient. Thereby, user B would gain access to data they can't have.
|
||||
user1_client = APIClient()
|
||||
user1_client.force_authenticate(user=user)
|
||||
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
|
||||
user2_client = APIClient()
|
||||
user2_client.force_authenticate(user=user2)
|
||||
team1_client = APIClient()
|
||||
t = team.tokens.create(name='Foo')
|
||||
team1_client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
|
||||
event1 = event
|
||||
|
||||
team1 = team
|
||||
team1.all_organizer_permissions = False
|
||||
team1.all_event_permissions = False
|
||||
team1.all_events = False
|
||||
team1.limit_organizer_permissions = {"organizer.settings.general:write": True}
|
||||
team1.limit_event_permissions = {"event.orders:read": True, "event.settings.general:write": True}
|
||||
team1.save()
|
||||
team1.limit_events.add(event1)
|
||||
team1.members.add(user)
|
||||
|
||||
t = team.tokens.create(name='Foo')
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
|
||||
team2 = organizer.teams.create(
|
||||
all_organizer_permissions=False, all_event_permissions=False, all_events=False,
|
||||
limit_event_permissions={"event.orders:read": True, "event.vouchers:read": True},
|
||||
limit_organizer_permissions={"organizer.giftcards:read": True}
|
||||
)
|
||||
team2.limit_events.add(event1)
|
||||
team2.members.add(user2)
|
||||
|
||||
# User 2 created an export that requires a special permission on organizer level
|
||||
# user 1 can see it, because they have permission to see scheduled exports, but can't change it, because they lack
|
||||
# that special permission
|
||||
s2 = ScheduledEventExport.objects.create(
|
||||
event=event,
|
||||
owner=user2,
|
||||
export_identifier="dummy_vouchers",
|
||||
mail_subject="Test",
|
||||
mail_template="Test",
|
||||
locale="en",
|
||||
schedule_rrule="DTSTART:20230118T000000\nRRULE:FREQ=DAILY;INTERVAL=1;WKST=MO",
|
||||
schedule_rrule_time=time(2, 30, 0)
|
||||
)
|
||||
user._teamcache = {}
|
||||
user2._teamcache = {}
|
||||
assert _get_and_patch_event_export(user2_client, s2)
|
||||
assert _get_and_patch_event_export(user1_client, s2, can_see=True, can_edit=False)
|
||||
assert _get_and_patch_event_export(team1_client, s2, can_see=True, can_edit=False)
|
||||
|
||||
# Scenario 6
|
||||
# User 2 created an export that requires a special permission on organizer level
|
||||
# user 1 can see it, because they have permission to see scheduled exports, and change it, because they have
|
||||
# that special permission
|
||||
team1.limit_event_permissions["event.vouchers:read"] = True
|
||||
team1.save()
|
||||
user._teamcache = {}
|
||||
assert _get_and_patch_event_export(user2_client, s2)
|
||||
assert _get_and_patch_event_export(team1_client, s2)
|
||||
assert _get_and_patch_event_export(user1_client, s2)
|
||||
|
||||
@@ -340,6 +340,8 @@ def test_invoice_list_multi_filter(token_client, organizer, event, order, order2
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_organizer_level(token_client, organizer, team, event, event2, invoice, invoice2):
|
||||
team.all_events = True
|
||||
team.save()
|
||||
resp = token_client.get('/api/v1/organizers/{}/invoices/'.format(organizer.slug))
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.data['results']) == 2
|
||||
|
||||
@@ -53,8 +53,13 @@ def organizer():
|
||||
|
||||
@pytest.fixture
|
||||
def admin_team(organizer):
|
||||
return Team.objects.create(organizer=organizer, can_change_teams=True, name='Admin team', all_events=True,
|
||||
can_create_events=True)
|
||||
return Team.objects.create(
|
||||
organizer=organizer,
|
||||
name='Admin team',
|
||||
all_events=True,
|
||||
all_event_permissions=True,
|
||||
all_organizer_permissions=True,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -387,7 +392,7 @@ def test_token_from_code(client, admin_user, organizer, application: OAuthApplic
|
||||
@pytest.mark.django_db
|
||||
def test_use_token_for_access_one_organizer(client, admin_user, organizer, application: OAuthApplication):
|
||||
o2 = Organizer.objects.create(name='A', slug='a')
|
||||
t2 = Team.objects.create(organizer=o2, can_change_teams=True, name='Admin team', all_events=True)
|
||||
t2 = Team.objects.create(organizer=o2, all_organizer_permissions=True, name='Admin team', all_events=True)
|
||||
t2.members.add(admin_user)
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
@@ -434,7 +439,13 @@ def test_use_token_for_access_one_organizer(client, admin_user, organizer, appli
|
||||
@pytest.mark.django_db
|
||||
def test_use_token_for_access_two_organizers(client, admin_user, organizer, application: OAuthApplication):
|
||||
o2 = Organizer.objects.create(name='A', slug='a')
|
||||
t2 = Team.objects.create(organizer=o2, can_change_teams=True, name='Admin team', all_events=True)
|
||||
t2 = Team.objects.create(
|
||||
organizer=o2,
|
||||
all_event_permissions=True,
|
||||
all_organizer_permissions=True,
|
||||
name='Admin team',
|
||||
all_events=True
|
||||
)
|
||||
t2.members.add(admin_user)
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -186,18 +186,8 @@ def team2(organizer, event2):
|
||||
team2 = Team.objects.create(
|
||||
organizer=organizer,
|
||||
name="Test-Team 2",
|
||||
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_manage_reusable_media=True,
|
||||
can_change_organizer_settings=True,
|
||||
|
||||
all_event_permissions=True,
|
||||
all_organizer_permissions=True,
|
||||
)
|
||||
team2.limit_events.add(event2)
|
||||
team2.save()
|
||||
@@ -209,6 +199,11 @@ def team2(organizer, event2):
|
||||
def limited_token_client(client, team2):
|
||||
team2.can_view_orders = True
|
||||
team2.can_view_vouchers = True
|
||||
team2.all_event_permissions = True
|
||||
team2.limit_event_permissions = {
|
||||
"event.vouchers:read": True,
|
||||
"event.orders:read": True,
|
||||
}
|
||||
team2.save()
|
||||
t = team2.tokens.create(name='Foo')
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
|
||||
@@ -43,247 +43,255 @@ from pretix.base.models import Organizer
|
||||
event_urls = [
|
||||
(None, ''),
|
||||
(None, 'categories/'),
|
||||
('can_view_orders', 'invoices/'),
|
||||
('event.orders:read', 'invoices/'),
|
||||
(None, 'items/'),
|
||||
('can_view_orders', 'orders/'),
|
||||
('can_view_orders', 'orderpositions/'),
|
||||
('event.orders:read', 'orders/'),
|
||||
('event.orders:read', 'orderpositions/'),
|
||||
(None, 'questions/'),
|
||||
(None, 'quotas/'),
|
||||
('can_view_vouchers', 'vouchers/'),
|
||||
('event.vouchers:read', 'vouchers/'),
|
||||
(None, 'subevents/'),
|
||||
(None, 'taxrules/'),
|
||||
('can_view_orders', 'waitinglistentries/'),
|
||||
('can_view_orders', 'checkinlists/'),
|
||||
('can_view_orders', 'checkins/'),
|
||||
('event.orders:read', 'waitinglistentries/'),
|
||||
('event.orders:read', 'checkinlists/'),
|
||||
('event.orders:read', 'checkins/'),
|
||||
(None, 'seats/'),
|
||||
]
|
||||
|
||||
event_permission_sub_urls = [
|
||||
('get', 'can_change_event_settings', 'settings/', 200),
|
||||
('patch', 'can_change_event_settings', 'settings/', 200),
|
||||
('get', 'can_view_orders', 'revokedsecrets/', 200),
|
||||
('get', 'can_view_orders', 'revokedsecrets/1/', 404),
|
||||
('get', 'can_view_orders', 'blockedsecrets/', 200),
|
||||
('get', 'can_view_orders', 'blockedsecrets/1/', 404),
|
||||
('get', 'can_view_orders', 'transactions/', 200),
|
||||
('get', 'can_view_orders', 'transactions/1/', 404),
|
||||
('get', 'can_view_orders', 'orders/', 200),
|
||||
('get', 'can_view_orders', 'orderpositions/', 200),
|
||||
('delete', 'can_change_orders', 'orderpositions/1/', 404),
|
||||
('post', 'can_change_orders', 'orderpositions/1/price_calc/', 404),
|
||||
('get', 'can_view_vouchers', 'vouchers/', 200),
|
||||
('get', 'can_view_orders', 'invoices/', 200),
|
||||
('get', 'can_view_orders', 'invoices/1/', 404),
|
||||
('post', 'can_change_orders', 'invoices/1/regenerate/', 404),
|
||||
('post', 'can_change_orders', 'invoices/1/reissue/', 404),
|
||||
('post', 'can_change_orders', 'invoices/1/retransmit/', 404),
|
||||
('get', 'can_view_orders', 'waitinglistentries/', 200),
|
||||
('get', 'can_view_orders', 'waitinglistentries/1/', 404),
|
||||
('post', 'can_change_orders', 'waitinglistentries/', 400),
|
||||
('delete', 'can_change_orders', 'waitinglistentries/1/', 404),
|
||||
('patch', 'can_change_orders', 'waitinglistentries/1/', 404),
|
||||
('put', 'can_change_orders', 'waitinglistentries/1/', 404),
|
||||
('post', 'can_change_orders', 'waitinglistentries/1/send_voucher/', 404),
|
||||
('get', None, 'settings/', 200),
|
||||
('patch', 'event.settings.general:write', 'settings/', 200),
|
||||
('get', 'event.orders:read', 'revokedsecrets/', 200),
|
||||
('get', 'event.orders:read', 'revokedsecrets/1/', 404),
|
||||
('get', 'event.orders:read', 'blockedsecrets/', 200),
|
||||
('get', 'event.orders:read', 'blockedsecrets/1/', 404),
|
||||
('get', 'event.orders:read', 'transactions/', 200),
|
||||
('get', 'event.orders:read', 'transactions/1/', 404),
|
||||
('get', 'event.orders:read', 'orders/', 200),
|
||||
('get', 'event.orders:read', 'orderpositions/', 200),
|
||||
('delete', 'event.orders:write', 'orderpositions/1/', 404),
|
||||
('post', 'event.orders:write', 'orderpositions/1/price_calc/', 404),
|
||||
('get', 'event.vouchers:read', 'vouchers/', 200),
|
||||
('get', 'event.orders:read', 'invoices/', 200),
|
||||
('get', 'event.orders:read', 'invoices/1/', 404),
|
||||
('post', 'event.orders:write', 'invoices/1/regenerate/', 404),
|
||||
('post', 'event.orders:write', 'invoices/1/reissue/', 404),
|
||||
('post', 'event.orders:write', 'invoices/1/retransmit/', 404),
|
||||
('get', 'event.orders:read', 'waitinglistentries/', 200),
|
||||
('get', 'event.orders:read', 'waitinglistentries/1/', 404),
|
||||
('post', 'event.orders:write', 'waitinglistentries/', 400),
|
||||
('delete', 'event.orders:write', 'waitinglistentries/1/', 404),
|
||||
('patch', 'event.orders:write', 'waitinglistentries/1/', 404),
|
||||
('put', 'event.orders:write', 'waitinglistentries/1/', 404),
|
||||
('post', 'event.orders:write', 'waitinglistentries/1/send_voucher/', 404),
|
||||
('get', None, 'categories/', 200),
|
||||
('get', None, 'items/', 200),
|
||||
('get', None, 'questions/', 200),
|
||||
('get', None, 'quotas/', 200),
|
||||
('get', None, 'discounts/', 200),
|
||||
('post', 'can_change_items', 'items/', 400),
|
||||
('post', 'event.items:write', 'items/', 400),
|
||||
('get', None, 'items/1/', 404),
|
||||
('put', 'can_change_items', 'items/1/', 404),
|
||||
('patch', 'can_change_items', 'items/1/', 404),
|
||||
('delete', 'can_change_items', 'items/1/', 404),
|
||||
('post', 'can_change_items', 'categories/', 400),
|
||||
('put', 'event.items:write', 'items/1/', 404),
|
||||
('patch', 'event.items:write', 'items/1/', 404),
|
||||
('delete', 'event.items:write', 'items/1/', 404),
|
||||
('post', 'event.items:write', 'categories/', 400),
|
||||
('get', None, 'categories/1/', 404),
|
||||
('put', 'can_change_items', 'categories/1/', 404),
|
||||
('patch', 'can_change_items', 'categories/1/', 404),
|
||||
('delete', 'can_change_items', 'categories/1/', 404),
|
||||
('post', 'can_change_items', 'discounts/', 400),
|
||||
('put', 'event.items:write', 'categories/1/', 404),
|
||||
('patch', 'event.items:write', 'categories/1/', 404),
|
||||
('delete', 'event.items:write', 'categories/1/', 404),
|
||||
('post', 'event.items:write', 'discounts/', 400),
|
||||
('get', None, 'discounts/1/', 404),
|
||||
('put', 'can_change_items', 'discounts/1/', 404),
|
||||
('patch', 'can_change_items', 'discounts/1/', 404),
|
||||
('delete', 'can_change_items', 'discounts/1/', 404),
|
||||
('post', 'can_change_items', 'items/1/variations/', 404),
|
||||
('put', 'event.items:write', 'discounts/1/', 404),
|
||||
('patch', 'event.items:write', 'discounts/1/', 404),
|
||||
('delete', 'event.items:write', 'discounts/1/', 404),
|
||||
('post', 'event.items:write', 'items/1/variations/', 404),
|
||||
('get', None, 'items/1/variations/', 404),
|
||||
('get', None, 'items/1/variations/1/', 404),
|
||||
('put', 'can_change_items', 'items/1/variations/1/', 404),
|
||||
('patch', 'can_change_items', 'items/1/variations/1/', 404),
|
||||
('delete', 'can_change_items', 'items/1/variations/1/', 404),
|
||||
('put', 'event.items:write', 'items/1/variations/1/', 404),
|
||||
('patch', 'event.items:write', 'items/1/variations/1/', 404),
|
||||
('delete', 'event.items:write', 'items/1/variations/1/', 404),
|
||||
('get', None, 'items/1/addons/', 404),
|
||||
('get', None, 'items/1/addons/1/', 404),
|
||||
('post', 'can_change_items', 'items/1/addons/', 404),
|
||||
('put', 'can_change_items', 'items/1/addons/1/', 404),
|
||||
('patch', 'can_change_items', 'items/1/addons/1/', 404),
|
||||
('delete', 'can_change_items', 'items/1/addons/1/', 404),
|
||||
('post', 'event.items:write', 'items/1/addons/', 404),
|
||||
('put', 'event.items:write', 'items/1/addons/1/', 404),
|
||||
('patch', 'event.items:write', 'items/1/addons/1/', 404),
|
||||
('delete', 'event.items:write', 'items/1/addons/1/', 404),
|
||||
('get', None, 'subevents/', 200),
|
||||
('get', None, 'subevents/1/', 404),
|
||||
('post', 'event.subevents:write', 'subevents/', 400),
|
||||
('patch', 'event.subevents:write', 'subevents/1/', 404),
|
||||
('put', 'event.subevents:write', 'subevents/1/', 404),
|
||||
('get', None, 'taxrules/', 200),
|
||||
('get', None, 'taxrules/1/', 404),
|
||||
('post', 'can_change_event_settings', 'taxrules/', 400),
|
||||
('put', 'can_change_event_settings', 'taxrules/1/', 404),
|
||||
('patch', 'can_change_event_settings', 'taxrules/1/', 404),
|
||||
('delete', 'can_change_event_settings', 'taxrules/1/', 404),
|
||||
('get', 'can_change_event_settings', 'sendmail_rules/', 200),
|
||||
('get', 'can_change_event_settings', 'sendmail_rules/1/', 404),
|
||||
('post', 'can_change_event_settings', 'sendmail_rules/', 400),
|
||||
('put', 'can_change_event_settings', 'sendmail_rules/1/', 404),
|
||||
('patch', 'can_change_event_settings', 'sendmail_rules/1/', 404),
|
||||
('delete', 'can_change_event_settings', 'sendmail_rules/1/', 404),
|
||||
('get', 'can_view_vouchers', 'vouchers/', 200),
|
||||
('get', 'can_view_vouchers', 'vouchers/1/', 404),
|
||||
('post', 'can_change_vouchers', 'vouchers/', 201),
|
||||
('put', 'can_change_vouchers', 'vouchers/1/', 404),
|
||||
('patch', 'can_change_vouchers', 'vouchers/1/', 404),
|
||||
('delete', 'can_change_vouchers', 'vouchers/1/', 404),
|
||||
('post', 'event.settings.tax:write', 'taxrules/', 400),
|
||||
('put', 'event.settings.tax:write', 'taxrules/1/', 404),
|
||||
('patch', 'event.settings.tax:write', 'taxrules/1/', 404),
|
||||
('delete', 'event.settings.tax:write', 'taxrules/1/', 404),
|
||||
('get', 'event.settings.general:write', 'sendmail_rules/', 200),
|
||||
('get', 'event.settings.general:write', 'sendmail_rules/1/', 404),
|
||||
('post', 'event.settings.general:write', 'sendmail_rules/', 400),
|
||||
('put', 'event.settings.general:write', 'sendmail_rules/1/', 404),
|
||||
('patch', 'event.settings.general:write', 'sendmail_rules/1/', 404),
|
||||
('delete', 'event.settings.general:write', 'sendmail_rules/1/', 404),
|
||||
('get', 'event.vouchers:read', 'vouchers/', 200),
|
||||
('get', 'event.vouchers:read', 'vouchers/1/', 404),
|
||||
('post', 'event.vouchers:write', 'vouchers/', 201),
|
||||
('put', 'event.vouchers:write', 'vouchers/1/', 404),
|
||||
('patch', 'event.vouchers:write', 'vouchers/1/', 404),
|
||||
('delete', 'event.vouchers:write', 'vouchers/1/', 404),
|
||||
('get', None, 'quotas/', 200),
|
||||
('get', None, 'quotas/1/', 404),
|
||||
('post', 'can_change_items', 'quotas/', 400),
|
||||
('put', 'can_change_items', 'quotas/1/', 404),
|
||||
('patch', 'can_change_items', 'quotas/1/', 404),
|
||||
('delete', 'can_change_items', 'quotas/1/', 404),
|
||||
('post', 'event.items:write', 'quotas/', 400),
|
||||
('put', 'event.items:write', 'quotas/1/', 404),
|
||||
('patch', 'event.items:write', 'quotas/1/', 404),
|
||||
('delete', 'event.items:write', 'quotas/1/', 404),
|
||||
('get', None, 'questions/', 200),
|
||||
('get', None, 'questions/1/', 404),
|
||||
('post', 'can_change_items', 'questions/', 400),
|
||||
('put', 'can_change_items', 'questions/1/', 404),
|
||||
('patch', 'can_change_items', 'questions/1/', 404),
|
||||
('delete', 'can_change_items', 'questions/1/', 404),
|
||||
('post', 'event.items:write', 'questions/', 400),
|
||||
('put', 'event.items:write', 'questions/1/', 404),
|
||||
('patch', 'event.items:write', 'questions/1/', 404),
|
||||
('delete', 'event.items:write', 'questions/1/', 404),
|
||||
('get', None, 'questions/1/options/', 404),
|
||||
('get', None, 'questions/1/options/1/', 404),
|
||||
('put', 'can_change_items', 'questions/1/options/1/', 404),
|
||||
('patch', 'can_change_items', 'questions/1/options/1/', 404),
|
||||
('delete', 'can_change_items', 'questions/1/options/1/', 404),
|
||||
('post', 'can_change_orders', 'orders/', 400),
|
||||
('patch', 'can_change_orders', 'orders/ABC12/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/mark_paid/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/mark_pending/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/mark_expired/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/mark_canceled/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/approve/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/deny/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/extend/', 400),
|
||||
('post', 'can_change_orders', 'orders/ABC12/create_invoice/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/resend_link/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/regenerate_secrets/', 404),
|
||||
('get', 'can_view_orders', 'orders/ABC12/payments/', 404),
|
||||
('get', 'can_view_orders', 'orders/ABC12/payments/1/', 404),
|
||||
('get', 'can_view_orders', 'orders/ABC12/refunds/', 404),
|
||||
('get', 'can_view_orders', 'orders/ABC12/refunds/1/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/payments/1/confirm/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/payments/1/refund/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/payments/1/cancel/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/refunds/1/cancel/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/refunds/1/process/', 404),
|
||||
('post', 'can_change_orders', 'orders/ABC12/refunds/1/done/', 404),
|
||||
('get', 'can_view_orders', 'checkinlists/', 200),
|
||||
('post', 'can_change_orders', 'checkinlists/1/failed_checkins/', 400),
|
||||
('get', 'can_view_orders', 'checkins/', 200),
|
||||
('get', 'can_view_orders', 'checkins/1/', 404),
|
||||
('post', 'can_change_event_settings', 'checkinlists/', 400),
|
||||
('put', 'can_change_event_settings', 'checkinlists/1/', 404),
|
||||
('patch', 'can_change_event_settings', 'checkinlists/1/', 404),
|
||||
('delete', 'can_change_event_settings', 'checkinlists/1/', 404),
|
||||
('get', 'can_view_orders', 'checkinlists/1/positions/', 404),
|
||||
('post', 'can_change_orders', 'checkinlists/1/positions/3/redeem/', 404),
|
||||
('post', 'can_create_events', 'clone/', 400),
|
||||
('get', 'can_view_orders', 'cartpositions/', 200),
|
||||
('get', 'can_view_orders', 'cartpositions/1/', 404),
|
||||
('post', 'can_change_orders', 'cartpositions/', 400),
|
||||
('delete', 'can_change_orders', 'cartpositions/1/', 404),
|
||||
('post', 'can_view_orders', 'exporters/invoicedata/run/', 400),
|
||||
('get', 'can_view_orders', 'exporters/invoicedata/download/bc3f9884-26ee-425b-8636-80613f84b6fa/3cb49ae6-eda3'
|
||||
'-4605-814e-099e23777b36/', 404),
|
||||
('put', 'event.items:write', 'questions/1/options/1/', 404),
|
||||
('patch', 'event.items:write', 'questions/1/options/1/', 404),
|
||||
('delete', 'event.items:write', 'questions/1/options/1/', 404),
|
||||
('post', 'event.orders:write', 'orders/', 400),
|
||||
('patch', 'event.orders:write', 'orders/ABC12/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/mark_paid/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/mark_pending/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/mark_expired/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/mark_canceled/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/approve/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/deny/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/extend/', 400),
|
||||
('post', 'event.orders:write', 'orders/ABC12/create_invoice/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/resend_link/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/regenerate_secrets/', 404),
|
||||
('get', 'event.orders:read', 'orders/ABC12/payments/', 404),
|
||||
('get', 'event.orders:read', 'orders/ABC12/payments/1/', 404),
|
||||
('get', 'event.orders:read', 'orders/ABC12/refunds/', 404),
|
||||
('get', 'event.orders:read', 'orders/ABC12/refunds/1/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/payments/1/confirm/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/payments/1/refund/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/payments/1/cancel/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/refunds/1/cancel/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/refunds/1/process/', 404),
|
||||
('post', 'event.orders:write', 'orders/ABC12/refunds/1/done/', 404),
|
||||
('get', 'event.orders:read', 'checkinlists/', 200),
|
||||
('post', 'event.orders:write', 'checkinlists/1/failed_checkins/', 400),
|
||||
('get', 'event.orders:read', 'checkins/', 200),
|
||||
('get', 'event.orders:read', 'checkins/1/', 404),
|
||||
('post', 'event.settings.general:write', 'checkinlists/', 400),
|
||||
('put', 'event.settings.general:write', 'checkinlists/1/', 404),
|
||||
('patch', 'event.settings.general:write', 'checkinlists/1/', 404),
|
||||
('delete', 'event.settings.general:write', 'checkinlists/1/', 404),
|
||||
('get', 'event.orders:read', 'checkinlists/1/positions/', 404),
|
||||
('post', 'event.orders:write', 'checkinlists/1/positions/3/redeem/', 404),
|
||||
('post', ('organizer.events:create', 'event.settings.general:write'), 'clone/', 400),
|
||||
('get', 'event.orders:read', 'cartpositions/', 200),
|
||||
('get', 'event.orders:read', 'cartpositions/1/', 404),
|
||||
('post', 'event.orders:write', 'cartpositions/', 400),
|
||||
('delete', 'event.orders:write', 'cartpositions/1/', 404),
|
||||
('post', 'event.orders:read', 'exporters/invoicedata/run/', 400),
|
||||
('get', None, 'item_meta_properties/', 200),
|
||||
('get', None, 'item_meta_properties/0/', 404),
|
||||
('post', 'can_change_event_settings', 'item_meta_properties/', 400),
|
||||
('patch', 'can_change_event_settings', 'item_meta_properties/0/', 404),
|
||||
('delete', 'can_change_event_settings', 'item_meta_properties/0/', 404),
|
||||
('post', 'event.settings.general:write', 'item_meta_properties/', 400),
|
||||
('patch', 'event.settings.general:write', 'item_meta_properties/0/', 404),
|
||||
('delete', 'event.settings.general:write', 'item_meta_properties/0/', 404),
|
||||
('get', None, 'seats/', 200),
|
||||
('get', 'can_view_orders', 'seats/?expand=orderposition', 200),
|
||||
('get', 'can_view_orders', 'seats/?expand=cartposition', 200),
|
||||
('get', 'can_view_vouchers', 'seats/?expand=voucher', 200),
|
||||
('get', 'event.orders:read', 'seats/?expand=orderposition', 200),
|
||||
('get', 'event.orders:read', 'seats/?expand=cartposition', 200),
|
||||
('get', 'event.vouchers:read', 'seats/?expand=voucher', 200),
|
||||
('get', None, 'seats/1/', 404),
|
||||
('patch', 'can_change_event_settings', 'seats/1/', 404),
|
||||
('patch', 'event.settings.general:write', 'seats/1/', 404),
|
||||
]
|
||||
|
||||
org_permission_sub_urls = [
|
||||
('patch', 'can_change_organizer_settings', '', 200),
|
||||
('patch', 'can_change_organizer_settings', 'settings/', 200),
|
||||
('get', 'can_change_organizer_settings', 'webhooks/', 200),
|
||||
('post', 'can_change_organizer_settings', 'webhooks/', 400),
|
||||
('get', 'can_change_organizer_settings', 'webhooks/1/', 404),
|
||||
('put', 'can_change_organizer_settings', 'webhooks/1/', 404),
|
||||
('patch', 'can_change_organizer_settings', 'webhooks/1/', 404),
|
||||
('delete', 'can_change_organizer_settings', 'webhooks/1/', 404),
|
||||
('get', 'can_manage_customers', 'customers/', 200),
|
||||
('post', 'can_manage_customers', 'customers/', 201),
|
||||
('get', 'can_manage_customers', 'customers/1/', 404),
|
||||
('patch', 'can_manage_customers', 'customers/1/', 404),
|
||||
('post', 'can_manage_customers', 'customers/1/anonymize/', 404),
|
||||
('put', 'can_manage_customers', 'customers/1/', 404),
|
||||
('delete', 'can_manage_customers', 'customers/1/', 404),
|
||||
('get', 'can_manage_customers', 'memberships/', 200),
|
||||
('post', 'can_manage_customers', 'memberships/', 400),
|
||||
('get', 'can_manage_customers', 'memberships/1/', 404),
|
||||
('patch', 'can_manage_customers', 'memberships/1/', 404),
|
||||
('put', 'can_manage_customers', 'memberships/1/', 404),
|
||||
('delete', 'can_manage_customers', 'memberships/1/', 404),
|
||||
('get', 'can_change_organizer_settings', 'saleschannels/', 200),
|
||||
('post', 'can_change_organizer_settings', 'saleschannels/', 400),
|
||||
('get', 'can_change_organizer_settings', 'saleschannels/web/', 200),
|
||||
('patch', 'can_change_organizer_settings', 'saleschannels/web/', 200),
|
||||
('put', 'can_change_organizer_settings', 'saleschannels/api.1/', 404),
|
||||
('delete', 'can_change_organizer_settings', 'saleschannels/api.1/', 404),
|
||||
('get', 'can_change_organizer_settings', 'membershiptypes/', 200),
|
||||
('post', 'can_change_organizer_settings', 'membershiptypes/', 400),
|
||||
('get', 'can_change_organizer_settings', 'membershiptypes/1/', 404),
|
||||
('patch', 'can_change_organizer_settings', 'membershiptypes/1/', 404),
|
||||
('put', 'can_change_organizer_settings', 'membershiptypes/1/', 404),
|
||||
('delete', 'can_change_organizer_settings', 'membershiptypes/1/', 404),
|
||||
('get', 'can_manage_gift_cards', 'giftcards/', 200),
|
||||
('post', 'can_manage_gift_cards', 'giftcards/', 400),
|
||||
('get', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||
('put', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||
('patch', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||
('get', 'can_manage_gift_cards', 'giftcards/1/transactions/', 404),
|
||||
('get', 'can_manage_gift_cards', 'giftcards/1/transactions/1/', 404),
|
||||
('get', 'can_change_organizer_settings', 'devices/', 200),
|
||||
('post', 'can_change_organizer_settings', 'devices/', 400),
|
||||
('get', 'can_change_organizer_settings', 'devices/1/', 404),
|
||||
('put', 'can_change_organizer_settings', 'devices/1/', 404),
|
||||
('patch', 'can_change_organizer_settings', 'devices/1/', 404),
|
||||
('get', 'can_change_teams', 'teams/', 200),
|
||||
('post', 'can_change_teams', 'teams/', 400),
|
||||
('get', 'can_change_teams', 'teams/{team_id}/', 200),
|
||||
('put', 'can_change_teams', 'teams/{team_id}/', 400),
|
||||
('patch', 'can_change_teams', 'teams/{team_id}/', 200),
|
||||
('get', 'can_change_teams', 'teams/{team_id}/members/', 200),
|
||||
('delete', 'can_change_teams', 'teams/{team_id}/members/2/', 404),
|
||||
('get', 'can_change_teams', 'teams/{team_id}/invites/', 200),
|
||||
('get', 'can_change_teams', 'teams/{team_id}/invites/2/', 404),
|
||||
('delete', 'can_change_teams', 'teams/{team_id}/invites/2/', 404),
|
||||
('post', 'can_change_teams', 'teams/{team_id}/invites/', 400),
|
||||
('get', 'can_change_teams', 'teams/{team_id}/tokens/', 200),
|
||||
('get', 'can_change_teams', 'teams/{team_id}/tokens/0/', 404),
|
||||
('delete', 'can_change_teams', 'teams/{team_id}/tokens/0/', 404),
|
||||
('post', 'can_change_teams', 'teams/{team_id}/tokens/', 400),
|
||||
('get', 'can_manage_reusable_media', 'reusablemedia/1/', 404),
|
||||
('patch', 'organizer.settings.general:write', '', 200),
|
||||
('patch', 'organizer.settings.general:write', 'settings/', 200),
|
||||
('get', 'organizer.settings.general:write', 'webhooks/', 200),
|
||||
('post', 'organizer.settings.general:write', 'webhooks/', 400),
|
||||
('get', 'organizer.settings.general:write', 'webhooks/1/', 404),
|
||||
('put', 'organizer.settings.general:write', 'webhooks/1/', 404),
|
||||
('patch', 'organizer.settings.general:write', 'webhooks/1/', 404),
|
||||
('delete', 'organizer.settings.general:write', 'webhooks/1/', 404),
|
||||
('get', 'organizer.customers:read', 'customers/', 200),
|
||||
('post', 'organizer.customers:write', 'customers/', 201),
|
||||
('get', 'organizer.customers:read', 'customers/1/', 404),
|
||||
('patch', 'organizer.customers:write', 'customers/1/', 404),
|
||||
('post', 'organizer.customers:write', 'customers/1/anonymize/', 404),
|
||||
('put', 'organizer.customers:write', 'customers/1/', 404),
|
||||
('delete', 'organizer.customers:write', 'customers/1/', 404),
|
||||
('get', 'organizer.customers:read', 'memberships/', 200),
|
||||
('post', 'organizer.customers:write', 'memberships/', 400),
|
||||
('get', 'organizer.customers:read', 'memberships/1/', 404),
|
||||
('patch', 'organizer.customers:write', 'memberships/1/', 404),
|
||||
('put', 'organizer.customers:write', 'memberships/1/', 404),
|
||||
('delete', 'organizer.customers:write', 'memberships/1/', 404),
|
||||
('get', 'organizer.settings.general:write', 'saleschannels/', 200),
|
||||
('post', 'organizer.settings.general:write', 'saleschannels/', 400),
|
||||
('get', 'organizer.settings.general:write', 'saleschannels/web/', 200),
|
||||
('patch', 'organizer.settings.general:write', 'saleschannels/web/', 200),
|
||||
('put', 'organizer.settings.general:write', 'saleschannels/api.1/', 404),
|
||||
('delete', 'organizer.settings.general:write', 'saleschannels/api.1/', 404),
|
||||
('get', 'organizer.settings.general:write', 'membershiptypes/', 200),
|
||||
('post', 'organizer.settings.general:write', 'membershiptypes/', 400),
|
||||
('get', 'organizer.settings.general:write', 'membershiptypes/1/', 404),
|
||||
('patch', 'organizer.settings.general:write', 'membershiptypes/1/', 404),
|
||||
('put', 'organizer.settings.general:write', 'membershiptypes/1/', 404),
|
||||
('delete', 'organizer.settings.general:write', 'membershiptypes/1/', 404),
|
||||
('get', 'organizer.giftcards:read', 'giftcards/', 200),
|
||||
('post', 'organizer.giftcards:write', 'giftcards/', 400),
|
||||
('get', 'organizer.giftcards:read', 'giftcards/1/', 404),
|
||||
('put', 'organizer.giftcards:write', 'giftcards/1/', 404),
|
||||
('patch', 'organizer.giftcards:write', 'giftcards/1/', 404),
|
||||
('get', 'organizer.giftcards:read', 'giftcards/1/transactions/', 404),
|
||||
('get', 'organizer.giftcards:read', 'giftcards/1/transactions/1/', 404),
|
||||
('get', 'organizer.devices:read', 'devices/', 200),
|
||||
('post', 'organizer.devices:write', 'devices/', 400),
|
||||
('get', 'organizer.devices:read', 'devices/1/', 404),
|
||||
('put', 'organizer.devices:write', 'devices/1/', 404),
|
||||
('patch', 'organizer.devices:write', 'devices/1/', 404),
|
||||
('get', 'organizer.teams:write', 'teams/', 200),
|
||||
('post', 'organizer.teams:write', 'teams/', 400),
|
||||
('get', 'organizer.teams:write', 'teams/{team_id}/', 200),
|
||||
('put', 'organizer.teams:write', 'teams/{team_id}/', 400),
|
||||
('patch', 'organizer.teams:write', 'teams/{team_id}/', 200),
|
||||
('get', 'organizer.teams:write', 'teams/{team_id}/members/', 200),
|
||||
('delete', 'organizer.teams:write', 'teams/{team_id}/members/2/', 404),
|
||||
('get', 'organizer.teams:write', 'teams/{team_id}/invites/', 200),
|
||||
('get', 'organizer.teams:write', 'teams/{team_id}/invites/2/', 404),
|
||||
('delete', 'organizer.teams:write', 'teams/{team_id}/invites/2/', 404),
|
||||
('post', 'organizer.teams:write', 'teams/{team_id}/invites/', 400),
|
||||
('get', 'organizer.teams:write', 'teams/{team_id}/tokens/', 200),
|
||||
('get', 'organizer.teams:write', 'teams/{team_id}/tokens/0/', 404),
|
||||
('delete', 'organizer.teams:write', 'teams/{team_id}/tokens/0/', 404),
|
||||
('post', 'organizer.teams:write', 'teams/{team_id}/tokens/', 400),
|
||||
('get', 'organizer.reusablemedia:read', 'reusablemedia/', 200),
|
||||
('get', 'organizer.reusablemedia:read', 'reusablemedia/1/', 404),
|
||||
('post', 'organizer.reusablemedia:write', 'reusablemedia/', 400),
|
||||
('patch', 'organizer.reusablemedia:write', 'reusablemedia/1/', 404),
|
||||
('put', 'organizer.reusablemedia:write', 'reusablemedia/1/', 404),
|
||||
('post', 'organizer.seatingplans:write', 'seatingplans/', 400),
|
||||
('patch', 'organizer.seatingplans:write', 'seatingplans/1/', 404),
|
||||
('put', 'organizer.seatingplans:write', 'seatingplans/1/', 404),
|
||||
]
|
||||
|
||||
|
||||
event_permission_root_urls = [
|
||||
('post', 'can_create_events', 400),
|
||||
('put', 'can_change_event_settings', 400),
|
||||
('patch', 'can_change_event_settings', 200),
|
||||
('delete', 'can_change_event_settings', 204),
|
||||
('post', 'organizer.events:create', 400),
|
||||
('put', 'event.settings.general:write', 400),
|
||||
('patch', 'event.settings.general:write', 200),
|
||||
('delete', 'event.settings.general:write', 204),
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def token_client(client, team):
|
||||
team.can_view_orders = True
|
||||
team.can_view_vouchers = True
|
||||
team.can_change_items = True
|
||||
team.limit_event_permissions["event.orders:read"] = True
|
||||
team.limit_event_permissions["event.vouchers:read"] = True
|
||||
team.limit_event_permissions["event.items:write"] = True
|
||||
team.save()
|
||||
t = team.tokens.create(name='Foo')
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
@@ -329,7 +337,7 @@ def test_event_allowed_all_events(token_client, team, organizer, event, url):
|
||||
@pytest.mark.parametrize("url", event_urls)
|
||||
def test_event_allowed_all_events_device(device_client, device, organizer, event, url):
|
||||
resp = device_client.get('/api/v1/organizers/{}/events/{}/{}'.format(organizer.slug, event.slug, url[1]))
|
||||
if url[0] is None or url[0] in device.permission_set():
|
||||
if url[0] is None or url[0] in device._event_permission_set():
|
||||
assert resp.status_code == 200
|
||||
else:
|
||||
assert resp.status_code == 403
|
||||
@@ -352,7 +360,7 @@ def test_event_allowed_limit_events_device(device_client, organizer, device, eve
|
||||
device.save()
|
||||
device.limit_events.add(event)
|
||||
resp = device_client.get('/api/v1/organizers/{}/events/{}/{}'.format(organizer.slug, event.slug, url[1]))
|
||||
if url[0] is None or url[0] in device.permission_set():
|
||||
if url[0] is None or url[0] in device._event_permission_set():
|
||||
assert resp.status_code == 200
|
||||
else:
|
||||
assert resp.status_code == 403
|
||||
@@ -387,8 +395,14 @@ def test_event_not_existing(token_client, organizer, url, event):
|
||||
@pytest.mark.parametrize("urlset", event_permission_sub_urls)
|
||||
def test_token_event_subresources_permission_allowed(token_client, team, organizer, event, urlset):
|
||||
team.all_events = True
|
||||
if urlset[1]:
|
||||
setattr(team, urlset[1], True)
|
||||
if urlset[1] is not None:
|
||||
for t in ((urlset[1],) if isinstance(urlset[1], str) else urlset[1]):
|
||||
if "organizer" in urlset[1]:
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions[t] = True
|
||||
else:
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions[t] = True
|
||||
team.save()
|
||||
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format(
|
||||
organizer.slug, event.slug, urlset[2]))
|
||||
@@ -402,7 +416,10 @@ def test_token_event_subresources_permission_not_allowed(token_client, team, org
|
||||
team.all_events = False
|
||||
else:
|
||||
team.all_events = True
|
||||
setattr(team, urlset[1], False)
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions.pop(urlset[1], None)
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions.pop(urlset[1], None)
|
||||
team.save()
|
||||
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format(
|
||||
organizer.slug, event.slug, urlset[2]))
|
||||
@@ -416,7 +433,14 @@ def test_token_event_subresources_permission_not_allowed(token_client, team, org
|
||||
@pytest.mark.parametrize("urlset", event_permission_root_urls)
|
||||
def test_token_event_permission_allowed(token_client, team, organizer, event, urlset):
|
||||
team.all_events = True
|
||||
setattr(team, urlset[1], True)
|
||||
if urlset[1] is not None:
|
||||
for t in ((urlset[1],) if isinstance(urlset[1], str) else urlset[1]):
|
||||
if "organizer" in urlset[1]:
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions[t] = True
|
||||
else:
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions[t] = True
|
||||
team.save()
|
||||
if urlset[0] == 'post':
|
||||
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/'.format(organizer.slug))
|
||||
@@ -429,7 +453,9 @@ def test_token_event_permission_allowed(token_client, team, organizer, event, ur
|
||||
@pytest.mark.parametrize("urlset", event_permission_root_urls)
|
||||
def test_token_event_permission_not_allowed(token_client, team, organizer, event, urlset):
|
||||
team.all_events = True
|
||||
setattr(team, urlset[1], False)
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions.pop(urlset[1], None)
|
||||
team.all_organizer_permissions = False
|
||||
team.save()
|
||||
if urlset[0] == 'post':
|
||||
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/'.format(organizer.slug))
|
||||
@@ -537,11 +563,11 @@ def test_update_session_activity(user_client, team, organizer, event):
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("urlset", event_permission_sub_urls)
|
||||
def test_device_subresource_permission_check(device_client, device, organizer, event, urlset):
|
||||
if urlset == ('get', 'can_change_event_settings', 'settings/', 200):
|
||||
if urlset == ('get', 'event.settings.general:write', 'settings/', 200):
|
||||
return
|
||||
resp = getattr(device_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format(
|
||||
organizer.slug, event.slug, urlset[2]))
|
||||
if urlset[1] is None or urlset[1] in device.permission_set():
|
||||
if urlset[1] is None or urlset[1] in device._event_permission_set():
|
||||
assert resp.status_code == urlset[3]
|
||||
else:
|
||||
if urlset[3] == 404:
|
||||
@@ -555,7 +581,8 @@ def test_device_subresource_permission_check(device_client, device, organizer, e
|
||||
def test_token_org_subresources_permission_allowed(token_client, team, organizer, event, urlset):
|
||||
team.all_events = True
|
||||
if urlset[1]:
|
||||
setattr(team, urlset[1], True)
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions[urlset[1]] = True
|
||||
team.save()
|
||||
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/{}'.format(
|
||||
organizer.slug, urlset[2].format(team_id=team.pk)))
|
||||
@@ -568,8 +595,8 @@ def test_token_org_subresources_permission_not_allowed(token_client, team, organ
|
||||
if urlset[1] is None:
|
||||
team.all_events = False
|
||||
else:
|
||||
team.all_events = True
|
||||
setattr(team, urlset[1], False)
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions.pop(urlset[1], None)
|
||||
team.save()
|
||||
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/{}'.format(
|
||||
organizer.slug, urlset[2].format(team_id=team.pk)))
|
||||
|
||||
@@ -119,7 +119,39 @@ def test_medium_list(token_client, organizer, event, medium):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_medium_detail(token_client, organizer, event, medium, giftcard, customer):
|
||||
def test_medium_detail_permission_missing(token_client, organizer, event, medium, giftcard, customer, team):
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions = {
|
||||
"organizer.reusablemedia:read": True,
|
||||
}
|
||||
team.save()
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/reusablemedia/{}/?expand=linked_giftcard'.format(
|
||||
organizer.slug, medium.pk
|
||||
)
|
||||
)
|
||||
assert resp.status_code == 403
|
||||
assert "No permission to access gift card details." in str(resp.data)
|
||||
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/reusablemedia/{}/?expand=customer'.format(
|
||||
organizer.slug, medium.pk
|
||||
)
|
||||
)
|
||||
assert resp.status_code == 403
|
||||
assert "No permission to access customer details." in str(resp.data)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_medium_detail(token_client, organizer, event, medium, giftcard, customer, team):
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions = {
|
||||
"organizer.reusablemedia:read": True,
|
||||
"organizer.customers:read": True,
|
||||
"organizer.giftcards:read": True,
|
||||
}
|
||||
team.save()
|
||||
|
||||
res = dict(TEST_MEDIUM_RES)
|
||||
res["id"] = medium.pk
|
||||
res["created"] = medium.created.isoformat().replace('+00:00', 'Z')
|
||||
@@ -340,7 +372,16 @@ def test_medium_lookup_not_found(token_client, organizer, organizer2, medium):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_medium_lookup_autocreate(token_client, organizer):
|
||||
def test_medium_lookup_autocreate(token_client, organizer, team):
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions = {
|
||||
"organizer.reusablemedia:read": True,
|
||||
"organizer.reusablemedia:write": True,
|
||||
"organizer.customers:read": True,
|
||||
"organizer.giftcards:read": True,
|
||||
}
|
||||
team.save()
|
||||
|
||||
# Disabled
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/reusablemedia/lookup/'.format(organizer.slug),
|
||||
@@ -386,7 +427,15 @@ def test_medium_lookup_autocreate(token_client, organizer):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_medium_autocreate_giftcard(token_client, organizer):
|
||||
def test_medium_autocreate_giftcard(token_client, organizer, team):
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions = {
|
||||
"organizer.reusablemedia:write": True,
|
||||
"organizer.reusablemedia:read": True,
|
||||
"organizer.customers:read": True,
|
||||
"organizer.giftcards:read": True,
|
||||
}
|
||||
team.save()
|
||||
organizer.settings.reusable_media_type_nfc_mf0aes_autocreate_giftcard = True
|
||||
organizer.settings.reusable_media_type_nfc_mf0aes_autocreate_giftcard_currency = 'USD'
|
||||
resp = token_client.post(
|
||||
|
||||
@@ -260,7 +260,8 @@ def test_all_subevents_list_filter(token_client, organizer, event, subevent):
|
||||
def test_subevent_create(team, token_client, organizer, event, subevent, meta_prop, item):
|
||||
meta_prop.choices = [{"key": "Conference", "label": {"en": "Conference"}}, {"key": "Workshop", "label": {"en": "Workshop"}}]
|
||||
meta_prop.save()
|
||||
team.can_change_organizer_settings = False
|
||||
team.limit_organizer_permissions = {"organizer.events:create": True}
|
||||
team.all_organizer_permissions = False
|
||||
team.save()
|
||||
organizer.meta_properties.create(
|
||||
name="protected", protected=True
|
||||
|
||||
@@ -31,6 +31,7 @@ def second_team(organizer, event):
|
||||
t = organizer.teams.create(
|
||||
name='User team',
|
||||
all_events=False,
|
||||
limit_event_permissions={"event.orders:read": True},
|
||||
)
|
||||
t.limit_events.add(event)
|
||||
return t
|
||||
@@ -41,8 +42,10 @@ TEST_TEAM_RES = {
|
||||
'can_change_teams': True, 'can_change_organizer_settings': True, 'can_manage_gift_cards': True,
|
||||
'can_manage_customers': True, 'can_manage_reusable_media': True,
|
||||
'can_change_event_settings': True, 'can_change_items': True, 'can_view_orders': True, 'can_change_orders': True,
|
||||
'can_view_vouchers': True, 'can_change_vouchers': True, 'can_checkin_orders': False,
|
||||
'can_view_vouchers': True, 'can_change_vouchers': True, 'can_checkin_orders': True,
|
||||
'require_2fa': False,
|
||||
'all_event_permissions': True, 'limit_event_permissions': [],
|
||||
'all_organizer_permissions': True, 'limit_organizer_permissions': [],
|
||||
}
|
||||
|
||||
SECOND_TEAM_RES = {
|
||||
@@ -50,9 +53,11 @@ SECOND_TEAM_RES = {
|
||||
'can_create_events': False,
|
||||
'can_manage_customers': False, 'can_manage_reusable_media': False,
|
||||
'can_change_teams': False, 'can_change_organizer_settings': False, 'can_manage_gift_cards': False,
|
||||
'can_change_event_settings': False, 'can_change_items': False, 'can_view_orders': False, 'can_change_orders': False,
|
||||
'can_change_event_settings': False, 'can_change_items': False, 'can_view_orders': True, 'can_change_orders': False,
|
||||
'can_view_vouchers': False, 'can_change_vouchers': False, 'can_checkin_orders': False,
|
||||
'require_2fa': False,
|
||||
'all_event_permissions': False, 'limit_event_permissions': ["event.orders:read"],
|
||||
'all_organizer_permissions': False, 'limit_organizer_permissions': [],
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +100,80 @@ def test_team_create(token_client, organizer, event):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_team_update(token_client, organizer, event, second_team):
|
||||
assert not second_team.can_change_event_settings
|
||||
def test_team_update(token_client, organizer, event, team, second_team):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'all_event_permission': False,
|
||||
'limit_event_permissions': ["event.settings.general:write"],
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
second_team.refresh_from_db()
|
||||
assert second_team.limit_event_permissions == {
|
||||
'event.settings.general:write': True,
|
||||
}
|
||||
assert not second_team.all_event_permissions
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'all_event_permission': False,
|
||||
'limit_event_permissions': ["INVALID"],
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert "invalid" in str(resp.data)
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, team.pk),
|
||||
{
|
||||
'limit_event_permissions': ["event.settings.general:write"],
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert "Do not set both" in str(resp.data)
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'all_organizer_permissions': False,
|
||||
'limit_organizer_permissions': ["organizer.devices:write"],
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert ("For permission group organizer.devices, the valid combinations of actions are '' or 'read' or "
|
||||
"'read,write' but you tried to set 'write'.") in str(resp.data)
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'all_organizer_permissions': True,
|
||||
'limit_organizer_permissions': ["organizer.events:create"],
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert "Do not set both" in str(resp.data)
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'all_events': True,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert "Do not set both" in str(resp.data)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.filterwarnings("ignore")
|
||||
def test_team_update_legacy_add_perm(token_client, organizer, event, second_team):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
@@ -107,15 +184,95 @@ def test_team_update(token_client, organizer, event, second_team):
|
||||
assert resp.status_code == 200
|
||||
second_team.refresh_from_db()
|
||||
assert second_team.can_change_event_settings
|
||||
assert second_team.limit_event_permissions == {
|
||||
"event.settings.general:write": True,
|
||||
"event.settings.payment:write": True,
|
||||
"event.settings.tax:write": True,
|
||||
"event.settings.invoicing:write": True,
|
||||
"event.subevents:write": True,
|
||||
"event.orders:read": True,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.filterwarnings("ignore")
|
||||
def test_team_update_legacy_add_all_perms(token_client, organizer, event, second_team):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'can_change_event_settings': True,
|
||||
'can_change_items': True,
|
||||
# can_view_orders omitted because already set
|
||||
'can_change_orders': True,
|
||||
'can_checkin_orders': True,
|
||||
'can_view_vouchers': True,
|
||||
'can_change_vouchers': True,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
second_team.refresh_from_db()
|
||||
assert second_team.all_event_permissions
|
||||
assert second_team.limit_event_permissions == {}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'all_events': True,
|
||||
'can_create_events': True,
|
||||
'can_change_organizer_settings': True,
|
||||
'can_change_teams': True,
|
||||
'can_manage_gift_cards': True,
|
||||
'can_manage_customers': True,
|
||||
'can_manage_reusable_media': True,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
second_team.refresh_from_db()
|
||||
assert second_team.all_organizer_permissions
|
||||
assert second_team.limit_organizer_permissions == {}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'can_change_teams': False,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
second_team.refresh_from_db()
|
||||
assert not second_team.all_organizer_permissions
|
||||
assert second_team.limit_organizer_permissions == {
|
||||
'organizer.settings.general:write': True,
|
||||
'organizer.giftcards:read': True,
|
||||
'organizer.giftcards:write': True,
|
||||
'organizer.events:create': True,
|
||||
'organizer.customers:read': True,
|
||||
'organizer.customers:write': True,
|
||||
'organizer.reusablemedia:read': True,
|
||||
'organizer.reusablemedia:write': True,
|
||||
'organizer.devices:read': True,
|
||||
'organizer.devices:write': True,
|
||||
'organizer.seatingplans:write': True,
|
||||
'organizer.outgoingmails:read': True,
|
||||
}
|
||||
assert resp.data["can_manage_customers"] is True
|
||||
assert resp.data["can_change_teams"] is False
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.filterwarnings("ignore")
|
||||
def test_team_update_legacy_and_new(token_client, organizer, event, second_team):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/teams/{}/'.format(organizer.slug, second_team.pk),
|
||||
{
|
||||
'can_change_event_settings': True,
|
||||
'all_organizer_permissions': True,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert "You cannot set deprecated and current permission attributes" in str(resp.data)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -242,7 +242,8 @@ def test_organizer_list(token_client, team, organizer, event, order, item, taxru
|
||||
assert resp.data["count"] == 0
|
||||
|
||||
team.all_events = True
|
||||
team.can_view_orders = False
|
||||
team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
team.all_event_permissions = False
|
||||
team.save()
|
||||
|
||||
resp = token_client.get(
|
||||
|
||||
@@ -48,7 +48,7 @@ def event():
|
||||
|
||||
@pytest.fixture
|
||||
def team(event):
|
||||
return event.organizer.teams.create(all_events=True, can_view_orders=True)
|
||||
return event.organizer.teams.create(all_events=True, all_event_permissions=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -105,7 +105,7 @@ def test_event_fail_invalid_config(event, user):
|
||||
assert s.error_counter == 1
|
||||
assert len(djmail.outbox) == 1
|
||||
assert djmail.outbox[0].subject == "Export failed"
|
||||
assert "Reason: Export type not found." in djmail.outbox[0].body
|
||||
assert "Reason: Export type not found" in djmail.outbox[0].body
|
||||
assert djmail.outbox[0].to == [user.email]
|
||||
|
||||
|
||||
@@ -143,7 +143,8 @@ def test_event_fail_user_no_permission(event, user, team):
|
||||
s.error_counter = 0
|
||||
s.save()
|
||||
|
||||
team.can_view_orders = False
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
team.save()
|
||||
|
||||
run_scheduled_exports(None)
|
||||
@@ -152,7 +153,7 @@ def test_event_fail_user_no_permission(event, user, team):
|
||||
assert s.error_counter == 1
|
||||
assert len(djmail.outbox) == 1
|
||||
assert djmail.outbox[0].subject == "Export failed"
|
||||
assert "Reason: Permission denied." in djmail.outbox[0].body
|
||||
assert "Reason: Export type not found or permission denied." in djmail.outbox[0].body
|
||||
assert djmail.outbox[0].to == [user.email]
|
||||
|
||||
|
||||
@@ -235,7 +236,7 @@ def test_organizer_fail_invalid_config(event, user):
|
||||
assert s.error_counter == 1
|
||||
assert len(djmail.outbox) == 1
|
||||
assert djmail.outbox[0].subject == "Export failed"
|
||||
assert "Reason: Export type not found." in djmail.outbox[0].body
|
||||
assert "Reason: Export type not found" in djmail.outbox[0].body
|
||||
assert djmail.outbox[0].to == [user.email]
|
||||
|
||||
|
||||
@@ -273,7 +274,8 @@ def test_organizer_fail_user_does_not_have_specific_permission(event, user, team
|
||||
s.error_counter = 0
|
||||
s.save()
|
||||
|
||||
team.can_manage_customers = False
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions = {"organizer.giftcards:write": True}
|
||||
team.save()
|
||||
|
||||
run_scheduled_exports(None)
|
||||
@@ -282,7 +284,7 @@ def test_organizer_fail_user_does_not_have_specific_permission(event, user, team
|
||||
assert s.error_counter == 1
|
||||
assert len(djmail.outbox) == 1
|
||||
assert djmail.outbox[0].subject == "Export failed"
|
||||
assert "Reason: Permission denied." in djmail.outbox[0].body
|
||||
assert "Reason: Export type not found or permission denied." in djmail.outbox[0].body
|
||||
assert djmail.outbox[0].to == [user.email]
|
||||
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ def order(event):
|
||||
|
||||
@pytest.fixture
|
||||
def team(event):
|
||||
return event.organizer.teams.create(all_events=True, can_view_orders=True)
|
||||
return event.organizer.teams.create(all_events=True, all_event_permissions=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -142,7 +142,8 @@ def test_notification_ignore_same_user(event, order, user, monkeypatch_on_commit
|
||||
@pytest.mark.django_db
|
||||
def test_notification_ignore_insufficient_permissions(event, order, user, team, monkeypatch_on_commit):
|
||||
djmail.outbox = []
|
||||
team.can_view_orders = False
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
team.save()
|
||||
user.notification_settings.create(
|
||||
method='mail', event=event, action_type='pretix.event.order.paid', enabled=True
|
||||
|
||||
@@ -66,13 +66,6 @@ def admin_request(admin, client):
|
||||
return r
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_invalid_permission(event, user):
|
||||
team = Team.objects.create(organizer=event.organizer)
|
||||
with pytest.raises(ValueError):
|
||||
team.has_permission('FOOOOOOBAR')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_any_event_permission_limited(event, user):
|
||||
user._teamcache = {}
|
||||
@@ -117,59 +110,59 @@ def test_any_event_permission_all(event, user):
|
||||
@pytest.mark.django_db
|
||||
def test_specific_event_permission_limited(event, user):
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
team = Team.objects.create(organizer=event.organizer, can_change_orders=True)
|
||||
team = Team.objects.create(organizer=event.organizer, limit_event_permissions={"event.orders:write": True})
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
team.members.add(user)
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
team.limit_events.add(event)
|
||||
user._teamcache = {}
|
||||
assert user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_event_settings')
|
||||
assert user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.settings.general:write')
|
||||
|
||||
assert user.has_event_permission(event.organizer, event, ('can_change_orders', 'can_change_event_settings'))
|
||||
assert not user.has_event_permission(event.organizer, event, ('can_change_teams', 'can_change_event_settings'))
|
||||
assert user.has_event_permission(event.organizer, event, ('event.orders:write', 'event.settings.general:write'))
|
||||
assert not user.has_event_permission(event.organizer, event, ('event.items:write', 'event.settings.general:write'))
|
||||
|
||||
team.can_change_orders = False
|
||||
team.limit_event_permissions = {}
|
||||
team.save()
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_specific_event_permission_all(event, user):
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
team = Team.objects.create(organizer=event.organizer, can_change_orders=True)
|
||||
team = Team.objects.create(organizer=event.organizer, limit_event_permissions={"event.orders:write": True})
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
team.members.add(user)
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
team.all_events = True
|
||||
team.save()
|
||||
user._teamcache = {}
|
||||
assert user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
team.can_change_orders = False
|
||||
team.limit_event_permissions = {}
|
||||
team.save()
|
||||
user._teamcache = {}
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_event_permissions_multiple_teams(event, user):
|
||||
team1 = Team.objects.create(organizer=event.organizer, can_change_orders=True, all_events=True)
|
||||
team2 = Team.objects.create(organizer=event.organizer, can_change_vouchers=True)
|
||||
team3 = Team.objects.create(organizer=event.organizer, can_change_event_settings=True)
|
||||
team1 = Team.objects.create(organizer=event.organizer, limit_event_permissions={"event.orders:write": True}, all_events=True)
|
||||
team2 = Team.objects.create(organizer=event.organizer, limit_event_permissions={"event.vouchers:write": True})
|
||||
team3 = Team.objects.create(organizer=event.organizer, limit_event_permissions={"event.settings.general:write": True})
|
||||
event2 = Event.objects.create(
|
||||
organizer=event.organizer, name='Dummy', slug='dummy2',
|
||||
date_from=now()
|
||||
@@ -180,12 +173,17 @@ def test_event_permissions_multiple_teams(event, user):
|
||||
team2.limit_events.add(event)
|
||||
team3.limit_events.add(event2)
|
||||
|
||||
assert user.has_event_permission(event.organizer, event, 'can_change_orders')
|
||||
assert user.has_event_permission(event.organizer, event, 'can_change_vouchers')
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_change_event_settings')
|
||||
assert user.get_event_permission_set(event.organizer, event) == {'can_change_orders', 'can_change_vouchers'}
|
||||
assert user.get_event_permission_set(event.organizer, event2) == {'can_change_orders', 'can_change_event_settings',
|
||||
'can_change_settings'}
|
||||
assert user.has_event_permission(event.organizer, event, 'event.orders:write')
|
||||
assert user.has_event_permission(event.organizer, event, 'event.vouchers:write')
|
||||
assert not user.has_event_permission(event.organizer, event, 'event.settings.general:write')
|
||||
assert user.get_event_permission_set(event.organizer, event) == {
|
||||
'event.orders:write', 'event.vouchers:write',
|
||||
'can_change_orders', 'can_change_vouchers',
|
||||
}
|
||||
assert user.get_event_permission_set(event.organizer, event2) == {
|
||||
'event.orders:write', 'event.settings.general:write', 'event.settings.general:write',
|
||||
'can_change_orders', 'can_change_event_settings', 'can_change_settings',
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -205,41 +203,47 @@ def test_any_organizer_permission(event, user):
|
||||
@pytest.mark.django_db
|
||||
def test_specific_organizer_permission(event, user):
|
||||
user._teamcache = {}
|
||||
assert not user.has_organizer_permission(event.organizer, 'can_create_events')
|
||||
assert not user.has_organizer_permission(event.organizer, 'organizer.events:create')
|
||||
|
||||
team = Team.objects.create(organizer=event.organizer, can_create_events=True)
|
||||
team = Team.objects.create(organizer=event.organizer, limit_organizer_permissions={"organizer.events:create": True})
|
||||
user._teamcache = {}
|
||||
assert not user.has_organizer_permission(event.organizer, 'can_create_events')
|
||||
assert not user.has_organizer_permission(event.organizer, 'organizer.events:create')
|
||||
|
||||
team.members.add(user)
|
||||
user._teamcache = {}
|
||||
assert user.has_organizer_permission(event.organizer, 'can_create_events')
|
||||
assert user.has_organizer_permission(event.organizer, ('can_create_events', 'can_change_organizer_settings'))
|
||||
assert user.has_organizer_permission(event.organizer, 'organizer.events:create')
|
||||
assert user.has_organizer_permission(event.organizer, ('organizer.events:create', 'organizer.settings.general:write'))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_organizer_permissions_multiple_teams(event, user):
|
||||
team1 = Team.objects.create(organizer=event.organizer, can_change_organizer_settings=True)
|
||||
team2 = Team.objects.create(organizer=event.organizer, can_create_events=True)
|
||||
team1 = Team.objects.create(organizer=event.organizer, limit_organizer_permissions={"organizer.settings.general:write": True})
|
||||
team2 = Team.objects.create(organizer=event.organizer, limit_organizer_permissions={"organizer.events:create": True})
|
||||
team1.members.add(user)
|
||||
team2.members.add(user)
|
||||
orga2 = Organizer.objects.create(slug='d2', name='d2')
|
||||
team3 = Team.objects.create(organizer=orga2, can_change_teams=True)
|
||||
team3 = Team.objects.create(organizer=orga2, limit_organizer_permissions={"organizer.teams:write": True})
|
||||
team3.members.add(user)
|
||||
|
||||
assert user.has_organizer_permission(event.organizer, 'can_create_events')
|
||||
assert user.has_organizer_permission(event.organizer, 'can_change_organizer_settings')
|
||||
assert not user.has_organizer_permission(event.organizer, 'can_change_teams')
|
||||
assert user.get_organizer_permission_set(event.organizer) == {'can_create_events', 'can_change_organizer_settings'}
|
||||
assert user.get_organizer_permission_set(orga2) == {'can_change_teams'}
|
||||
assert user.has_organizer_permission(event.organizer, 'organizer.events:create')
|
||||
assert user.has_organizer_permission(event.organizer, 'organizer.settings.general:write')
|
||||
assert not user.has_organizer_permission(event.organizer, 'organizer.teams:write')
|
||||
assert user.get_organizer_permission_set(event.organizer) == {
|
||||
'organizer.events:create', 'organizer.settings.general:write',
|
||||
'can_create_events', 'can_change_organizer_settings',
|
||||
}
|
||||
assert user.get_organizer_permission_set(orga2) == {
|
||||
'organizer.teams:write',
|
||||
'can_change_teams',
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_superuser(event, admin, admin_request):
|
||||
assert admin.has_organizer_permission(event.organizer, request=admin_request)
|
||||
assert admin.has_organizer_permission(event.organizer, 'can_create_events', request=admin_request)
|
||||
assert admin.has_organizer_permission(event.organizer, 'organizer.events:create', request=admin_request)
|
||||
assert admin.has_event_permission(event.organizer, event, request=admin_request)
|
||||
assert admin.has_event_permission(event.organizer, event, 'can_change_event_settings', request=admin_request)
|
||||
assert admin.has_event_permission(event.organizer, event, 'event.settings.general:write', request=admin_request)
|
||||
|
||||
assert 'arbitrary' not in admin.get_event_permission_set(event.organizer, event)
|
||||
assert 'arbitrary' not in admin.get_organizer_permission_set(event.organizer)
|
||||
@@ -266,9 +270,9 @@ def test_list_of_events(event, user, admin, admin_request):
|
||||
|
||||
assert not user.get_events_with_any_permission()
|
||||
|
||||
team1 = Team.objects.create(organizer=event.organizer, can_change_orders=True, all_events=True)
|
||||
team2 = Team.objects.create(organizer=event.organizer, can_change_vouchers=True)
|
||||
team3 = Team.objects.create(organizer=orga2, can_change_event_settings=True)
|
||||
team1 = Team.objects.create(organizer=event.organizer, limit_event_permissions={"event.orders:write": True}, all_events=True)
|
||||
team2 = Team.objects.create(organizer=event.organizer, limit_event_permissions={"event.vouchers:write": True})
|
||||
team3 = Team.objects.create(organizer=orga2, limit_event_permissions={"event.settings.general:write": True})
|
||||
team1.members.add(user)
|
||||
team2.members.add(user)
|
||||
team3.members.add(user)
|
||||
@@ -282,7 +286,7 @@ def test_list_of_events(event, user, admin, admin_request):
|
||||
assert event3 in events
|
||||
assert event4 not in events
|
||||
|
||||
events = list(user.get_events_with_permission('can_change_event_settings', request=admin_request))
|
||||
events = list(user.get_events_with_permission('event.settings.general:write', request=admin_request))
|
||||
assert event not in events
|
||||
assert event2 not in events
|
||||
assert event3 in events
|
||||
@@ -293,8 +297,73 @@ def test_list_of_events(event, user, admin, admin_request):
|
||||
assert set(event3.get_users_with_any_permission()) == {user}
|
||||
assert set(event4.get_users_with_any_permission()) == set()
|
||||
|
||||
assert set(event.get_users_with_permission('can_change_event_settings')) == set()
|
||||
assert set(event2.get_users_with_permission('can_change_event_settings')) == set()
|
||||
assert set(event3.get_users_with_permission('can_change_event_settings')) == {user}
|
||||
assert set(event4.get_users_with_permission('can_change_event_settings')) == set()
|
||||
assert set(event.get_users_with_permission('can_change_orders')) == {user}
|
||||
assert set(event.get_users_with_permission('event.settings.general:write')) == set()
|
||||
assert set(event2.get_users_with_permission('event.settings.general:write')) == set()
|
||||
assert set(event3.get_users_with_permission('event.settings.general:write')) == {user}
|
||||
assert set(event4.get_users_with_permission('event.settings.general:write')) == set()
|
||||
assert set(event.get_users_with_permission('event.orders:write')) == {user}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.filterwarnings("ignore")
|
||||
def test_check_with_legacy_permission_names(event, user):
|
||||
team1 = Team.objects.create(
|
||||
organizer=event.organizer,
|
||||
limit_event_permissions={"event.settings.general:write": True},
|
||||
limit_organizer_permissions={
|
||||
"organizer.giftcards:read": True,
|
||||
"organizer.giftcards:write": True,
|
||||
"organizer.reusablemedia:write": True,
|
||||
},
|
||||
all_events=True
|
||||
)
|
||||
team1.members.add(user)
|
||||
|
||||
# Team methods
|
||||
assert team1.has_event_permission('can_change_event_settings')
|
||||
assert team1.has_event_permission('can_change_settings')
|
||||
assert not team1.has_event_permission('can_view_orders')
|
||||
assert team1.has_organizer_permission('can_manage_gift_cards')
|
||||
assert not team1.has_organizer_permission('can_manage_reusable_media')
|
||||
assert team1.organizer_permission_set() == {
|
||||
"organizer.giftcards:read",
|
||||
"organizer.giftcards:write",
|
||||
"organizer.reusablemedia:write",
|
||||
"can_manage_gift_cards",
|
||||
}
|
||||
assert team1.organizer_permission_set(include_legacy=False) == {
|
||||
"organizer.giftcards:read",
|
||||
"organizer.giftcards:write",
|
||||
"organizer.reusablemedia:write",
|
||||
}
|
||||
assert team1.event_permission_set() == {
|
||||
"event.settings.general:write", "can_change_event_settings", "can_change_settings",
|
||||
}
|
||||
assert team1.event_permission_set(include_legacy=False) == {
|
||||
"event.settings.general:write",
|
||||
}
|
||||
|
||||
# User methods
|
||||
user._teamcache = {}
|
||||
assert user.get_event_permission_set(event.organizer, event) == {
|
||||
"event.settings.general:write", "can_change_event_settings", "can_change_settings",
|
||||
}
|
||||
assert user.get_organizer_permission_set(event.organizer) == {
|
||||
"organizer.giftcards:read",
|
||||
"organizer.giftcards:write",
|
||||
"organizer.reusablemedia:write",
|
||||
"can_manage_gift_cards",
|
||||
}
|
||||
assert user.has_event_permission(event.organizer, event, 'can_change_event_settings')
|
||||
assert user.has_event_permission(event.organizer, event, 'can_change_settings')
|
||||
assert not user.has_event_permission(event.organizer, event, 'can_view_orders')
|
||||
assert user.has_organizer_permission(event.organizer, 'can_manage_gift_cards')
|
||||
assert not user.has_organizer_permission(event.organizer, 'can_manage_reusable_media')
|
||||
assert user.get_events_with_permission("can_change_event_settings").get() == event
|
||||
assert not user.get_events_with_permission("can_view_orders").exists()
|
||||
assert user.get_organizers_with_permission("can_manage_gift_cards").get() == event.organizer
|
||||
assert not user.get_organizers_with_permission("can_manage_reusable_media").exists()
|
||||
|
||||
# Event methods
|
||||
assert event.get_users_with_permission("can_change_event_settings").get() == user
|
||||
assert not event.get_users_with_permission("can_view_orders").exists()
|
||||
|
||||
@@ -1123,7 +1123,7 @@ class Obligatory2FATest(TestCase):
|
||||
session.save()
|
||||
|
||||
organizer = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
team = Team.objects.create(organizer=organizer, can_change_teams=True, name='Admin team')
|
||||
team = Team.objects.create(organizer=organizer, all_event_permissions=True, name='Admin team')
|
||||
team.members.add(self.user)
|
||||
self.user.require_2fa = False
|
||||
self.user.save()
|
||||
|
||||
@@ -61,7 +61,7 @@ def dashboard_env():
|
||||
item_ticket = Item.objects.create(event=event, name="Ticket", default_price=23, admission=True)
|
||||
item_mascot = Item.objects.create(event=event, name="Mascot", default_price=10, admission=False)
|
||||
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=o, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
@@ -139,7 +139,7 @@ def checkin_list_env():
|
||||
# permission
|
||||
orga = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
team = Team.objects.create(organizer=orga, can_view_orders=True, can_change_orders=True)
|
||||
team = Team.objects.create(organizer=orga, all_event_permissions=True)
|
||||
team.members.add(user)
|
||||
|
||||
# event
|
||||
@@ -321,7 +321,7 @@ def test_manual_checkins_revert_requires_order_change_permission(client, checkin
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
with scopes_disabled():
|
||||
assert not checkin_list_env[5][3].checkins.exists()
|
||||
Team.objects.update(can_change_orders=False, can_checkin_orders=True)
|
||||
Team.objects.update(all_event_permissions=False, limit_event_permissions={"event.orders:checkin": True})
|
||||
client.post('/control/event/dummy/dummy/checkinlists/{}/bulk_action'.format(checkin_list_env[6].pk), {
|
||||
'checkin': [checkin_list_env[5][3].pk]
|
||||
})
|
||||
@@ -363,7 +363,7 @@ def checkin_list_with_addon_env():
|
||||
# permission
|
||||
orga = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
team = Team.objects.create(organizer=orga, can_view_orders=True, can_change_orders=True)
|
||||
team = Team.objects.create(organizer=orga, all_event_permissions=True)
|
||||
team.members.add(user)
|
||||
|
||||
# event
|
||||
@@ -466,7 +466,7 @@ class CheckinListFormTest(SoupTest):
|
||||
date_from=datetime(2013, 12, 26, tzinfo=timezone.utc),
|
||||
)
|
||||
self.event1.settings.timezone = 'Europe/Berlin'
|
||||
t = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_view_orders=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -85,7 +85,7 @@ def order(event, customer):
|
||||
def admin_user(organizer):
|
||||
u = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
admin_team = Team.objects.create(
|
||||
organizer=organizer, can_manage_customers=True, can_change_organizer_settings=True,
|
||||
organizer=organizer, all_organizer_permissions=True,
|
||||
name='Admin team'
|
||||
)
|
||||
admin_team.members.add(u)
|
||||
|
||||
@@ -55,7 +55,7 @@ def admin_user(admin_team):
|
||||
|
||||
@pytest.fixture
|
||||
def admin_team(organizer):
|
||||
return Team.objects.create(organizer=organizer, can_change_organizer_settings=True, name='Admin team')
|
||||
return Team.objects.create(organizer=organizer, all_organizer_permissions=True, name='Admin team')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -76,13 +76,16 @@ class EventsTest(SoupTest):
|
||||
date_from=datetime.datetime(2014, 9, 5, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
|
||||
self.team1 = Team.objects.create(organizer=self.orga1, can_create_events=True, can_change_event_settings=True,
|
||||
can_change_items=True)
|
||||
self.team1 = Team.objects.create(
|
||||
organizer=self.orga1,
|
||||
name="T1",
|
||||
all_event_permissions=True,
|
||||
limit_organizer_permissions={"organizer.events:create": True}
|
||||
)
|
||||
self.team1.members.add(self.user)
|
||||
self.team1.limit_events.add(self.event1)
|
||||
|
||||
self.team2 = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_change_items=True,
|
||||
can_change_orders=True, can_change_vouchers=True)
|
||||
self.team2 = Team.objects.create(organizer=self.orga1, name="T2", all_event_permissions=True)
|
||||
self.team2.members.add(self.user)
|
||||
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
@@ -339,7 +342,7 @@ class EventsTest(SoupTest):
|
||||
self.orga1.refresh_from_db()
|
||||
assert "tests.testdummyhybrid" not in self.orga1.plugins
|
||||
|
||||
t2 = Team.objects.create(organizer=self.orga1, can_change_organizer_settings=True)
|
||||
t2 = Team.objects.create(organizer=self.orga1, all_organizer_permissions=True, all_event_permissions=True)
|
||||
t2.members.add(self.user)
|
||||
|
||||
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
|
||||
@@ -1262,6 +1265,265 @@ class EventsTest(SoupTest):
|
||||
})
|
||||
assert doc.select(".has-error")
|
||||
|
||||
def test_create_event_copy_from_other_org_validates_source_permissions(self):
|
||||
# To prevent leaks of e.g. settings contents, a user may only copy from one organizer to the other
|
||||
# if they have basically all permissions on the old event for all data that may be copied.
|
||||
self.team1.all_event_permissions = False
|
||||
self.team1.limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
|
||||
self.team1.save()
|
||||
team3 = Team.objects.create(organizer=self.orga2, all_event_permissions=True, all_organizer_permissions=True)
|
||||
team3.members.add(self.user)
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'foundation',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'foundation-organizer': self.orga2.pk,
|
||||
'foundation-locales': ('en', 'de')
|
||||
})
|
||||
assert doc.select("#id_basics-name_0")
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'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 doc.select("#id_copy-copy_from_event")
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'copy',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'copy-copy_from_event': self.event1.pk
|
||||
})
|
||||
assert doc.select(".alert-danger")
|
||||
assert "sufficient level of access" in doc.select(".has-error")[0].text
|
||||
|
||||
def test_create_event_clone_from_other_org_validates_source_permissions(self):
|
||||
# To prevent leaks of e.g. settings contents, a user may only copy from one organizer to the other
|
||||
# if they have basically all permissions on the old event for all data that may be copied.
|
||||
self.team1.all_event_permissions = False
|
||||
self.team1.limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
|
||||
self.team1.save()
|
||||
team3 = Team.objects.create(organizer=self.orga2, all_event_permissions=True, all_organizer_permissions=True)
|
||||
team3.members.add(self.user)
|
||||
|
||||
doc = self.post_doc(f'/control/events/add?clone={self.event1.pk}', {
|
||||
'event_wizard-current_step': 'foundation',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'foundation-organizer': self.orga2.pk,
|
||||
'foundation-locales': ('en', 'de')
|
||||
})
|
||||
assert doc.select(".alert-danger")
|
||||
assert "sufficient level of access" in doc.select(".has-error")[0].text
|
||||
|
||||
def test_create_event_copy_from_same_org_creates_new_team_with_same_permissions(self):
|
||||
# To prevent unwanted permission escalations, when a user copies an event and a new team is created to make
|
||||
# sure they can access the new event, the new event must be created with the same level of access they have
|
||||
# on the old event.
|
||||
self.team1.all_event_permissions = False
|
||||
self.team1.limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
|
||||
self.team1.save()
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'foundation',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'foundation-organizer': self.orga1.pk,
|
||||
'foundation-locales': ('en', 'de')
|
||||
})
|
||||
assert doc.select("#id_basics-name_0")
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'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 doc.select("#id_copy-copy_from_event")
|
||||
|
||||
self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'copy',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'copy-copy_from_event': self.event1.pk
|
||||
})
|
||||
with scopes_disabled():
|
||||
ev = Event.objects.get(slug='33c3')
|
||||
new_team = Team.objects.get(limit_events=ev, members=self.user)
|
||||
assert new_team.pk > self.team2.pk
|
||||
assert new_team.all_event_permissions is False
|
||||
assert new_team.all_organizer_permissions is False
|
||||
assert new_team.limit_event_permissions == {"event.settings.general:write": True, "event.orders:read": True}
|
||||
assert new_team.limit_organizer_permissions == {}
|
||||
assert new_team.all_events is False
|
||||
assert new_team.limit_events.get() == ev
|
||||
|
||||
def test_create_event_clone_from_same_org_creates_new_team_with_same_permissions(self):
|
||||
# To prevent unwanted permission escalations, when a user copies an event and a new team is created to make
|
||||
# sure they can access the new event, the new event must be created with the same level of access they have
|
||||
# on the old event.
|
||||
self.team1.all_event_permissions = False
|
||||
self.team1.limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
|
||||
self.team1.save()
|
||||
|
||||
doc = self.post_doc(f'/control/events/add?clone={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-name_0")
|
||||
|
||||
self.post_doc(f'/control/events/add?clone={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',
|
||||
})
|
||||
with scopes_disabled():
|
||||
ev = Event.objects.get(slug='33c3')
|
||||
new_team = Team.objects.get(limit_events=ev, members=self.user)
|
||||
assert new_team.pk > self.team2.pk
|
||||
assert new_team.all_event_permissions is False
|
||||
assert new_team.all_organizer_permissions is False
|
||||
assert new_team.limit_event_permissions == {"event.settings.general:write": True, "event.orders:read": True}
|
||||
assert new_team.limit_organizer_permissions == {}
|
||||
assert new_team.all_events is False
|
||||
assert new_team.limit_events.get() == ev
|
||||
|
||||
def test_create_event_copy_from_same_org_validates_selected_team_permissions(self):
|
||||
# To prevent unwanted permission escalations, when a user copies an event and selects the team the new event
|
||||
# should be attached to, this new team may not have higher permissions than the permissions the user holds for
|
||||
# the event that is copied from.
|
||||
self.team1.all_event_permissions = False
|
||||
self.team1.limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
|
||||
self.team1.save()
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'foundation',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'foundation-organizer': self.orga1.pk,
|
||||
'foundation-locales': ('en', 'de')
|
||||
})
|
||||
assert doc.select("#id_basics-name_0")
|
||||
assert doc.select("#id_basics-team")
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'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-team': self.team2.pk,
|
||||
'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 doc.select("#id_copy-copy_from_event")
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'copy',
|
||||
'event_wizard-prefix': 'event_wizard',
|
||||
'copy-copy_from_event': self.event1.pk
|
||||
})
|
||||
assert doc.select(".alert-danger")
|
||||
assert "less access than" in doc.select(".has-error")[0].text
|
||||
|
||||
def test_create_event_clone_from_same_org_validates_selected_team_permissions(self):
|
||||
# To prevent unwanted permission escalations, when a user copies an event and selects the team the new event
|
||||
# should be attached to, this new team may not have higher permissions than the permissions the user holds for
|
||||
# the event that is copied from.
|
||||
self.team1.all_event_permissions = False
|
||||
self.team1.limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
|
||||
self.team1.save()
|
||||
|
||||
doc = self.post_doc(f'/control/events/add?clone={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-name_0")
|
||||
assert doc.select("#id_basics-team")
|
||||
|
||||
doc = self.post_doc(f'/control/events/add?clone={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-team': self.team2.pk,
|
||||
'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 "would give you more access than" in doc.select(".has-error")[0].text
|
||||
|
||||
|
||||
class EventDeletionTest(SoupTest):
|
||||
@scopes_disabled()
|
||||
@@ -1276,8 +1538,7 @@ class EventDeletionTest(SoupTest):
|
||||
has_subevents=False
|
||||
)
|
||||
|
||||
t = Team.objects.create(organizer=self.orga1, can_create_events=True, can_change_event_settings=True,
|
||||
can_change_items=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_organizer_permissions=True, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.ticket = self.event1.items.create(name='Early-bird ticket',
|
||||
|
||||
@@ -23,7 +23,9 @@ import datetime
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from bs4 import BeautifulSoup
|
||||
from django.utils.timezone import now
|
||||
from tests.base import extract_form_fields
|
||||
|
||||
from pretix.base.models import (
|
||||
Event, Item, Organizer, ScheduledEventExport, ScheduledOrganizerExport,
|
||||
@@ -40,8 +42,7 @@ def env():
|
||||
)
|
||||
event.settings.set("ticketoutput_testdummy__enabled", True)
|
||||
user = User.objects.create_user("dummy@dummy.dummy", "dummy")
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True, can_manage_customers=True,
|
||||
can_change_event_settings=True)
|
||||
t = Team.objects.create(organizer=o, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
@@ -163,7 +164,8 @@ def test_event_export_schedule(client, env):
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_event_limited_permission(client, env):
|
||||
env[2].can_change_event_settings = False
|
||||
env[2].all_event_permissions = False
|
||||
env[2].limit_event_permissions = {"event.orders:read": True}
|
||||
env[2].save()
|
||||
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
|
||||
|
||||
@@ -199,7 +201,7 @@ def test_event_limited_permission(client, env):
|
||||
response = client.get(f"/control/event/dummy/dummy/orders/export/{s2.pk}/delete")
|
||||
assert response.status_code == 404
|
||||
|
||||
env[2].can_change_event_settings = True
|
||||
env[2].limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
|
||||
env[2].save()
|
||||
response = client.get("/control/event/dummy/dummy/orders/export/")
|
||||
assert b"RULE1" in response.content
|
||||
@@ -330,7 +332,8 @@ def test_organizer_export_schedule(client, env):
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_organizer_limited_permission(client, env):
|
||||
env[2].can_change_organizer_settings = False
|
||||
env[2].all_organizer_permissions = False
|
||||
env[2].all_event_permissions = True
|
||||
env[2].save()
|
||||
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
|
||||
|
||||
@@ -366,7 +369,7 @@ def test_organizer_limited_permission(client, env):
|
||||
response = client.post(f"/control/organizer/dummy/export/{s2.pk}/run")
|
||||
assert response.status_code == 404
|
||||
|
||||
env[2].can_change_organizer_settings = True
|
||||
env[2].limit_organizer_permissions = {"organizer.settings.general:write": True}
|
||||
env[2].save()
|
||||
response = client.get("/control/organizer/dummy/export/")
|
||||
assert b"RULE1" in response.content
|
||||
@@ -377,3 +380,197 @@ def test_organizer_limited_permission(client, env):
|
||||
assert response.status_code == 200
|
||||
response = client.post(f"/control/organizer/dummy/export/{s2.pk}/run")
|
||||
assert response.status_code == 302
|
||||
|
||||
|
||||
def _can_see_but_not_edit_org_export(client, user, scheduled):
|
||||
client.login(email=user.email, password="dummy")
|
||||
|
||||
response = client.get("/control/organizer/dummy/export/")
|
||||
assert f"export/{scheduled.pk}/delete".encode() in response.content
|
||||
response = client.get(f"/control/organizer/dummy/export/?identifier={scheduled.export_identifier}&scheduled={scheduled.pk}")
|
||||
if response.status_code == 404:
|
||||
return False
|
||||
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content, "lxml")
|
||||
form_data = extract_form_fields(doc.select("form[data-asynctask]")[0])
|
||||
form_data["schedule"] = "save"
|
||||
|
||||
response = client.post(f"/control/organizer/dummy/export/?identifier={scheduled.export_identifier}&scheduled={scheduled.pk}",
|
||||
data=form_data, follow=True)
|
||||
assert response.status_code == 200
|
||||
|
||||
return b"alert-success" in response.content and b"does not have sufficient permission" not in response.content
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_organizer_edit_restrictions(client, env):
|
||||
# This tests the prevention of a possible privilege escalation where user A creates a scheduled export and
|
||||
# user B has settings permission (= they can see the export configuration), but not enough permission
|
||||
# to run the export themselves. Without this check, user B could modify the export and add themselves
|
||||
# as a recipient. Thereby, user B would gain access to data they can't have.
|
||||
user1 = env[1]
|
||||
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
|
||||
|
||||
event1 = env[0]
|
||||
event2 = Event.objects.create(
|
||||
organizer=env[0].organizer, name="Dummy", slug="dummy2",
|
||||
date_from=now(), plugins="pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy"
|
||||
)
|
||||
|
||||
team1 = env[2]
|
||||
team1.all_organizer_permissions = False
|
||||
team1.all_event_permissions = False
|
||||
team1.all_events = False
|
||||
team1.limit_organizer_permissions = {"organizer.settings.general:write": True}
|
||||
team1.limit_event_permissions = {"event.orders:read": True, "event.settings.general:write": True}
|
||||
team1.save()
|
||||
team1.limit_events.add(event1)
|
||||
|
||||
team2 = env[0].organizer.teams.create(
|
||||
all_organizer_permissions=False, all_event_permissions=False, all_events=False,
|
||||
limit_event_permissions={"event.orders:read": True},
|
||||
limit_organizer_permissions={"organizer.giftcards:read": True}
|
||||
)
|
||||
team2.limit_events.add(event2)
|
||||
team2.members.add(user2)
|
||||
|
||||
# Scenario 1
|
||||
# User 2 created an export for all events. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, but can't change it, because they
|
||||
# don't have access to all events.
|
||||
s1 = ScheduledOrganizerExport.objects.create(
|
||||
organizer=env[0].organizer,
|
||||
owner=user2,
|
||||
export_identifier="dummy_orders",
|
||||
export_form_data={"all_events": True, "events": []},
|
||||
mail_subject="Test",
|
||||
mail_template="Test",
|
||||
schedule_rrule="DTSTART:20230118T000000\nRRULE:FREQ=DAILY;INTERVAL=1;WKST=MO",
|
||||
schedule_rrule_time=datetime.time(2, 30, 0)
|
||||
)
|
||||
assert _can_see_but_not_edit_org_export(client, user2, s1)
|
||||
assert not _can_see_but_not_edit_org_export(client, user1, s1)
|
||||
|
||||
# Scenario 2
|
||||
# User 2 created an export for all events. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, and change it, because they
|
||||
# have access to all events.
|
||||
team1.all_events = True
|
||||
team1.save()
|
||||
assert _can_see_but_not_edit_org_export(client, user2, s1)
|
||||
assert _can_see_but_not_edit_org_export(client, user1, s1)
|
||||
|
||||
# Scenario 3
|
||||
# User 2 created an export for a specific event. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, but can't change it, because they
|
||||
# don't have access to that event.
|
||||
team1.all_events = False
|
||||
team1.save()
|
||||
s1.export_form_data = {"all_events": False, "events": [event2.pk]}
|
||||
s1.save()
|
||||
assert _can_see_but_not_edit_org_export(client, user2, s1)
|
||||
assert not _can_see_but_not_edit_org_export(client, user1, s1)
|
||||
|
||||
# Scenario 4
|
||||
# User 2 created an export for a specific event. User 2 can edit it, because they own it.
|
||||
# User 1 can see it, because they have permission to see scheduled exports, and change it, because they
|
||||
# have access to that event.
|
||||
team1.limit_events.add(event2)
|
||||
assert _can_see_but_not_edit_org_export(client, user2, s1)
|
||||
assert _can_see_but_not_edit_org_export(client, user1, s1)
|
||||
|
||||
# Scenario 5
|
||||
# User 2 created an export that requires a special permission on organizer level
|
||||
# user 1 can see it, because they have permission to see scheduled exports, but can't change it, because they lack
|
||||
# that special permission
|
||||
s2 = ScheduledOrganizerExport.objects.create(
|
||||
organizer=env[0].organizer,
|
||||
owner=user2,
|
||||
export_identifier="giftcardlist",
|
||||
mail_subject="Test",
|
||||
mail_template="Test",
|
||||
schedule_rrule="DTSTART:20230118T000000\nRRULE:FREQ=DAILY;INTERVAL=1;WKST=MO",
|
||||
schedule_rrule_time=datetime.time(2, 30, 0)
|
||||
)
|
||||
assert _can_see_but_not_edit_org_export(client, user2, s2)
|
||||
assert not _can_see_but_not_edit_org_export(client, user1, s2)
|
||||
|
||||
# Scenario 6
|
||||
# User 2 created an export that requires a special permission on organizer level
|
||||
# user 1 can see it, because they have permission to see scheduled exports, and change it, because they have
|
||||
# that special permission
|
||||
team1.limit_organizer_permissions["organizer.giftcards:read"] = True
|
||||
team1.save()
|
||||
assert _can_see_but_not_edit_org_export(client, user2, s2)
|
||||
assert _can_see_but_not_edit_org_export(client, user1, s2)
|
||||
|
||||
|
||||
def _can_see_but_not_edit_event_export(client, user, scheduled):
|
||||
client.login(email=user.email, password="dummy")
|
||||
|
||||
response = client.get("/control/event/dummy/dummy/orders/export/")
|
||||
assert f"export/{scheduled.pk}/delete".encode() in response.content
|
||||
response = client.get(f"/control/event/dummy/dummy/orders/export/?identifier={scheduled.export_identifier}&scheduled={scheduled.pk}")
|
||||
if response.status_code == 404:
|
||||
return False
|
||||
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content, "lxml")
|
||||
form_data = extract_form_fields(doc.select("form[data-asynctask]")[0])
|
||||
form_data["schedule"] = "save"
|
||||
|
||||
response = client.post(f"/control/event/dummy/dummy/orders/export/?identifier={scheduled.export_identifier}&scheduled={scheduled.pk}",
|
||||
data=form_data, follow=True)
|
||||
assert response.status_code == 200
|
||||
|
||||
return b"alert-success" in response.content and b"does not have sufficient permission" not in response.content
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_event_edit_restrictions(client, env):
|
||||
# This tests the prevention of a possible privilege escalation where user A creates a scheduled export and
|
||||
# user B has settings permission (= they can see the export configuration), but not enough permission
|
||||
# to run the export themselves. Without this check, user B could modify the export and add themselves
|
||||
# as a recipient. Thereby, user B would gain access to data they can't have.
|
||||
user1 = env[1]
|
||||
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
|
||||
event1 = env[0]
|
||||
|
||||
team1 = env[2]
|
||||
team1.all_organizer_permissions = False
|
||||
team1.all_event_permissions = False
|
||||
team1.all_events = False
|
||||
team1.limit_organizer_permissions = {"organizer.settings.general:write": True}
|
||||
team1.limit_event_permissions = {"event.orders:read": True, "event.settings.general:write": True}
|
||||
team1.save()
|
||||
team1.limit_events.add(event1)
|
||||
|
||||
team2 = env[0].organizer.teams.create(
|
||||
all_organizer_permissions=False, all_event_permissions=False, all_events=False,
|
||||
limit_event_permissions={"event.orders:read": True, "event.vouchers:read": True},
|
||||
limit_organizer_permissions={"organizer.giftcards:read": True}
|
||||
)
|
||||
team2.limit_events.add(event1)
|
||||
team2.members.add(user2)
|
||||
|
||||
s2 = ScheduledEventExport.objects.create(
|
||||
event=event1,
|
||||
owner=user2,
|
||||
export_identifier="dummy_vouchers",
|
||||
mail_subject="Test",
|
||||
mail_template="Test",
|
||||
schedule_rrule="DTSTART:20230118T000000\nRRULE:FREQ=DAILY;INTERVAL=1;WKST=MO",
|
||||
schedule_rrule_time=datetime.time(2, 30, 0)
|
||||
)
|
||||
assert _can_see_but_not_edit_event_export(client, user2, s2)
|
||||
assert not _can_see_but_not_edit_event_export(client, user1, s2)
|
||||
|
||||
# Scenario 6
|
||||
# User 2 created an export that requires a special permission on organizer level
|
||||
# user 1 can see it, because they have permission to see scheduled exports, and change it, because they have
|
||||
# that special permission
|
||||
team1.limit_event_permissions["event.vouchers:read"] = True
|
||||
team1.save()
|
||||
assert _can_see_but_not_edit_event_export(client, user2, s2)
|
||||
assert _can_see_but_not_edit_event_export(client, user1, s2)
|
||||
|
||||
@@ -51,15 +51,14 @@ def gift_card(organizer):
|
||||
@pytest.fixture
|
||||
def admin_user(organizer):
|
||||
u = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
admin_team = Team.objects.create(organizer=organizer, can_manage_gift_cards=True, name='Admin team',
|
||||
can_change_organizer_settings=True)
|
||||
admin_team = Team.objects.create(organizer=organizer, name='Admin team', all_organizer_permissions=True)
|
||||
admin_team.members.add(u)
|
||||
return u
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def team2(admin_user, organizer2):
|
||||
admin_team = Team.objects.create(organizer=organizer2, can_manage_gift_cards=True, name='Admin team')
|
||||
admin_team = Team.objects.create(organizer=organizer2, name='Admin team', all_organizer_permissions=True)
|
||||
admin_team.members.add(admin_user)
|
||||
|
||||
|
||||
@@ -213,8 +212,8 @@ def test_typeahead(organizer, admin_user, client, gift_card):
|
||||
assert d == {"results": [{"id": gift_card.pk, "text": gift_card.secret}], "pagination": {"more": False}}
|
||||
|
||||
# Unprivileged user can only do exact match
|
||||
team.can_manage_gift_cards = False
|
||||
team.can_manage_reusable_media = True
|
||||
team.all_organizer_permissions = False
|
||||
team.limit_organizer_permissions = {"organizer.reusablemedia:write": True, "organizer.reusablemedia:read": True}
|
||||
team.save()
|
||||
|
||||
r = client.get('/control/organizer/dummy/giftcards/select2?query=' + gift_card.secret[0:3])
|
||||
|
||||
@@ -57,9 +57,9 @@ class ItemFormTest(SoupTest):
|
||||
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
self.item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1)
|
||||
t = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_change_items=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.team = Team.objects.create(organizer=self.orga1, all_event_permissions=True)
|
||||
self.team.members.add(self.user)
|
||||
self.team.limit_events.add(self.event1)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
|
||||
@@ -270,6 +270,14 @@ class QuestionsTest(ItemFormTest):
|
||||
tbl = doc.select('.container-fluid table.table-bordered tbody')[0]
|
||||
assert tbl.select('tr')[0].select('td')[0].text.strip() == '42'
|
||||
|
||||
# Test permission requirement
|
||||
self.team.all_event_permissions = False
|
||||
self.team.limit_event_permissions = {}
|
||||
self.team.save()
|
||||
doc = self.get_doc('/control/event/%s/%s/questions/%s/' % (self.orga1.slug, self.event1.slug, c.id))
|
||||
assert not doc.select('.container-fluid table.table-bordered tbody')
|
||||
assert doc.select('.empty-collection')
|
||||
|
||||
def test_set_dependency(self):
|
||||
with scopes_disabled():
|
||||
q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True)
|
||||
|
||||
@@ -47,7 +47,7 @@ class MailSettingPreviewTest(SoupTest):
|
||||
)
|
||||
self.locale_event.settings.locales = ['en', 'de-informal']
|
||||
self.locale_event.save()
|
||||
t = Team.objects.create(organizer=self.orga1, can_change_items=True, can_change_event_settings=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.locale_event)
|
||||
t.limit_events.add(self.event1)
|
||||
|
||||
@@ -35,8 +35,7 @@ def env():
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.paypal'
|
||||
)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True,
|
||||
can_change_vouchers=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
return event, user
|
||||
|
||||
@@ -67,7 +67,7 @@ def env():
|
||||
)
|
||||
event.settings.set('ticketoutput_testdummy__enabled', True)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True, can_manage_customers=True)
|
||||
t = Team.objects.create(organizer=o, all_event_permissions=True, all_organizer_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
o = Order.objects.create(
|
||||
@@ -1422,7 +1422,7 @@ class OrderChangeTests(SoupTest):
|
||||
self.quota.items.add(self.ticket)
|
||||
self.quota.items.add(self.shirt)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=o, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(self.event)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -56,7 +56,7 @@ def env():
|
||||
)
|
||||
event.settings.set('ticketoutput_testdummy__enabled', True)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True, can_manage_customers=True)
|
||||
t = Team.objects.create(organizer=o, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket',
|
||||
|
||||
@@ -52,8 +52,7 @@ class OrganizerTest(SoupTest):
|
||||
plugins='pretix.plugins.banktransfer,tests.testdummy'
|
||||
)
|
||||
|
||||
t = Team.objects.create(organizer=self.orga1, can_create_events=True, can_change_event_settings=True,
|
||||
can_change_items=True, can_change_organizer_settings=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_organizer_permissions=True, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ from pretix.base.models import Event, Order, Organizer, Team, User
|
||||
|
||||
@pytest.fixture
|
||||
def env():
|
||||
o = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
o = Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
|
||||
event = Event.objects.create(
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
@@ -292,7 +292,7 @@ def test_wrong_event(perf_patch, client, env, url):
|
||||
organizer=env[2], name='Dummy', slug='dummy2',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
t = Team.objects.create(pk=2, organizer=env[2], can_change_event_settings=True)
|
||||
t = Team.objects.create(pk=2, organizer=env[2], all_event_permissions=True)
|
||||
t.members.add(env[1])
|
||||
t.limit_events.add(event2)
|
||||
|
||||
@@ -307,115 +307,114 @@ HTTP_POST = "post"
|
||||
HTTP_GET = "get"
|
||||
|
||||
event_permission_urls = [
|
||||
("can_change_event_settings", "live/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "delete/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "dangerzone/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/plugins", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/payment", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tickets", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/email", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/email/setup", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/cancel", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/invoice", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/widget", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/invoice/preview", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/1/", 404, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/1/delete", 404, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/1/default", 404, HTTP_POST),
|
||||
("can_change_event_settings", "comment/", 405, HTTP_GET),
|
||||
# Lists are currently not access-controlled
|
||||
# ("can_change_items", "items/", 200),
|
||||
("can_change_items", "items/add", 200, HTTP_GET),
|
||||
("can_change_items", "items/1/up", 404, HTTP_POST),
|
||||
("can_change_items", "items/1/down", 404, HTTP_POST),
|
||||
("can_change_items", "items/reorder/2/", 400, HTTP_POST),
|
||||
("can_change_items", "items/1/delete", 404, HTTP_GET),
|
||||
# ("can_change_items", "categories/", 200),
|
||||
("event.settings.general:write", "live/", 200, HTTP_GET),
|
||||
("event.settings.general:write", "delete/", 200, HTTP_GET),
|
||||
("event.settings.general:write", "dangerzone/", 200, HTTP_GET),
|
||||
("event.settings.general:write", "settings/", 200, HTTP_GET),
|
||||
# ("event.settings.payment:write", "settings/payment", 200, HTTP_GET), GET allowed also with other permissions
|
||||
("event.settings.payment:write", "settings/payment", 200, HTTP_POST),
|
||||
("event.settings.payment:write", "settings/payment/banktransfer", 200, HTTP_GET),
|
||||
("event.settings.general:write", "settings/tickets", 200, HTTP_GET),
|
||||
("event.settings.general:write", "settings/email", 200, HTTP_GET),
|
||||
("event.settings.general:write", "settings/email/setup", 200, HTTP_GET),
|
||||
("event.settings.general:write", "settings/cancel", 200, HTTP_GET),
|
||||
("event.settings.general:write", "settings/widget", 200, HTTP_GET),
|
||||
("event.settings.invoicing:write", "settings/invoice", 200, HTTP_GET),
|
||||
("event.settings.invoicing:write", "settings/invoice/preview", 200, HTTP_GET),
|
||||
("event.settings.tax:write", "settings/tax/", 200, HTTP_GET),
|
||||
("event.settings.tax:write", "settings/tax/1/", 404, HTTP_GET),
|
||||
("event.settings.tax:write", "settings/tax/add", 200, HTTP_GET),
|
||||
("event.settings.tax:write", "settings/tax/1/delete", 404, HTTP_GET),
|
||||
("event.settings.tax:write", "settings/tax/1/default", 404, HTTP_POST),
|
||||
("event.settings.general:write", "comment/", 405, HTTP_GET),
|
||||
(None, "items/", 200, HTTP_GET),
|
||||
("event.items:write", "items/add", 200, HTTP_GET),
|
||||
("event.items:write", "items/1/up", 404, HTTP_POST),
|
||||
("event.items:write", "items/1/down", 404, HTTP_POST),
|
||||
("event.items:write", "items/reorder/2/", 400, HTTP_POST),
|
||||
("event.items:write", "items/1/delete", 404, HTTP_GET),
|
||||
(None, "categories/", 200, HTTP_GET),
|
||||
# We don't have to create categories and similar objects
|
||||
# for testing this, it is enough to test that a 404 error
|
||||
# is returned instead of a 403 one.
|
||||
("can_change_items", "categories/2/", 404, HTTP_GET),
|
||||
("can_change_items", "categories/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "categories/2/up", 404, HTTP_POST),
|
||||
("can_change_items", "categories/2/down", 404, HTTP_POST),
|
||||
("can_change_items", "categories/reorder", 400, HTTP_POST),
|
||||
("can_change_items", "categories/add", 200, HTTP_GET),
|
||||
# ("can_change_items", "questions/", 200, HTTP_GET),
|
||||
("can_change_items", "questions/2/", 404, HTTP_GET),
|
||||
("can_change_items", "questions/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "questions/reorder", 400, HTTP_POST),
|
||||
("can_change_items", "questions/add", 200, HTTP_GET),
|
||||
# ("can_change_items", "quotas/", 200, HTTP_GET),
|
||||
("can_change_items", "quotas/2/change", 404, HTTP_GET),
|
||||
("can_change_items", "quotas/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "quotas/add", 200, HTTP_GET),
|
||||
# ("can_change_items", "discounts/", 200),
|
||||
# We don't have to create categories and similar objects
|
||||
# for testing this, it is enough to test that a 404 error
|
||||
# is returned instead of a 403 one.
|
||||
("can_change_items", "discounts/2/", 404, HTTP_GET),
|
||||
("can_change_items", "discounts/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "discounts/2/up", 404, HTTP_POST),
|
||||
("can_change_items", "discounts/2/down", 404, HTTP_POST),
|
||||
("can_change_items", "discounts/reorder", 400, HTTP_POST),
|
||||
("can_change_items", "discounts/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/2/", 404, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/2/delete", 404, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/add", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/overview/", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/export/", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/export/do", 302, HTTP_POST),
|
||||
("can_view_orders", "orders/", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/FOO/", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/extend", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/reactivate", 302, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/contact", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/transition", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/checkvatid", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/resend", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/invoice", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/change", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/approve", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/deny", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/delete", 302, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/comment", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/locale", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/sendmail", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/1/sendmail", 404, HTTP_GET),
|
||||
("can_change_orders", "orders/import/", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/import/0ab7b081-92d3-4480-82de-2f8b056fd32f/", 404, HTTP_GET),
|
||||
("can_view_orders", "orders/FOO/answer/5/", 404, HTTP_GET),
|
||||
("can_change_orders", "cancel/", 200, HTTP_GET),
|
||||
("can_change_vouchers", "vouchers/add", 200, HTTP_GET),
|
||||
("can_change_vouchers", "vouchers/bulk_add", 200, HTTP_GET),
|
||||
("can_view_vouchers", "vouchers/", 200, HTTP_GET),
|
||||
("can_view_vouchers", "vouchers/tags/", 200, HTTP_GET),
|
||||
("can_view_vouchers", "vouchers/1234/", 404, HTTP_GET),
|
||||
("can_change_vouchers", "vouchers/1234/", 404, HTTP_POST),
|
||||
("can_change_vouchers", "vouchers/1234/delete", 404, HTTP_GET),
|
||||
("can_view_orders", "waitinglist/", 200, HTTP_GET),
|
||||
("can_change_orders", "waitinglist/auto_assign", 405, HTTP_GET),
|
||||
("can_change_orders", "waitinglist/action", 405, HTTP_GET),
|
||||
("can_view_orders", "checkins/", 200, HTTP_GET),
|
||||
("can_view_orders", "checkinlists/", 200, HTTP_GET),
|
||||
("can_view_orders", "checkinlists/1/", 404, HTTP_GET),
|
||||
("can_change_orders", "checkinlists/1/bulk_action", 404, HTTP_POST),
|
||||
("can_checkin_orders", "checkinlists/1/bulk_action", 404, HTTP_POST),
|
||||
("can_change_event_settings", "checkinlists/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "checkinlists/1/change", 404, HTTP_GET),
|
||||
("can_change_event_settings", "checkinlists/1/delete", 404, HTTP_GET),
|
||||
("event.items:write", "categories/2/", 404, HTTP_GET),
|
||||
("event.items:write", "categories/2/delete", 404, HTTP_GET),
|
||||
("event.items:write", "categories/2/up", 404, HTTP_POST),
|
||||
("event.items:write", "categories/2/down", 404, HTTP_POST),
|
||||
("event.items:write", "categories/reorder", 400, HTTP_POST),
|
||||
("event.items:write", "categories/add", 200, HTTP_GET),
|
||||
(None, "questions/", 200, HTTP_GET),
|
||||
(None, "questions/2/", 404, HTTP_GET),
|
||||
("event.items:write", "questions/2/delete", 404, HTTP_GET),
|
||||
("event.items:write", "questions/reorder", 400, HTTP_POST),
|
||||
("event.items:write", "questions/add", 200, HTTP_GET),
|
||||
(None, "quotas/", 200, HTTP_GET),
|
||||
("event.items:write", "quotas/2/change", 404, HTTP_GET),
|
||||
("event.items:write", "quotas/2/delete", 404, HTTP_GET),
|
||||
("event.items:write", "quotas/add", 200, HTTP_GET),
|
||||
(None, "discounts/", 200, HTTP_GET),
|
||||
("event.items:write", "discounts/2/", 404, HTTP_GET),
|
||||
("event.items:write", "discounts/2/delete", 404, HTTP_GET),
|
||||
("event.items:write", "discounts/2/up", 404, HTTP_POST),
|
||||
("event.items:write", "discounts/2/down", 404, HTTP_POST),
|
||||
("event.items:write", "discounts/reorder", 400, HTTP_POST),
|
||||
("event.items:write", "discounts/add", 200, HTTP_GET),
|
||||
(None, "subevents/", 200, HTTP_GET),
|
||||
("event.subevents:write", "subevents/2/", 404, HTTP_GET),
|
||||
("event.subevents:write", "subevents/2/", 404, HTTP_POST),
|
||||
("event.subevents:write", "subevents/2/delete", 404, HTTP_GET),
|
||||
("event.subevents:write", "subevents/add", 200, HTTP_GET),
|
||||
("event.subevents:write", "subevents/bulk_add", 200, HTTP_GET),
|
||||
("event.subevents:write", "subevents/bulk_action", 302, HTTP_POST),
|
||||
("event.subevents:write", "subevents/bulk_edit", 404, HTTP_POST),
|
||||
("event.orders:read", "orders/overview/", 200, HTTP_GET),
|
||||
("event.orders:read", "orders/", 200, HTTP_GET),
|
||||
("event.orders:read", "orders/FOO/", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/extend", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/reactivate", 302, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/contact", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/transition", 405, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/checkvatid", 405, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/resend", 405, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/invoice", 405, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/change", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/approve", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/deny", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/delete", 302, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/comment", 405, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/locale", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/sendmail", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/FOO/1/sendmail", 404, HTTP_GET),
|
||||
("event.orders:write", "orders/import/", 200, HTTP_GET),
|
||||
("event.orders:write", "orders/import/0ab7b081-92d3-4480-82de-2f8b056fd32f/", 404, HTTP_GET),
|
||||
("event.orders:read", "orders/FOO/answer/5/", 404, HTTP_GET),
|
||||
("event:cancel", "cancel/", 200, HTTP_GET),
|
||||
("event.vouchers:write", "vouchers/add", 200, HTTP_GET),
|
||||
("event.vouchers:write", "vouchers/bulk_add", 200, HTTP_GET),
|
||||
("event.vouchers:read", "vouchers/", 200, HTTP_GET),
|
||||
("event.vouchers:read", "vouchers/tags/", 200, HTTP_GET),
|
||||
("event.vouchers:read", "vouchers/1234/", 404, HTTP_GET),
|
||||
("event.vouchers:write", "vouchers/1234/", 404, HTTP_POST),
|
||||
("event.vouchers:write", "vouchers/1234/delete", 404, HTTP_GET),
|
||||
("event.orders:read", "waitinglist/", 200, HTTP_GET),
|
||||
("event.orders:write", "waitinglist/auto_assign", 405, HTTP_GET),
|
||||
("event.orders:write", "waitinglist/action", 405, HTTP_GET),
|
||||
("event.orders:read", "checkins/", 200, HTTP_GET),
|
||||
("event.orders:read", "checkinlists/", 200, HTTP_GET),
|
||||
("event.orders:read", "checkinlists/1/", 404, HTTP_GET),
|
||||
("event.orders:write", "checkinlists/1/bulk_action", 404, HTTP_POST),
|
||||
("event.orders:checkin", "checkinlists/1/bulk_action", 404, HTTP_POST),
|
||||
("event.settings.general:write", "checkinlists/add", 200, HTTP_GET),
|
||||
("event.settings.general:write", "checkinlists/1/change", 404, HTTP_GET),
|
||||
("event.settings.general:write", "checkinlists/1/delete", 404, HTTP_GET),
|
||||
|
||||
# bank transfer
|
||||
("can_change_orders", "banktransfer/import/", 200, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/job/1/", 404, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/action/", 200, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/refunds/", 200, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/export/1/", 404, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/sepa-export/1/", 404, HTTP_GET),
|
||||
("event.orders:write", "banktransfer/import/", 200, HTTP_GET),
|
||||
("event.orders:write", "banktransfer/job/1/", 404, HTTP_GET),
|
||||
("event.orders:write", "banktransfer/action/", 200, HTTP_GET),
|
||||
("event.orders:write", "banktransfer/refunds/", 200, HTTP_GET),
|
||||
("event.orders:write", "banktransfer/export/1/", 404, HTTP_GET),
|
||||
("event.orders:write", "banktransfer/sepa-export/1/", 404, HTTP_GET),
|
||||
]
|
||||
|
||||
|
||||
@@ -425,7 +424,10 @@ def test_wrong_event_permission(perf_patch, client, env, perm, url, code, http_m
|
||||
t = Team(
|
||||
pk=2, organizer=env[2], all_events=True
|
||||
)
|
||||
setattr(t, perm, False)
|
||||
if not perm:
|
||||
pytest.skip()
|
||||
t.all_event_permissions = False
|
||||
t.limit_event_permissions.pop(perm, None)
|
||||
t.save()
|
||||
t.members.add(env[1])
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
@@ -443,7 +445,7 @@ def test_limited_event_permission_for_other_event(perf_patch, client, env, perm,
|
||||
organizer=env[2], name='Dummy', slug='dummy2',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
t = Team.objects.create(pk=2, organizer=env[2], can_change_event_settings=True)
|
||||
t = Team.objects.create(pk=2, organizer=env[2], all_event_permissions=True)
|
||||
t.members.add(env[1])
|
||||
t.limit_events.add(event2)
|
||||
|
||||
@@ -460,14 +462,16 @@ def test_current_permission(client, env):
|
||||
t = Team(
|
||||
pk=2, organizer=env[2], all_events=True
|
||||
)
|
||||
setattr(t, 'can_change_event_settings', True)
|
||||
setattr(t, 'event.settings.general:write', True)
|
||||
t.all_event_permissions = False
|
||||
t.limit_event_permissions['event.settings.general:write'] = True
|
||||
t.save()
|
||||
t.members.add(env[1])
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/settings/')
|
||||
assert response.status_code == 200
|
||||
setattr(t, 'can_change_event_settings', False)
|
||||
t.limit_event_permissions.pop('event.settings.general:write', None)
|
||||
t.save()
|
||||
response = client.get('/control/event/dummy/dummy/settings/')
|
||||
assert response.status_code == 403
|
||||
@@ -477,7 +481,8 @@ def test_current_permission(client, env):
|
||||
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
|
||||
def test_correct_event_permission_all_events(perf_patch, client, env, perm, url, code, http_method):
|
||||
t = Team(pk=2, organizer=env[2], all_events=True)
|
||||
setattr(t, perm, True)
|
||||
t.all_event_permissions = False
|
||||
t.limit_event_permissions[perm] = True
|
||||
t.save()
|
||||
t.members.add(env[1])
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
@@ -495,7 +500,8 @@ def test_correct_event_permission_all_events(perf_patch, client, env, perm, url,
|
||||
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
|
||||
def test_correct_event_permission_limited(perf_patch, client, env, perm, url, code, http_method):
|
||||
t = Team(pk=2, organizer=env[2])
|
||||
setattr(t, perm, True)
|
||||
t.all_event_permissions = False
|
||||
t.limit_event_permissions[perm] = True
|
||||
t.save()
|
||||
t.members.add(env[1])
|
||||
t.limit_events.add(env[0])
|
||||
@@ -521,77 +527,80 @@ def test_wrong_organizer(perf_patch, client, env, url):
|
||||
|
||||
|
||||
organizer_permission_urls = [
|
||||
("can_change_teams", "organizer/dummy/teams", 200),
|
||||
("can_change_teams", "organizer/dummy/team/add", 200),
|
||||
("can_change_teams", "organizer/dummy/team/1/", 200),
|
||||
("can_change_teams", "organizer/dummy/team/1/edit", 200),
|
||||
("can_change_teams", "organizer/dummy/team/1/delete", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/edit", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/settings/plugins", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/settings/plugins/pretix.plugins.sendmail/events", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/settings/email", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/settings/email/setup", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/outgoingmails", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/outgoingmail/1/", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/outgoingmail/bulk_action", 405),
|
||||
("can_change_organizer_settings", "organizer/dummy/devices", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/devices/select2", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/device/add", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/device/1/edit", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/device/1/connect", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/device/1/revoke", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/gates", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/gates/select2", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/gate/add", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/gate/1/edit", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/gate/1/delete", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/properties", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/property/add", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/property/1/edit", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/property/1/delete", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/channels", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/channel/add", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/channel/web/edit", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/channel/web/delete", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/membershiptypes", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/membershiptype/add", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/membershiptype/1/edit", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/membershiptype/1/delete", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/ssoproviders", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/ssoprovider/add", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/ssoprovider/1/edit", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/ssoprovider/1/delete", 404),
|
||||
("can_manage_customers", "organizer/dummy/customers", 200),
|
||||
("can_manage_customers", "organizer/dummy/customer/ABC/edit", 404),
|
||||
("can_manage_customers", "organizer/dummy/customer/ABC/anonymize", 404),
|
||||
("can_manage_customers", "organizer/dummy/customer/ABC/membership/add", 404),
|
||||
("can_manage_customers", "organizer/dummy/customer/ABC/membership/1/edit", 404),
|
||||
("can_manage_customers", "organizer/dummy/customer/ABC/", 404),
|
||||
("can_manage_reusable_media", "organizer/dummy/reusable_media", 200),
|
||||
("can_manage_reusable_media", "organizer/dummy/reusable_media/1/edit", 404),
|
||||
("can_manage_reusable_media", "organizer/dummy/reusable_media/1/", 404),
|
||||
("can_manage_gift_cards", "organizer/dummy/giftcards", 200),
|
||||
("can_manage_gift_cards", "organizer/dummy/giftcard/add", 200),
|
||||
("can_manage_gift_cards", "organizer/dummy/giftcard/1/", 404),
|
||||
("can_manage_gift_cards", "organizer/dummy/giftcard/1/edit", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/giftcards/acceptance", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/giftcards/acceptance/invite", 200),
|
||||
("organizer.teams:write", "organizer/dummy/teams", 200),
|
||||
("organizer.teams:write", "organizer/dummy/team/add", 200),
|
||||
("organizer.teams:write", "organizer/dummy/team/1/", 200),
|
||||
("organizer.teams:write", "organizer/dummy/team/1/edit", 200),
|
||||
("organizer.teams:write", "organizer/dummy/team/1/delete", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/edit", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/settings/plugins", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/settings/plugins/pretix.plugins.sendmail/events", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/settings/email", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/settings/email/setup", 200),
|
||||
("organizer.outgoingmails:read", "organizer/dummy/outgoingmails", 200),
|
||||
("organizer.outgoingmails:read", "organizer/dummy/outgoingmail/1/", 404),
|
||||
("organizer.outgoingmails:read", "organizer/dummy/outgoingmail/bulk_action", 405),
|
||||
("organizer.devices:read", "organizer/dummy/devices", 200),
|
||||
("organizer.devices:read", "organizer/dummy/devices/select2", 200),
|
||||
("organizer.devices:write", "organizer/dummy/device/add", 200),
|
||||
("organizer.devices:write", "organizer/dummy/device/1/edit", 404),
|
||||
("organizer.devices:write", "organizer/dummy/device/1/connect", 404),
|
||||
("organizer.devices:write", "organizer/dummy/device/1/revoke", 404),
|
||||
("organizer.devices:read", "organizer/dummy/gates", 200),
|
||||
("organizer.devices:read", "organizer/dummy/gates/select2", 200),
|
||||
("organizer.devices:write", "organizer/dummy/gate/add", 200),
|
||||
("organizer.devices:write", "organizer/dummy/gate/1/edit", 404),
|
||||
("organizer.devices:write", "organizer/dummy/gate/1/delete", 404),
|
||||
("organizer.settings.general:write", "organizer/dummy/properties", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/property/add", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/property/1/edit", 404),
|
||||
("organizer.settings.general:write", "organizer/dummy/property/1/delete", 404),
|
||||
("organizer.settings.general:write", "organizer/dummy/channels", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/channel/add", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/channel/web/edit", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/channel/web/delete", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/membershiptypes", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/membershiptype/add", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/membershiptype/1/edit", 404),
|
||||
("organizer.settings.general:write", "organizer/dummy/membershiptype/1/delete", 404),
|
||||
("organizer.settings.general:write", "organizer/dummy/ssoproviders", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/ssoprovider/add", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/ssoprovider/1/edit", 404),
|
||||
("organizer.settings.general:write", "organizer/dummy/ssoprovider/1/delete", 404),
|
||||
("organizer.customers:read", "organizer/dummy/customers", 200),
|
||||
("organizer.customers:write", "organizer/dummy/customer/ABC/edit", 404),
|
||||
("organizer.customers:write", "organizer/dummy/customer/ABC/anonymize", 404),
|
||||
("organizer.customers:write", "organizer/dummy/customer/ABC/membership/add", 404),
|
||||
("organizer.customers:write", "organizer/dummy/customer/ABC/membership/1/edit", 404),
|
||||
("organizer.customers:read", "organizer/dummy/customer/ABC/", 404),
|
||||
("organizer.reusablemedia:read", "organizer/dummy/reusable_media", 200),
|
||||
("organizer.reusablemedia:write", "organizer/dummy/reusable_media/1/edit", 404),
|
||||
("organizer.reusablemedia:read", "organizer/dummy/reusable_media/1/", 404),
|
||||
("organizer.giftcards:read", "organizer/dummy/giftcards", 200),
|
||||
("organizer.giftcards:write", "organizer/dummy/giftcard/add", 200),
|
||||
("organizer.giftcards:read", "organizer/dummy/giftcard/1/", 404),
|
||||
("organizer.giftcards:write", "organizer/dummy/giftcard/1/edit", 404),
|
||||
("organizer.settings.general:write", "organizer/dummy/giftcards/acceptance", 200),
|
||||
("organizer.settings.general:write", "organizer/dummy/giftcards/acceptance/invite", 200),
|
||||
|
||||
# bank transfer
|
||||
("can_change_orders", "organizer/dummy/banktransfer/import/", 200),
|
||||
("can_change_orders", "organizer/dummy/banktransfer/job/1/", 404),
|
||||
("can_change_orders", "organizer/dummy/banktransfer/action/", 200),
|
||||
("can_change_orders", "organizer/dummy/banktransfer/refunds/", 200),
|
||||
("can_change_orders", "organizer/dummy/banktransfer/export/1/", 404),
|
||||
("can_change_orders", "organizer/dummy/banktransfer/sepa-export/1/", 404),
|
||||
("event.orders:write", "organizer/dummy/banktransfer/import/", 200),
|
||||
("event.orders:write", "organizer/dummy/banktransfer/job/1/", 404),
|
||||
("event.orders:write", "organizer/dummy/banktransfer/action/", 200),
|
||||
("event.orders:write", "organizer/dummy/banktransfer/refunds/", 200),
|
||||
("event.orders:write", "organizer/dummy/banktransfer/export/1/", 404),
|
||||
("event.orders:write", "organizer/dummy/banktransfer/sepa-export/1/", 404),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("perm,url,code", organizer_permission_urls)
|
||||
def test_wrong_organizer_permission(perf_patch, client, env, perm, url, code):
|
||||
t = Team(pk=2, organizer=env[2])
|
||||
setattr(t, perm, False)
|
||||
t = Team(pk=2, organizer=env[2], all_events=True)
|
||||
t.all_organizer_permissions = False
|
||||
t.limit_organizer_permissions.pop(perm, None)
|
||||
t.all_event_permissions = False
|
||||
t.limit_event_permissions.pop(perm, None)
|
||||
t.save()
|
||||
t.members.add(env[1])
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
@@ -602,8 +611,14 @@ def test_wrong_organizer_permission(perf_patch, client, env, perm, url, code):
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("perm,url,code", organizer_permission_urls)
|
||||
def test_correct_organizer_permission(perf_patch, client, env, perm, url, code):
|
||||
t = Team(pk=2, organizer=env[2])
|
||||
setattr(t, perm, True)
|
||||
t = Team(pk=2, organizer=env[2], all_events=True)
|
||||
if perm.startswith("event."):
|
||||
t.all_organizer_permissions = False
|
||||
t.all_event_permissions = False
|
||||
t.limit_event_permissions[perm] = True
|
||||
else:
|
||||
t.all_organizer_permissions = False
|
||||
t.limit_organizer_permissions[perm] = True
|
||||
t.save()
|
||||
t.members.add(env[1])
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -51,7 +51,7 @@ def gift_card(organizer):
|
||||
@pytest.fixture
|
||||
def admin_user(organizer):
|
||||
u = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
admin_team = Team.objects.create(organizer=organizer, can_manage_reusable_media=True, name='Admin team')
|
||||
admin_team = Team.objects.create(organizer=organizer, all_organizer_permissions=True, name='Admin team')
|
||||
admin_team.members.add(u)
|
||||
return u
|
||||
|
||||
@@ -122,7 +122,7 @@ def test_typeahead(organizer, admin_user, client, gift_card):
|
||||
|
||||
# Privileged user can search
|
||||
team.all_events = True
|
||||
team.can_view_orders = True
|
||||
team.limit_event_permissions["event.orders:read"] = True
|
||||
team.save()
|
||||
|
||||
r = client.get('/control/organizer/dummy/ticket_select2?query=' + op.secret[0:3])
|
||||
@@ -140,7 +140,8 @@ def test_typeahead(organizer, admin_user, client, gift_card):
|
||||
|
||||
# Unprivileged user can only do exact match
|
||||
team.all_events = True
|
||||
team.can_view_orders = False
|
||||
team.all_event_permissions = False
|
||||
team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
team.save()
|
||||
|
||||
r = client.get('/control/organizer/dummy/ticket_select2?query=' + op.secret[0:3])
|
||||
@@ -154,7 +155,7 @@ def test_typeahead(organizer, admin_user, client, gift_card):
|
||||
assert d == {"results": [{'event': 'Dummy', 'id': op.pk, 'text': 'FOO-1 (Early-bird ticket)'}], "pagination": {"more": False}}
|
||||
|
||||
team.all_events = False
|
||||
team.can_view_orders = True
|
||||
team.limit_event_permissions["event.orders:read"] = True
|
||||
team.save()
|
||||
|
||||
r = client.get('/control/organizer/dummy/ticket_select2?query=' + op.secret[0:3])
|
||||
|
||||
@@ -86,7 +86,7 @@ class OrderSearchTest(SoupTest):
|
||||
attendee_name_parts={'full_name': "Mark", "_scheme": "full"}
|
||||
)
|
||||
|
||||
self.team = Team.objects.create(organizer=self.orga1, can_view_orders=True)
|
||||
self.team = Team.objects.create(organizer=self.orga1, limit_event_permissions={"event.orders:read": True})
|
||||
self.team.members.add(self.user)
|
||||
self.team.limit_events.add(self.event1)
|
||||
|
||||
@@ -98,7 +98,8 @@ class OrderSearchTest(SoupTest):
|
||||
assert 'DEFFO2' not in resp
|
||||
|
||||
def test_team_limit_event_wrong_permission(self):
|
||||
self.team.can_view_orders = False
|
||||
self.team.all_event_permissions = False
|
||||
self.team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
self.team.save()
|
||||
resp = self.client.get('/control/search/orders/').content.decode()
|
||||
assert 'ABCFO1' not in resp
|
||||
@@ -113,7 +114,8 @@ class OrderSearchTest(SoupTest):
|
||||
|
||||
def test_team_all_events_wrong_permission(self):
|
||||
self.team.all_events = True
|
||||
self.team.can_view_orders = False
|
||||
self.team.all_event_permissions = False
|
||||
self.team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
self.team.save()
|
||||
resp = self.client.get('/control/search/orders/').content.decode()
|
||||
assert 'ABCFO1' not in resp
|
||||
@@ -270,8 +272,8 @@ class PaymentSearchTest(SoupTest):
|
||||
info="{test payment order 2}"
|
||||
)
|
||||
|
||||
self.team = Team.objects.create(organizer=self.orga1, can_view_orders=True)
|
||||
self.team2 = Team.objects.create(organizer=self.orga2, can_view_orders=True)
|
||||
self.team = Team.objects.create(organizer=self.orga1, limit_event_permissions={"event.orders:read": True})
|
||||
self.team2 = Team.objects.create(organizer=self.orga2, limit_event_permissions={"event.orders:read": True})
|
||||
self.team.members.add(self.user)
|
||||
self.team.limit_events.add(self.event1)
|
||||
|
||||
@@ -283,7 +285,8 @@ class PaymentSearchTest(SoupTest):
|
||||
assert 'DEFFO2' not in resp
|
||||
|
||||
def test_team_limit_event_wrong_permission(self):
|
||||
self.team.can_view_orders = False
|
||||
self.team.all_event_permissions = False
|
||||
self.team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
self.team.save()
|
||||
resp = self.client.get('/control/search/payments/').content.decode()
|
||||
assert 'ABCFO1' not in resp
|
||||
@@ -298,7 +301,8 @@ class PaymentSearchTest(SoupTest):
|
||||
|
||||
def test_team_all_events_wrong_permission(self):
|
||||
self.team.all_events = True
|
||||
self.team.can_view_orders = False
|
||||
self.team.all_event_permissions = False
|
||||
self.team.limit_event_permissions = {"event.vouchers:read": True}
|
||||
self.team.save()
|
||||
resp = self.client.get('/control/search/payments/').content.decode()
|
||||
assert 'ABCFO1' not in resp
|
||||
|
||||
@@ -58,8 +58,7 @@ class EventShredderTest(SoupTest):
|
||||
plugins='pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy'
|
||||
)
|
||||
|
||||
t = Team.objects.create(organizer=self.orga1, can_create_events=True, can_change_event_settings=True,
|
||||
can_change_items=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_organizer_permissions=True, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.order = Order.objects.create(
|
||||
|
||||
@@ -45,8 +45,7 @@ class SubEventsTest(SoupTest):
|
||||
has_subevents=True
|
||||
)
|
||||
|
||||
t = Team.objects.create(organizer=self.orga1, can_create_events=True, can_change_event_settings=True,
|
||||
can_change_items=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_organizer_permissions=True, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.ticket = self.event1.items.create(name='Early-bird ticket',
|
||||
|
||||
@@ -41,7 +41,7 @@ class TaxRateFormTest(SoupTest):
|
||||
organizer=self.orga1, name='30C3', slug='30c3',
|
||||
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
t = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_change_items=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_organizer_permissions=True, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -56,7 +56,7 @@ def event(organizer):
|
||||
|
||||
@pytest.fixture
|
||||
def admin_team(organizer):
|
||||
return Team.objects.create(organizer=organizer, can_change_teams=True, name='Admin team')
|
||||
return Team.objects.create(organizer=organizer, all_organizer_permissions=True, all_event_permissions=True, name='Admin team')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -216,7 +216,7 @@ def test_team_remove_last_admin(event, admin_user, admin_team, client):
|
||||
with scopes_disabled():
|
||||
assert admin_user in admin_team.members.all()
|
||||
|
||||
t2.can_change_teams = True
|
||||
t2.limit_organizer_permissions = {"organizer.teams:write": True}
|
||||
t2.save()
|
||||
resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), {
|
||||
'remove-member': admin_user.pk
|
||||
@@ -229,17 +229,35 @@ def test_team_remove_last_admin(event, admin_user, admin_team, client):
|
||||
@pytest.mark.django_db
|
||||
def test_create_team(event, admin_user, admin_team, client):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
client.post('/control/organizer/dummy/team/add', {
|
||||
r = client.post('/control/organizer/dummy/team/add', {
|
||||
'name': 'Foo',
|
||||
'can_create_events': 'on',
|
||||
'organizer_organizer.events': "create",
|
||||
'organizer_organizer.settings.general': "EMPTY",
|
||||
'organizer_organizer.teams': "EMPTY",
|
||||
'organizer_organizer.giftcards': "EMPTY",
|
||||
'organizer_organizer.customers': "EMPTY",
|
||||
'organizer_organizer.reusablemedia': "EMPTY",
|
||||
'organizer_organizer.devices': "EMPTY",
|
||||
'organizer_organizer.seatingplans': "EMPTY",
|
||||
'organizer_organizer.outgoingmails': "EMPTY",
|
||||
'event_event.settings.general': "write",
|
||||
'event_event.settings.payment': "EMPTY",
|
||||
'event_event.settings.tax': "EMPTY",
|
||||
'event_event.settings.invoicing': "EMPTY",
|
||||
'event_event.subevents': "EMPTY",
|
||||
'event_event.items': "EMPTY",
|
||||
'event_event.orders': "EMPTY",
|
||||
'event_event.vouchers': "EMPTY",
|
||||
'event_event': "EMPTY",
|
||||
'limit_events': str(event.pk),
|
||||
'can_change_event_settings': 'on'
|
||||
}, follow=True)
|
||||
assert 'alert-success' in r.content.decode()
|
||||
with scopes_disabled():
|
||||
t = Team.objects.last()
|
||||
assert t.can_change_event_settings
|
||||
assert t.can_create_events
|
||||
assert not t.can_change_organizer_settings
|
||||
assert not t.all_event_permissions
|
||||
assert t.limit_event_permissions == {"event.settings.general:write": True}
|
||||
assert not t.all_organizer_permissions
|
||||
assert t.limit_organizer_permissions == {"organizer.events:create": True}
|
||||
assert list(t.limit_events.all()) == [event]
|
||||
assert list(t.members.all()) == [admin_user]
|
||||
|
||||
@@ -247,15 +265,36 @@ def test_create_team(event, admin_user, admin_team, client):
|
||||
@pytest.mark.django_db
|
||||
def test_update_team(event, admin_user, admin_team, client):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
client.post('/control/organizer/dummy/team/{}/edit'.format(admin_team.pk), {
|
||||
r = client.post('/control/organizer/dummy/team/{}/edit'.format(admin_team.pk), {
|
||||
'name': 'Admin',
|
||||
'can_change_teams': 'on',
|
||||
'limit_events': str(event.pk),
|
||||
'can_change_event_settings': 'on'
|
||||
'all_event_permissions': 'on',
|
||||
'all_organizer_permissions': '',
|
||||
'organizer_organizer.events': "EMPTY",
|
||||
'organizer_organizer.settings.general': "EMPTY",
|
||||
'organizer_organizer.teams': "write",
|
||||
'organizer_organizer.giftcards': "EMPTY",
|
||||
'organizer_organizer.customers': "EMPTY",
|
||||
'organizer_organizer.reusablemedia': "EMPTY",
|
||||
'organizer_organizer.devices': "EMPTY",
|
||||
'organizer_organizer.seatingplans': "EMPTY",
|
||||
'organizer_organizer.outgoingmails': "EMPTY",
|
||||
'event_event.settings.general': "write",
|
||||
'event_event.settings.payment': "EMPTY",
|
||||
'event_event.settings.tax': "EMPTY",
|
||||
'event_event.settings.invoicing': "EMPTY",
|
||||
'event_event.subevents': "EMPTY",
|
||||
'event_event.items': "EMPTY",
|
||||
'event_event.orders': "EMPTY",
|
||||
'event_event.vouchers': "EMPTY",
|
||||
'event_event': "EMPTY",
|
||||
}, follow=True)
|
||||
assert 'alert-success' in r.content.decode()
|
||||
admin_team.refresh_from_db()
|
||||
assert admin_team.can_change_event_settings
|
||||
assert not admin_team.can_change_organizer_settings
|
||||
assert admin_team.all_event_permissions
|
||||
assert admin_team.limit_event_permissions == {}
|
||||
assert not admin_team.all_organizer_permissions
|
||||
assert admin_team.limit_organizer_permissions == {"organizer.teams:write": True}
|
||||
with scopes_disabled():
|
||||
assert list(admin_team.limit_events.all()) == [event]
|
||||
|
||||
@@ -265,7 +304,23 @@ def test_update_last_team_to_be_no_admin(event, admin_user, admin_team, client):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
resp = client.post('/control/organizer/dummy/team/{}/edit'.format(admin_team.pk), {
|
||||
'name': 'Admin',
|
||||
'can_change_event_settings': 'on'
|
||||
'organizer_organizer.events': "write",
|
||||
'organizer_organizer.settings.general': "EMPTY",
|
||||
'organizer_organizer.teams': "EMPTY",
|
||||
'organizer_organizer.giftcards': "EMPTY",
|
||||
'organizer_organizer.customers': "EMPTY",
|
||||
'organizer_organizer.reusablemedia': "EMPTY",
|
||||
'organizer_organizer.devices': "EMPTY",
|
||||
'organizer_organizer.seatingplans': "EMPTY",
|
||||
'event_event.settings.general': "write",
|
||||
'event_event.settings.payment': "EMPTY",
|
||||
'event_event.settings.tax': "EMPTY",
|
||||
'event_event.settings.invoicing': "EMPTY",
|
||||
'event_event.subevents': "EMPTY",
|
||||
'event_event.items': "EMPTY",
|
||||
'event_event.orders': "EMPTY",
|
||||
'event_event.vouchers': "EMPTY",
|
||||
'event_event': "EMPTY",
|
||||
}, follow=True)
|
||||
assert 'alert-danger' in resp.content.decode()
|
||||
|
||||
|
||||
@@ -482,7 +482,7 @@ class UserSettingsNotificationsTest(SoupTest):
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
t = o.teams.create(can_change_orders=True, all_events=True)
|
||||
t = o.teams.create(limit_event_permissions={"event.orders:write": True}, all_events=True)
|
||||
t.members.add(self.user)
|
||||
|
||||
def test_toggle_all(self):
|
||||
|
||||
@@ -110,9 +110,8 @@ def logged_in_client(client, event):
|
||||
user = User.objects.create_superuser('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(
|
||||
organizer=event.organizer,
|
||||
all_events=True, can_create_events=True, can_change_teams=True,
|
||||
can_change_organizer_settings=True, can_change_event_settings=True, can_change_items=True,
|
||||
can_view_orders=True, can_change_orders=True, can_view_vouchers=True, can_change_vouchers=True
|
||||
all_event_permissions=True,
|
||||
all_organizer_permissions=True,
|
||||
)
|
||||
t.members.add(user)
|
||||
client.force_login(user)
|
||||
|
||||
@@ -58,7 +58,7 @@ class VoucherFormTest(SoupTestMixin, TransactionTestCase):
|
||||
organizer=self.orga, name='30C3', slug='30c3',
|
||||
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
t = Team.objects.create(organizer=self.orga, can_view_vouchers=True, can_change_vouchers=True)
|
||||
t = Team.objects.create(organizer=self.orga, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -66,7 +66,7 @@ def env():
|
||||
event=event, item=item2, email='valid@example.org', voucher=v
|
||||
)
|
||||
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=o, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ def admin_user(admin_team):
|
||||
|
||||
@pytest.fixture
|
||||
def admin_team(organizer):
|
||||
return Team.objects.create(organizer=organizer, can_change_organizer_settings=True, name='Admin team')
|
||||
return Team.objects.create(organizer=organizer, all_organizer_permissions=True, name='Admin team')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -68,18 +68,8 @@ def team(organizer):
|
||||
organizer=organizer,
|
||||
name="Test-Team",
|
||||
all_events=True,
|
||||
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_view_orders=True,
|
||||
can_change_orders=True,
|
||||
can_manage_customers=True,
|
||||
can_manage_reusable_media=True,
|
||||
can_change_organizer_settings=True,
|
||||
all_organizer_permissions=True,
|
||||
all_event_permissions=True,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -46,24 +46,16 @@ class AutoCheckinFormTest(SoupTest):
|
||||
)
|
||||
t = Team.objects.create(
|
||||
organizer=self.orga1,
|
||||
can_change_event_settings=True,
|
||||
can_view_orders=True,
|
||||
can_change_items=True,
|
||||
all_organizer_permissions=True,
|
||||
all_event_permissions=True,
|
||||
all_events=True,
|
||||
can_create_events=True,
|
||||
can_change_orders=True,
|
||||
can_change_vouchers=True,
|
||||
)
|
||||
t.members.add(self.user)
|
||||
t = Team.objects.create(
|
||||
organizer=self.orga2,
|
||||
can_change_event_settings=True,
|
||||
can_view_orders=True,
|
||||
can_change_items=True,
|
||||
all_organizer_permissions=True,
|
||||
all_event_permissions=True,
|
||||
all_events=True,
|
||||
can_create_events=True,
|
||||
can_change_orders=True,
|
||||
can_change_vouchers=True,
|
||||
)
|
||||
t.members.add(self.user)
|
||||
self.client.login(email="dummy@dummy.dummy", password="dummy")
|
||||
|
||||
@@ -53,9 +53,7 @@ class BadgeLayoutFormTest(SoupTest):
|
||||
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
self.item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1)
|
||||
t = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_view_orders=True,
|
||||
can_change_items=True, all_events=True, can_create_events=True,
|
||||
can_change_orders=True, can_change_vouchers=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_events=True, all_event_permissions=True, all_organizer_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -41,7 +41,7 @@ def env():
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
o1 = Order.objects.create(
|
||||
@@ -274,7 +274,8 @@ def test_assign_order_organizer_no_permission(env, client):
|
||||
state=BankTransaction.STATE_NOMATCH,
|
||||
amount=23, date='unknown')
|
||||
team = env[1].teams.first()
|
||||
team.can_change_orders = False
|
||||
team.limit_event_permissions = {}
|
||||
team.all_event_permissions = False
|
||||
team.save()
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
r = client.post('/control/organizer/{}/banktransfer/action/'.format(env[0].organizer.slug), {
|
||||
@@ -290,7 +291,12 @@ def test_assign_order_organizer_no_permission_for_event(env, client):
|
||||
state=BankTransaction.STATE_NOMATCH,
|
||||
amount=23, date='unknown')
|
||||
team = env[1].teams.first()
|
||||
team.limit_events.clear()
|
||||
event2 = Event.objects.create(
|
||||
organizer=env[0].organizer, name='Dummy2', slug='dummy2',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
with scopes_disabled():
|
||||
team.limit_events.set([event2])
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
r = json.loads(client.post('/control/organizer/{}/banktransfer/action/'.format(env[0].organizer.slug), {
|
||||
'action_{}'.format(trans.pk): 'assign:{}-{}'.format(env[0].slug.upper(), env[2].code),
|
||||
|
||||
@@ -42,7 +42,7 @@ def env():
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
o1 = Order.objects.create(
|
||||
|
||||
@@ -61,7 +61,7 @@ def env():
|
||||
event.settings.invoice_numbers_prefix = 'INV-'
|
||||
event.settings.invoice_numbers_counter_length = 3
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
o1 = Order.objects.create(
|
||||
|
||||
@@ -40,7 +40,7 @@ def env():
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.paypal'
|
||||
)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
order = Order.objects.create(
|
||||
|
||||
@@ -41,7 +41,7 @@ def env():
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.paypal'
|
||||
)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
order = Order.objects.create(
|
||||
|
||||
@@ -51,7 +51,7 @@ def env(client):
|
||||
event.settings.set('attendee_names_asked', False)
|
||||
event.settings.set('payment_paypal__enabled', True)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_change_event_settings=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
client.force_login(user)
|
||||
|
||||
@@ -41,7 +41,7 @@ def env():
|
||||
organizer=o, name='Dummy', slug='dummy', plugins='pretix.plugins.paypal',
|
||||
date_from=now(), live=True
|
||||
)
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
o1 = Order.objects.create(
|
||||
|
||||
@@ -51,7 +51,7 @@ def env(client):
|
||||
event.settings.set('attendee_names_asked', False)
|
||||
event.settings.set('payment_paypal__enabled', True)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_change_event_settings=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
client.force_login(user)
|
||||
|
||||
@@ -42,7 +42,7 @@ def env():
|
||||
organizer=o, name='Dummy', slug='dummy', plugins='pretix.plugins.paypal2',
|
||||
date_from=now(), live=True
|
||||
)
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
o1 = Order.objects.create(
|
||||
|
||||
@@ -47,7 +47,7 @@ from pretix.base.models import Checkin, Item, Order, OrderPosition, Team, User
|
||||
def logged_in_client(client, event):
|
||||
"""Returns a logged client"""
|
||||
user = User.objects.create_superuser('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
client.force_login(user)
|
||||
|
||||
@@ -74,7 +74,7 @@ def env(client):
|
||||
event.settings.set('attendee_names_asked', False)
|
||||
event.settings.set('payment_stripe__enabled', True)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_change_event_settings=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
client.force_login(user)
|
||||
|
||||
@@ -41,7 +41,7 @@ def env():
|
||||
organizer=o, name='Dummy', slug='dummy', plugins='pretix.plugins.stripe',
|
||||
date_from=now(), live=True
|
||||
)
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
o1 = Order.objects.create(
|
||||
|
||||
@@ -43,7 +43,7 @@ def env():
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True)
|
||||
t.limit_events.add(event)
|
||||
item1 = Item.objects.create(event=event, name="Ticket", default_price=23)
|
||||
tl = event.ticket_layouts.create(
|
||||
|
||||
@@ -54,9 +54,7 @@ class TicketLayoutFormTest(SoupTest):
|
||||
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
self.item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1)
|
||||
t = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_view_orders=True,
|
||||
can_change_items=True, all_events=True, can_create_events=True,
|
||||
can_change_vouchers=True, can_change_orders=True)
|
||||
t = Team.objects.create(organizer=self.orga1, all_event_permissions=True, all_organizer_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -36,7 +36,7 @@ def env():
|
||||
date_from=now(), plugins='pretix.plugins.ticketoutputpdf'
|
||||
)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=event.organizer, can_create_events=True, can_change_event_settings=True, can_change_items=True)
|
||||
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True, all_organizer_permissions=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
item1 = Item.objects.create(event=event, name="Ticket", default_price=23)
|
||||
|
||||
@@ -70,7 +70,7 @@ class EventTestMixin:
|
||||
live=True,
|
||||
)
|
||||
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=self.orga, can_change_event_settings=True)
|
||||
t = Team.objects.create(organizer=self.orga, all_event_permissions=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event)
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@ class TimemachineTestMixin:
|
||||
@scopes_disabled()
|
||||
def _login_with_permission(self, orga):
|
||||
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
self.team1 = Team.objects.create(organizer=orga, can_create_events=True, can_change_event_settings=True,
|
||||
can_change_items=True, all_events=True)
|
||||
self.team1 = Team.objects.create(organizer=orga, all_event_permissions=True, all_events=True)
|
||||
self.team1.members.add(self.user)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.channels import SalesChannelType
|
||||
from pretix.base.exporter import BaseExporter
|
||||
from pretix.base.invoicing.transmission import (
|
||||
TransmissionProvider, transmission_providers,
|
||||
)
|
||||
from pretix.base.models import Invoice
|
||||
from pretix.base.signals import (
|
||||
register_data_exporters, register_multievent_data_exporters,
|
||||
register_payment_providers, register_sales_channel_types,
|
||||
register_ticket_outputs,
|
||||
)
|
||||
@@ -48,6 +50,40 @@ def register_payment_provider(sender, **kwargs):
|
||||
return [DummyPaymentProvider, DummyFullRefundablePaymentProvider, DummyPartialRefundablePaymentProvider]
|
||||
|
||||
|
||||
class DummyOrdersExporter(BaseExporter):
|
||||
verbose_name = "Dummy orders"
|
||||
identifier = "dummy_orders"
|
||||
|
||||
|
||||
class DummyVoucherExporter(BaseExporter):
|
||||
verbose_name = "Dummy orders"
|
||||
identifier = "dummy_vouchers"
|
||||
|
||||
@classmethod
|
||||
def get_required_event_permission(cls) -> str:
|
||||
return "event.vouchers:read"
|
||||
|
||||
|
||||
@receiver(register_data_exporters, dispatch_uid="dummy_exporter_o")
|
||||
def register_data_exporters_recv_o(sender, **kwargs):
|
||||
return DummyOrdersExporter
|
||||
|
||||
|
||||
@receiver(register_data_exporters, dispatch_uid="dummy_exporter_v")
|
||||
def register_data_exporters_recv_v(sender, **kwargs):
|
||||
return DummyVoucherExporter
|
||||
|
||||
|
||||
@receiver(register_multievent_data_exporters, dispatch_uid="dummy_exporter_multi_o")
|
||||
def register_multievent_data_exporters_recv_o(sender, **kwargs):
|
||||
return DummyOrdersExporter
|
||||
|
||||
|
||||
@receiver(register_multievent_data_exporters, dispatch_uid="dummy_exporter_multi_v")
|
||||
def register_multievent_data_exporters_recv(sender, **kwargs):
|
||||
return DummyVoucherExporter
|
||||
|
||||
|
||||
class FoobazSalesChannel(SalesChannelType):
|
||||
identifier = "baz"
|
||||
verbose_name = "Foobar"
|
||||
|
||||
Reference in New Issue
Block a user