diff --git a/src/pretix/api/auth/permission.py b/src/pretix/api/auth/permission.py index e023a14956..dd69fc3d66 100644 --- a/src/pretix/api/auth/permission.py +++ b/src/pretix/api/auth/permission.py @@ -44,7 +44,24 @@ from pretix.helpers.security import ( ) +class RequireAll: + def __init__(self, *permissions): + self.permissions = permissions + + class EventPermission(BasePermission): + @staticmethod + def _check_required_permission(request, required_permission): + if isinstance(required_permission, RequireAll): + if any(p not in request.eventpermset for p in required_permission.permissions): + return False + elif isinstance(required_permission, (list, tuple)): + if not any(p in request.eventpermset for p in required_permission): + return False + else: + if required_permission and required_permission not in request.eventpermset: + return False + return True def has_permission(self, request, view): if not request.user.is_authenticated and not isinstance(request.auth, (Device, TeamAPIToken)): @@ -87,12 +104,8 @@ class EventPermission(BasePermission): else: request.eventpermset = perm_holder.get_event_permission_set(request.organizer, request.event) - if isinstance(required_permission, (list, tuple)): - if not any(p in request.eventpermset for p in required_permission): - return False - else: - if required_permission and required_permission not in request.eventpermset: - return False + if not self._check_required_permission(request, required_permission): + return False elif 'organizer' in request.resolver_match.kwargs: if not request.organizer or not perm_holder.has_organizer_permission(request.organizer, request=request): @@ -102,12 +115,8 @@ class EventPermission(BasePermission): else: request.orgapermset = perm_holder.get_organizer_permission_set(request.organizer) - if isinstance(required_permission, (list, tuple)): - if not any(p in request.eventpermset for p in required_permission): - return False - else: - if required_permission and required_permission not in request.orgapermset: - return False + if not self._check_required_permission(request, required_permission): + return False if isinstance(request.auth, OAuthAccessToken): if not request.auth.allow_scopes(['write']) and request.method not in SAFE_METHODS: diff --git a/src/pretix/api/views/event.py b/src/pretix/api/views/event.py index 86f1d3c2c5..46cf4afe63 100644 --- a/src/pretix/api/views/event.py +++ b/src/pretix/api/views/event.py @@ -42,9 +42,10 @@ from django_scopes import scopes_disabled from rest_framework import serializers, views, viewsets from rest_framework.exceptions import PermissionDenied, ValidationError, NotFound from rest_framework.generics import get_object_or_404 +from rest_framework.permissions import SAFE_METHODS from rest_framework.response import Response -from pretix.api.auth.permission import EventCRUDPermission +from pretix.api.auth.permission import EventCRUDPermission, RequireAll from pretix.api.pagination import TotalOrderingFilter from pretix.api.serializers.event import ( CloneEventSerializer, DeviceEventSettingsSerializer, EventSerializer, @@ -672,11 +673,17 @@ class EventSettingsView(views.APIView): class SeatViewSet(ConditionalListView, viewsets.ModelViewSet): serializer_class = SeatSerializer queryset = Seat.objects.none() - permission = 'can_view_orders' - write_permission = 'can_change_event_settings' filter_backends = (DjangoFilterBackend,) filterset_fields = ('zone_name', 'row_name', 'row_label', 'seat_number', 'seat_label', 'seat_guid', 'blocked',) + def _get_permission_name(self, request): + perms = [] + if 'orderposition' in request.query_params.getlist('expand'): + perms.append('can_view_orders') + if request.method not in SAFE_METHODS: + perms.append('can_change_event_settings') + return RequireAll(*perms) + def get_queryset(self): if self.request.event.has_subevents and 'subevent' in self.request.resolver_match.kwargs: try: diff --git a/src/pretix/api/views/media.py b/src/pretix/api/views/media.py index b6335033c7..44c12cfaf6 100644 --- a/src/pretix/api/views/media.py +++ b/src/pretix/api/views/media.py @@ -34,6 +34,7 @@ from rest_framework.exceptions import MethodNotAllowed from rest_framework.filters import OrderingFilter from rest_framework.response import Response +from pretix.api.auth.permission import RequireAll from pretix.api.serializers.media import ( MediaLookupInputSerializer, ReusableMediaSerializer, ) @@ -61,13 +62,17 @@ with scopes_disabled(): class ReusableMediaViewSet(viewsets.ModelViewSet): serializer_class = ReusableMediaSerializer queryset = ReusableMedium.objects.none() - permission = 'can_manage_reusable_media' - write_permission = 'can_manage_reusable_media' filter_backends = (DjangoFilterBackend, OrderingFilter) ordering = ('-updated', '-id') ordering_fields = ('created', 'updated', 'identifier', 'type', 'id') filterset_class = ReusableMediumFilter + def _get_permission_name(self, request): + if 'linked_orderposition' in request.query_params.getlist('expand'): + return RequireAll(['can_manage_reusable_media', 'can_view_orders']) + else: + return 'can_manage_reusable_media' + def get_queryset(self): s = GiftCardTransaction.objects.filter( card=OuterRef('pk')