Make tests pass

This commit is contained in:
Raphael Michel
2026-01-09 17:30:51 +01:00
parent 70973c8c6f
commit e566ab3405
30 changed files with 219 additions and 117 deletions

View File

@@ -14,7 +14,8 @@ Core
:members: periodic_task, event_live_issues, event_copy_data, email_filter, register_notification_types, notification, :members: periodic_task, event_live_issues, event_copy_data, email_filter, register_notification_types, notification,
item_copy_data, register_sales_channel_types, register_global_settings, quota_availability, global_email_filter, item_copy_data, register_sales_channel_types, register_global_settings, quota_availability, global_email_filter,
register_ticket_secret_generators, gift_card_transaction_display, register_ticket_secret_generators, gift_card_transaction_display,
register_text_placeholders, register_mail_placeholders, device_info_updated register_text_placeholders, register_mail_placeholders, device_info_updated,
register_event_permissions, register_organizer_permissions
Order events Order events
"""""""""""" """"""""""""

View File

@@ -341,7 +341,7 @@ class CloneEventViewSet(viewsets.ModelViewSet):
lookup_field = 'slug' lookup_field = 'slug'
lookup_url_kwarg = 'event' lookup_url_kwarg = 'event'
http_method_names = ['post'] http_method_names = ['post']
write_permission = 'organizer.events:create' write_permission = 'event.settings.general:write'
def get_serializer_context(self): def get_serializer_context(self):
ctx = super().get_serializer_context() ctx = super().get_serializer_context()
@@ -350,6 +350,12 @@ class CloneEventViewSet(viewsets.ModelViewSet):
return ctx return ctx
def perform_create(self, serializer): def perform_create(self, serializer):
# Weird edge case: Requires settings permission on the event (to read) but also on the organizer (two write)
perm_holder = (self.request.auth if isinstance(self.request.auth, (Device, TeamAPIToken))
else self.request.user)
if not perm_holder.has_organizer_permission(self.request.organizer, "organizer.events:create", request=self.request):
raise PermissionDenied("No permission to create events")
serializer.save(organizer=self.request.organizer) serializer.save(organizer=self.request.organizer)
serializer.instance.log_action( serializer.instance.log_action(

View File

@@ -1942,10 +1942,15 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
ordering = ('nr',) ordering = ('nr',)
ordering_fields = ('nr', 'date') ordering_fields = ('nr', 'date')
filterset_class = InvoiceFilter filterset_class = InvoiceFilter
permission = 'event.orders:read'
lookup_url_kwarg = 'number' lookup_url_kwarg = 'number'
lookup_field = 'nr' lookup_field = 'nr'
write_permission = 'event.orders:write'
def _get_permission_name(self, request):
if 'event' in request.resolver_match.kwargs:
if request.method not in SAFE_METHODS:
return "event.orders:write"
return "event.orders:read"
return None # org-level is handled by event__in check
def get_queryset(self): def get_queryset(self):
perm = "event.orders:read" if self.request.method in SAFE_METHODS else "event.orders:write" perm = "event.orders:read" if self.request.method in SAFE_METHODS else "event.orders:write"

View File

@@ -472,7 +472,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
:return: set :return: set
""" """
teams = self._get_teams_for_event(organizer, event) teams = self._get_teams_for_event(organizer, event)
sets = [t.permission_set() for t in teams] sets = [t.event_permission_set() for t in teams]
if sets: if sets:
return set.union(*sets) return set.union(*sets)
else: else:
@@ -486,7 +486,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
:return: set :return: set
""" """
teams = self._get_teams_for_organizer(organizer) teams = self._get_teams_for_organizer(organizer)
sets = [t.permission_set() for t in teams] sets = [t.organizer_permission_set() for t in teams]
if sets: if sets:
return set.union(*sets) return set.union(*sets)
else: else:

View File

@@ -189,11 +189,15 @@ class Device(LoggedModel):
kwargs['update_fields'] = {'device_id'}.union(kwargs['update_fields']) kwargs['update_fields'] = {'device_id'}.union(kwargs['update_fields'])
super().save(*args, **kwargs) super().save(*args, **kwargs)
def permission_set(self) -> set: def _event_permission_set(self) -> set:
return { return {
'event.orders:read', 'event.orders:read',
'event.orders:write', 'event.orders:write',
'event.vouchers:read', 'event.vouchers:read',
}
def _organizer_permission_set(self) -> set:
return {
'organizer.giftcards:read', 'organizer.giftcards:read',
'organizer.giftcards:write', 'organizer.giftcards:write',
'organizer.reusablemedia:read', 'organizer.reusablemedia:read',
@@ -211,7 +215,7 @@ class Device(LoggedModel):
has_event_access = (self.all_events and organizer == self.organizer) or ( has_event_access = (self.all_events and organizer == self.organizer) or (
event in self.limit_events.all() event in self.limit_events.all()
) )
return self.permission_set() if has_event_access else set() return self._event_permission_set() if has_event_access else set()
def get_organizer_permission_set(self, organizer) -> set: def get_organizer_permission_set(self, organizer) -> set:
""" """
@@ -220,7 +224,7 @@ class Device(LoggedModel):
:param organizer: The organizer of the event :param organizer: The organizer of the event
:return: set of permissions :return: set of permissions
""" """
return self.permission_set() if self.organizer == organizer else set() return self._organizer_permission_set() if self.organizer == organizer else set()
def has_event_permission(self, organizer, event, perm_name=None, request=None) -> bool: def has_event_permission(self, organizer, event, perm_name=None, request=None) -> bool:
""" """
@@ -237,8 +241,8 @@ class Device(LoggedModel):
event in self.limit_events.all() event in self.limit_events.all()
) )
if isinstance(perm_name, (tuple, list)): if isinstance(perm_name, (tuple, list)):
return has_event_access and any(p in self.permission_set() for p in perm_name) return has_event_access and any(p in self._event_permission_set() for p in perm_name)
return has_event_access and (not perm_name or perm_name in self.permission_set()) return has_event_access and (not perm_name or perm_name in self._event_permission_set())
def has_organizer_permission(self, organizer, perm_name=None, request=None): def has_organizer_permission(self, organizer, perm_name=None, request=None):
""" """
@@ -251,8 +255,8 @@ class Device(LoggedModel):
:return: bool :return: bool
""" """
if isinstance(perm_name, (tuple, list)): if isinstance(perm_name, (tuple, list)):
return organizer == self.organizer and any(p in self.permission_set() for p in perm_name) return organizer == self.organizer and any(p in self._organizer_permission_set() for p in perm_name)
return organizer == self.organizer and (not perm_name or perm_name in self.permission_set()) return organizer == self.organizer and (not perm_name or perm_name in self._organizer_permission_set())
def get_events_with_any_permission(self): def get_events_with_any_permission(self):
""" """
@@ -273,8 +277,8 @@ class Device(LoggedModel):
:return: Iterable of Events :return: Iterable of Events
""" """
if ( if (
isinstance(permission, (list, tuple)) and any(p in self.permission_set() for p in permission) isinstance(permission, (list, tuple)) and any(p in self._event_permission_set() for p in permission)
) or (isinstance(permission, str) and permission in self.permission_set()): ) or (isinstance(permission, str) and permission in self._event_permission_set()):
return self.get_events_with_any_permission() return self.get_events_with_any_permission()
else: else:
return self.organizer.events.none() return self.organizer.events.none()

View File

@@ -1386,14 +1386,13 @@ class Event(EventMixin, LoggedModel):
from .auth import User from .auth import User
if permission: if permission:
kwargs = {permission: True} qs = Team.objects.with_event_permission(permission)
else: else:
kwargs = {} qs = Team.objects.all()
team_with_perm = Team.objects.filter( team_with_perm = qs.filter(
members__pk=OuterRef('pk'), members__pk=OuterRef('pk'),
organizer=self.organizer, organizer=self.organizer,
**kwargs
).filter( ).filter(
Q(all_events=True) | Q(limit_events__pk=self.pk) Q(all_events=True) | Q(limit_events__pk=self.pk)
) )

View File

@@ -397,26 +397,32 @@ class Team(LoggedModel):
'object': str(self.organizer), 'object': str(self.organizer),
} }
def permission_set(self, include_legacy=True) -> set: def event_permission_set(self, include_legacy=True) -> set:
from ..permissions import ( from ..permissions import get_all_event_permissions
get_all_event_permissions, get_all_organizer_permissions,
)
result = set() result = set()
for permission in get_all_event_permissions().keys(): for permission in get_all_event_permissions().keys():
if self.all_event_permissions or self.limit_event_permissions.get(permission): if self.all_event_permissions or self.limit_event_permissions.get(permission):
result.add(permission) result.add(permission)
for permission in get_all_organizer_permissions().keys():
if self.all_organizer_permissions or self.limit_organizer_permissions.get(permission):
result.add(permission)
if include_legacy: if include_legacy:
# Add legacy permissions as well for plugin compatibility # Add legacy permissions as well for plugin compatibility
for k, v in OLD_TO_NEW_EVENT_COMPAT.items(): for k, v in OLD_TO_NEW_EVENT_COMPAT.items():
if self.all_event_permissions or all(self.limit_event_permissions.get(kk) for kk in v): if self.all_event_permissions or all(self.limit_event_permissions.get(kk) for kk in v):
result.add(k) result.add(k)
return result
def organizer_permission_set(self, include_legacy=True) -> set:
from ..permissions import get_all_organizer_permissions
result = set()
for permission in get_all_organizer_permissions().keys():
if self.all_organizer_permissions or self.limit_organizer_permissions.get(permission):
result.add(permission)
if include_legacy:
# Add legacy permissions as well for plugin compatibility
for k, v in OLD_TO_NEW_ORGANIZER_COMPAT.items(): for k, v in OLD_TO_NEW_ORGANIZER_COMPAT.items():
if self.all_organizer_permissions or all(self.limit_organizer_permissions.get(kk) for kk in v): if self.all_organizer_permissions or all(self.limit_organizer_permissions.get(kk) for kk in v):
result.add(k) result.add(k)
@@ -516,7 +522,7 @@ class TeamAPIToken(models.Model):
has_event_access = (self.team.all_events and organizer == self.team.organizer) or ( has_event_access = (self.team.all_events and organizer == self.team.organizer) or (
event in self.team.limit_events.all() event in self.team.limit_events.all()
) )
return self.team.permission_set() if has_event_access else set() return self.team.event_permission_set() if has_event_access else set()
def get_organizer_permission_set(self, organizer) -> set: def get_organizer_permission_set(self, organizer) -> set:
""" """
@@ -525,7 +531,7 @@ class TeamAPIToken(models.Model):
:param organizer: The organizer of the event :param organizer: The organizer of the event
:return: set of permissions :return: set of permissions
""" """
return self.team.permission_set() if self.team.organizer == organizer else set() return self.team.organizer_permission_set() if self.team.organizer == organizer else set()
def has_event_permission(self, organizer, event, perm_name=None, request=None) -> bool: def has_event_permission(self, organizer, event, perm_name=None, request=None) -> bool:
""" """

View File

@@ -376,7 +376,7 @@ class TeamForm(forms.ModelForm):
def clean(self): def clean(self):
data = super().clean() data = super().clean()
if self.instance.pk and not data['all_organizer_permissions'] and not data.get('limit_organizer_permissions', {}).get('organizer.teams:write'): if self.instance.pk and not data['all_organizer_permissions'] and 'organizer.teams:write' not in data.get('limit_organizer_permissions', []):
if not self.instance.organizer.teams.exclude(pk=self.instance.pk).filter( if not self.instance.organizer.teams.exclude(pk=self.instance.pk).filter(
TeamQuerySet.organizer_permission_q("organizer.teams:write"), TeamQuerySet.organizer_permission_q("organizer.teams:write"),
members__isnull=False members__isnull=False

View File

@@ -245,7 +245,7 @@ class OrganizerDetail(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
class OrganizerTeamView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView): class OrganizerTeamView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
model = Organizer model = Organizer
template_name = 'pretixcontrol/organizers/teams.html' template_name = 'pretixcontrol/organizers/teams.html'
permission = 'organizer.teams:read' permission = 'organizer.teams:write'
context_object_name = 'organizer' context_object_name = 'organizer'
@@ -1068,7 +1068,7 @@ class TeamMemberView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
TeamQuerySet.organizer_permission_q("organizer.teams:write"), TeamQuerySet.organizer_permission_q("organizer.teams:write"),
members__isnull=False members__isnull=False
).exists() or self.request.user.has_active_staff_session(self.request.session.session_key) ).exists() or self.request.user.has_active_staff_session(self.request.session.session_key)
if not other_admin_teams and self.object.has_permission() and self.object.members.count() == 1: if not other_admin_teams and self.object.has_organizer_permission("organizer.teams:write") and self.object.members.count() == 1:
messages.error(self.request, _('You cannot remove the last member from this team as no one would ' messages.error(self.request, _('You cannot remove the last member from this team as no one would '
'be left with the permission to change teams.')) 'be left with the permission to change teams.'))
return redirect(self.get_success_url()) return redirect(self.get_success_url())
@@ -1754,7 +1754,7 @@ class GiftCardAcceptanceListView(OrganizerDetailViewMixin, OrganizerPermissionRe
class GiftCardListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView): class GiftCardListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
model = GiftCard model = GiftCard
template_name = 'pretixcontrol/organizers/giftcards.html' template_name = 'pretixcontrol/organizers/giftcards.html'
permission = 'organizer.giftcards:write' permission = 'organizer.giftcards:read'
context_object_name = 'giftcards' context_object_name = 'giftcards'
paginate_by = 50 paginate_by = 50
@@ -1788,7 +1788,7 @@ class GiftCardListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView): class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
template_name = 'pretixcontrol/organizers/giftcard.html' template_name = 'pretixcontrol/organizers/giftcard.html'
permission = 'organizer.giftcards:write' permission = 'organizer.giftcards:read'
context_object_name = 'card' context_object_name = 'card'
def get_object(self, queryset=None) -> Organizer: def get_object(self, queryset=None) -> Organizer:
@@ -1799,6 +1799,8 @@ class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
@transaction.atomic() @transaction.atomic()
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if not request.user.has_organizer_permission(request.organizer, "organizer.giftcards:write", request=request):
raise PermissionDenied()
self.object = GiftCard.objects.select_for_update(of=OF_SELF).get(pk=self.get_object().pk) self.object = GiftCard.objects.select_for_update(of=OF_SELF).get(pk=self.get_object().pk)
if 'revert' in request.POST: if 'revert' in request.POST:
t = get_object_or_404(self.object.transactions.all(), pk=request.POST.get('revert'), order__isnull=False) t = get_object_or_404(self.object.transactions.all(), pk=request.POST.get('revert'), order__isnull=False)

View File

@@ -45,7 +45,7 @@ OLD_TO_NEW_ORGANIZER_MIGRATION = {
"can_create_events": ["organizer.events:create"], "can_create_events": ["organizer.events:create"],
"can_change_organizer_settings": ["organizer.settings.general:write", "organizer.devices:read", "can_change_organizer_settings": ["organizer.settings.general:write", "organizer.devices:read",
"organizer.devices:write"], "organizer.devices:write"],
"can_change_teams": ["organizer.teams:write", "organizer.teams:read"], "can_change_teams": ["organizer.teams:write"],
"can_manage_gift_cards": ["organizer.giftcards:read", "organizer.giftcards:write"], "can_manage_gift_cards": ["organizer.giftcards:read", "organizer.giftcards:write"],
"can_manage_customers": ["organizer.customers:read", "organizer.customers:write"], "can_manage_customers": ["organizer.customers:read", "organizer.customers:write"],
"can_manage_reusable_media": ["organizer.reusablemedia:read", "organizer.reusablemedia:write"], "can_manage_reusable_media": ["organizer.reusablemedia:read", "organizer.reusablemedia:write"],
@@ -66,7 +66,7 @@ OLD_TO_NEW_EVENT_COMPAT = {
OLD_TO_NEW_ORGANIZER_COMPAT = { OLD_TO_NEW_ORGANIZER_COMPAT = {
"can_create_events": ["organizer.events:create"], "can_create_events": ["organizer.events:create"],
"can_change_organizer_settings": ["organizer.settings.general:write"], "can_change_organizer_settings": ["organizer.settings.general:write"],
"can_change_teams": ["organizer.teams:write", "organizer.teams:read"], "can_change_teams": ["organizer.teams:write"],
"can_manage_gift_cards": ["organizer.giftcards:read", "organizer.giftcards:write"], "can_manage_gift_cards": ["organizer.giftcards:read", "organizer.giftcards:write"],
"can_manage_customers": ["organizer.customers:read", "organizer.customers:write"], "can_manage_customers": ["organizer.customers:read", "organizer.customers:write"],
"can_manage_reusable_media": ["organizer.reusablemedia:read", "organizer.reusablemedia:write"], "can_manage_reusable_media": ["organizer.reusablemedia:read", "organizer.reusablemedia:write"],

View File

@@ -97,7 +97,6 @@ class BankImportJobViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
queryset = BankImportJob.objects.none() queryset = BankImportJob.objects.none()
filter_backends = (DjangoFilterBackend,) filter_backends = (DjangoFilterBackend,)
filterset_class = JobFilter filterset_class = JobFilter
permission = 'event.orders:read'
def get_queryset(self): def get_queryset(self):
return BankImportJob.objects.filter(organizer=self.request.organizer) return BankImportJob.objects.filter(organizer=self.request.organizer)
@@ -105,9 +104,30 @@ class BankImportJobViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
def perform_create(self, serializer): def perform_create(self, serializer):
return serializer.save() return serializer.save()
def retrieve(self, request, *args, **kwargs):
perm_holder = (request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user)
has_any_event_perm = perm_holder.get_events_with_permission(
"event.orders:read", request=request
).filter(organizer=request.organizer).exists()
if not has_any_event_perm:
raise PermissionDenied('Invalid set of permissions')
return super().retrieve(request, *args, **kwargs)
def list(self, request, *args, **kwargs):
perm_holder = (request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user)
has_any_event_perm = perm_holder.get_events_with_permission(
"event.orders:read", request=request
).filter(organizer=request.organizer).exists()
if not has_any_event_perm:
raise PermissionDenied('Invalid set of permissions')
return super().list(request, *args, **kwargs)
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
perm_holder = (request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user) perm_holder = (request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user)
if not perm_holder.has_organizer_permission(request.organizer, 'event.orders:write'): has_any_event_perm = perm_holder.get_events_with_permission(
"event.orders:write", request=request
).filter(organizer=request.organizer).exists()
if not has_any_event_perm:
raise PermissionDenied('Invalid set of permissions') raise PermissionDenied('Invalid set of permissions')
if BankImportJob.objects.filter(Q(organizer=request.organizer)).filter( if BankImportJob.objects.filter(Q(organizer=request.organizer)).filter(

View File

@@ -76,7 +76,10 @@ def control_nav_import(sender, request=None, **kwargs):
@receiver(nav_organizer, dispatch_uid="payment_banktransfer_organav") @receiver(nav_organizer, dispatch_uid="payment_banktransfer_organav")
def control_nav_orga_import(sender, request=None, **kwargs): def control_nav_orga_import(sender, request=None, **kwargs):
url = resolve(request.path_info) url = resolve(request.path_info)
if not request.user.has_organizer_permission(request.organizer, 'event.orders:write', request=request): has_any_event_perm = request.user.get_events_with_permission(
"event.orders:write", request=request
).filter(organizer=request.organizer).exists()
if not has_any_event_perm:
return [] return []
return [ return [
{ {

View File

@@ -44,6 +44,7 @@ from typing import Set
from django import forms from django import forms
from django.contrib import messages from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.db import transaction from django.db import transaction
from django.db.models import Count, Q, QuerySet from django.db.models import Count, Q, QuerySet
from django.http import FileResponse, JsonResponse from django.http import FileResponse, JsonResponse
@@ -61,9 +62,7 @@ from pretix.base.models import Event, Order, OrderPayment, OrderRefund, Quota
from pretix.base.models.organizer import TeamQuerySet from pretix.base.models.organizer import TeamQuerySet
from pretix.base.settings import SettingsSandbox from pretix.base.settings import SettingsSandbox
from pretix.base.templatetags.money import money_filter from pretix.base.templatetags.money import money_filter
from pretix.control.permissions import ( from pretix.control.permissions import EventPermissionRequiredMixin
EventPermissionRequiredMixin, OrganizerPermissionRequiredMixin,
)
from pretix.control.views.organizer import OrganizerDetailViewMixin from pretix.control.views.organizer import OrganizerDetailViewMixin
from pretix.helpers.json import CustomJSONEncoder from pretix.helpers.json import CustomJSONEncoder
from pretix.plugins.banktransfer import camtimport, csvimport, mt940import from pretix.plugins.banktransfer import camtimport, csvimport, mt940import
@@ -626,6 +625,11 @@ class ImportView(ListView):
class OrganizerBanktransferView: class OrganizerBanktransferView:
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
has_any_event_perm = request.user.get_events_with_permission(
"event.orders:write", request=request
).filter(organizer=request.organizer).exists()
if not has_any_event_perm:
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
@@ -633,27 +637,26 @@ class EventImportView(EventPermissionRequiredMixin, ImportView):
permission = 'event.orders:write' permission = 'event.orders:write'
class OrganizerImportView(OrganizerBanktransferView, OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, class OrganizerImportView(OrganizerBanktransferView, OrganizerDetailViewMixin,
ImportView): ImportView):
permission = 'event.orders:write' pass
class EventJobDetailView(EventPermissionRequiredMixin, JobDetailView): class EventJobDetailView(EventPermissionRequiredMixin, JobDetailView):
permission = 'event.orders:write' permission = 'event.orders:write'
class OrganizerJobDetailView(OrganizerBanktransferView, OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, class OrganizerJobDetailView(OrganizerBanktransferView, OrganizerDetailViewMixin,
JobDetailView): JobDetailView):
permission = 'event.orders:write' pass
class EventActionView(EventPermissionRequiredMixin, ActionView): class EventActionView(EventPermissionRequiredMixin, ActionView):
permission = 'event.orders:write' permission = 'event.orders:write'
class OrganizerActionView(OrganizerBanktransferView, OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, class OrganizerActionView(OrganizerBanktransferView, OrganizerDetailViewMixin,
ActionView): ActionView):
permission = 'event.orders:write'
def order_qs(self): def order_qs(self):
all = self.request.user.teams.filter( all = self.request.user.teams.filter(
@@ -784,8 +787,7 @@ class EventRefundExportListView(EventPermissionRequiredMixin, RefundExportListVi
) )
class OrganizerRefundExportListView(OrganizerPermissionRequiredMixin, RefundExportListView): class OrganizerRefundExportListView(OrganizerBanktransferView, RefundExportListView):
permission = 'event.orders:write'
def get_success_url(self): def get_success_url(self):
return reverse('plugins:banktransfer:refunds.list', kwargs={ return reverse('plugins:banktransfer:refunds.list', kwargs={
@@ -828,8 +830,7 @@ class EventDownloadRefundExportView(EventPermissionRequiredMixin, DownloadRefund
) )
class OrganizerDownloadRefundExportView(OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, DownloadRefundExportView): class OrganizerDownloadRefundExportView(OrganizerBanktransferView, OrganizerDetailViewMixin, DownloadRefundExportView):
permission = 'event.orders:write'
def get_object(self, *args, **kwargs): def get_object(self, *args, **kwargs):
return get_object_or_404( return get_object_or_404(
@@ -857,9 +858,9 @@ class SepaXMLExportView(SingleObjectMixin, FormView):
template_name = 'pretixplugins/banktransfer/sepa_export.html' template_name = 'pretixplugins/banktransfer/sepa_export.html'
context_object_name = "export" context_object_name = "export"
def setup(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.object: RefundExport = self.get_object() self.object: RefundExport = self.get_object()
return super().dispatch(request, *args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
self.object.downloaded = True self.object.downloaded = True
@@ -891,8 +892,7 @@ class EventSepaXMLExportView(EventPermissionRequiredMixin, SepaXMLExportView):
return form return form
class OrganizerSepaXMLExportView(OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, SepaXMLExportView): class OrganizerSepaXMLExportView(OrganizerBanktransferView, OrganizerDetailViewMixin, SepaXMLExportView):
permission = 'event.orders:write'
def get_object(self, *args, **kwargs): def get_object(self, *args, **kwargs):
return get_object_or_404( return get_object_or_404(

View File

@@ -364,8 +364,8 @@ 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)) resp = user_client.get('/api/v1/organizers/{}/events/{}/scheduled_exports/'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
team.limit_organizer_permissions = {"organizer.events:create": True}
team.all_organizer_permissions = False team.all_organizer_permissions = False
team.limit_event_permissions = {"event.orders:read": True}
team.all_event_permissions = False team.all_event_permissions = False
team.save() team.save()

View File

@@ -340,6 +340,8 @@ def test_invoice_list_multi_filter(token_client, organizer, event, order, order2
@pytest.mark.django_db @pytest.mark.django_db
def test_organizer_level(token_client, organizer, team, event, event2, invoice, invoice2): 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)) resp = token_client.get('/api/v1/organizers/{}/invoices/'.format(organizer.slug))
assert resp.status_code == 200 assert resp.status_code == 200
assert len(resp.data['results']) == 2 assert len(resp.data['results']) == 2

View File

@@ -185,7 +185,7 @@ event_permission_sub_urls = [
('delete', 'event.settings.general:write', 'checkinlists/1/', 404), ('delete', 'event.settings.general:write', 'checkinlists/1/', 404),
('get', 'event.orders:read', 'checkinlists/1/positions/', 404), ('get', 'event.orders:read', 'checkinlists/1/positions/', 404),
('post', 'event.orders:write', 'checkinlists/1/positions/3/redeem/', 404), ('post', 'event.orders:write', 'checkinlists/1/positions/3/redeem/', 404),
('post', 'organizer.events:create', 'clone/', 400), ('post', ('organizer.events:create', 'event.settings.general:write'), 'clone/', 400),
('get', 'event.orders:read', 'cartpositions/', 200), ('get', 'event.orders:read', 'cartpositions/', 200),
('get', 'event.orders:read', 'cartpositions/1/', 404), ('get', 'event.orders:read', 'cartpositions/1/', 404),
('post', 'event.orders:write', 'cartpositions/', 400), ('post', 'event.orders:write', 'cartpositions/', 400),
@@ -328,7 +328,7 @@ def test_event_allowed_all_events(token_client, team, organizer, event, url):
@pytest.mark.parametrize("url", event_urls) @pytest.mark.parametrize("url", event_urls)
def test_event_allowed_all_events_device(device_client, device, organizer, event, url): 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])) 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 assert resp.status_code == 200
else: else:
assert resp.status_code == 403 assert resp.status_code == 403
@@ -351,7 +351,7 @@ def test_event_allowed_limit_events_device(device_client, organizer, device, eve
device.save() device.save()
device.limit_events.add(event) device.limit_events.add(event)
resp = device_client.get('/api/v1/organizers/{}/events/{}/{}'.format(organizer.slug, event.slug, url[1])) 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 assert resp.status_code == 200
else: else:
assert resp.status_code == 403 assert resp.status_code == 403
@@ -386,8 +386,14 @@ def test_event_not_existing(token_client, organizer, url, event):
@pytest.mark.parametrize("urlset", event_permission_sub_urls) @pytest.mark.parametrize("urlset", event_permission_sub_urls)
def test_token_event_subresources_permission_allowed(token_client, team, organizer, event, urlset): def test_token_event_subresources_permission_allowed(token_client, team, organizer, event, urlset):
team.all_events = True team.all_events = True
if urlset[1]: if urlset[1] is not None:
setattr(team, urlset[1], True) 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() team.save()
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format( resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format(
organizer.slug, event.slug, urlset[2])) organizer.slug, event.slug, urlset[2]))
@@ -401,7 +407,10 @@ def test_token_event_subresources_permission_not_allowed(token_client, team, org
team.all_events = False team.all_events = False
else: else:
team.all_events = True 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() team.save()
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format( resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format(
organizer.slug, event.slug, urlset[2])) organizer.slug, event.slug, urlset[2]))
@@ -415,7 +424,14 @@ def test_token_event_subresources_permission_not_allowed(token_client, team, org
@pytest.mark.parametrize("urlset", event_permission_root_urls) @pytest.mark.parametrize("urlset", event_permission_root_urls)
def test_token_event_permission_allowed(token_client, team, organizer, event, urlset): def test_token_event_permission_allowed(token_client, team, organizer, event, urlset):
team.all_events = True 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() team.save()
if urlset[0] == 'post': if urlset[0] == 'post':
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/'.format(organizer.slug)) resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/'.format(organizer.slug))
@@ -428,7 +444,9 @@ def test_token_event_permission_allowed(token_client, team, organizer, event, ur
@pytest.mark.parametrize("urlset", event_permission_root_urls) @pytest.mark.parametrize("urlset", event_permission_root_urls)
def test_token_event_permission_not_allowed(token_client, team, organizer, event, urlset): def test_token_event_permission_not_allowed(token_client, team, organizer, event, urlset):
team.all_events = True 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() team.save()
if urlset[0] == 'post': if urlset[0] == 'post':
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/'.format(organizer.slug)) resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/events/'.format(organizer.slug))
@@ -540,7 +558,7 @@ def test_device_subresource_permission_check(device_client, device, organizer, e
return return
resp = getattr(device_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format( resp = getattr(device_client, urlset[0])('/api/v1/organizers/{}/events/{}/{}'.format(
organizer.slug, event.slug, urlset[2])) 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] assert resp.status_code == urlset[3]
else: else:
if urlset[3] == 404: if urlset[3] == 404:
@@ -554,7 +572,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): def test_token_org_subresources_permission_allowed(token_client, team, organizer, event, urlset):
team.all_events = True team.all_events = True
if urlset[1]: if urlset[1]:
setattr(team, urlset[1], True) team.all_organizer_permissions = False
team.limit_organizer_permissions[urlset[1]] = True
team.save() team.save()
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/{}'.format( resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/{}'.format(
organizer.slug, urlset[2].format(team_id=team.pk))) organizer.slug, urlset[2].format(team_id=team.pk)))
@@ -567,8 +586,8 @@ def test_token_org_subresources_permission_not_allowed(token_client, team, organ
if urlset[1] is None: if urlset[1] is None:
team.all_events = False team.all_events = False
else: else:
team.all_events = True team.all_organizer_permissions = False
setattr(team, urlset[1], False) team.limit_organizer_permissions.pop(urlset[1], None)
team.save() team.save()
resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/{}'.format( resp = getattr(token_client, urlset[0])('/api/v1/organizers/{}/{}'.format(
organizer.slug, urlset[2].format(team_id=team.pk))) organizer.slug, urlset[2].format(team_id=team.pk)))

View File

@@ -242,8 +242,8 @@ def test_organizer_list(token_client, team, organizer, event, order, item, taxru
assert resp.data["count"] == 0 assert resp.data["count"] == 0
team.all_events = True team.all_events = True
team.limit_organizer_permissions = {"event.vouchers:read": True} team.limit_event_permissions = {"event.vouchers:read": True}
team.all_organizer_permissions = False team.all_event_permissions = False
team.save() team.save()
resp = token_client.get( resp = token_client.get(

View File

@@ -143,7 +143,8 @@ def test_event_fail_user_no_permission(event, user, team):
s.error_counter = 0 s.error_counter = 0
s.save() s.save()
team.limit_event_permissions["event.orders:read"] = False team.all_event_permissions = False
team.limit_event_permissions = {"event.vouchers:read": True}
team.save() team.save()
run_scheduled_exports(None) run_scheduled_exports(None)

View File

@@ -142,7 +142,8 @@ def test_notification_ignore_same_user(event, order, user, monkeypatch_on_commit
@pytest.mark.django_db @pytest.mark.django_db
def test_notification_ignore_insufficient_permissions(event, order, user, team, monkeypatch_on_commit): def test_notification_ignore_insufficient_permissions(event, order, user, team, monkeypatch_on_commit):
djmail.outbox = [] djmail.outbox = []
team.limit_event_permissions["event.orders:read"] = False team.all_event_permissions = False
team.limit_event_permissions = {"event.vouchers:read": True}
team.save() team.save()
user.notification_settings.create( user.notification_settings.create(
method='mail', event=event, action_type='pretix.event.order.paid', enabled=True method='mail', event=event, action_type='pretix.event.order.paid', enabled=True

View File

@@ -66,13 +66,6 @@ def admin_request(admin, client):
return r 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 @pytest.mark.django_db
def test_any_event_permission_limited(event, user): def test_any_event_permission_limited(event, user):
user._teamcache = {} user._teamcache = {}
@@ -183,9 +176,14 @@ def test_event_permissions_multiple_teams(event, user):
assert user.has_event_permission(event.organizer, event, 'event.orders:write') assert user.has_event_permission(event.organizer, event, 'event.orders:write')
assert user.has_event_permission(event.organizer, event, 'event.vouchers: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 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'} assert user.get_event_permission_set(event.organizer, event) == {
assert user.get_event_permission_set(event.organizer, event2) == {'event.orders:write', 'event.settings.general:write', 'event.orders:write', 'event.vouchers:write',
'event.settings.general: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',
}
@pytest.mark.django_db @pytest.mark.django_db
@@ -230,8 +228,14 @@ def test_organizer_permissions_multiple_teams(event, user):
assert user.has_organizer_permission(event.organizer, 'organizer.events:create') assert user.has_organizer_permission(event.organizer, 'organizer.events:create')
assert user.has_organizer_permission(event.organizer, 'organizer.settings.general:write') assert user.has_organizer_permission(event.organizer, 'organizer.settings.general:write')
assert not user.has_organizer_permission(event.organizer, 'organizer.teams: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'} assert user.get_organizer_permission_set(event.organizer) == {
assert user.get_organizer_permission_set(orga2) == {'organizer.teams:write'} '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 @pytest.mark.django_db

View File

@@ -76,7 +76,7 @@ class EventsTest(SoupTest):
date_from=datetime.datetime(2014, 9, 5, tzinfo=datetime.timezone.utc), date_from=datetime.datetime(2014, 9, 5, tzinfo=datetime.timezone.utc),
) )
self.team1 = Team.objects.create(organizer=self.orga1, all_organizer_permissions=True, all_event_permissions=True) self.team1 = Team.objects.create(organizer=self.orga1, all_event_permissions=True, limit_organizer_permissions={"organizer.events:create": True})
self.team1.members.add(self.user) self.team1.members.add(self.user)
self.team1.limit_events.add(self.event1) self.team1.limit_events.add(self.event1)

View File

@@ -162,7 +162,8 @@ def test_event_export_schedule(client, env):
@pytest.mark.django_db(transaction=True) @pytest.mark.django_db(transaction=True)
def test_event_limited_permission(client, env): def test_event_limited_permission(client, env):
env[2].limit_event_permissions = [] env[2].all_event_permissions = False
env[2].limit_event_permissions = {"event.orders:read": True}
env[2].save() env[2].save()
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy") user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
@@ -198,7 +199,7 @@ def test_event_limited_permission(client, env):
response = client.get(f"/control/event/dummy/dummy/orders/export/{s2.pk}/delete") response = client.get(f"/control/event/dummy/dummy/orders/export/{s2.pk}/delete")
assert response.status_code == 404 assert response.status_code == 404
env[2].limit_event_permissions = {"event:settings.general:write": True} env[2].limit_event_permissions = {"event.settings.general:write": True, "event.orders:read": True}
env[2].save() env[2].save()
response = client.get("/control/event/dummy/dummy/orders/export/") response = client.get("/control/event/dummy/dummy/orders/export/")
assert b"RULE1" in response.content assert b"RULE1" in response.content
@@ -330,7 +331,7 @@ def test_organizer_export_schedule(client, env):
@pytest.mark.django_db(transaction=True) @pytest.mark.django_db(transaction=True)
def test_organizer_limited_permission(client, env): def test_organizer_limited_permission(client, env):
env[2].all_organizer_permissions = False env[2].all_organizer_permissions = False
env[2].all_event_permissions = False env[2].all_event_permissions = True
env[2].save() env[2].save()
user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy") user2 = User.objects.create_user("dummy2@dummy.dummy", "dummy")
@@ -366,7 +367,7 @@ def test_organizer_limited_permission(client, env):
response = client.post(f"/control/organizer/dummy/export/{s2.pk}/run") response = client.post(f"/control/organizer/dummy/export/{s2.pk}/run")
assert response.status_code == 404 assert response.status_code == 404
env[2].limit_event_permissions = {"event:settings.general:write": True} env[2].limit_organizer_permissions = {"organizer.settings.general:write": True}
env[2].save() env[2].save()
response = client.get("/control/organizer/dummy/export/") response = client.get("/control/organizer/dummy/export/")
assert b"RULE1" in response.content assert b"RULE1" in response.content

View File

@@ -67,7 +67,7 @@ def env():
) )
event.settings.set('ticketoutput_testdummy__enabled', True) event.settings.set('ticketoutput_testdummy__enabled', True)
user = User.objects.create_user('dummy@dummy.dummy', 'dummy') user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
t = Team.objects.create(organizer=o, all_event_permissions=True) t = Team.objects.create(organizer=o, all_event_permissions=True, all_organizer_permissions=True)
t.members.add(user) t.members.add(user)
t.limit_events.add(event) t.limit_events.add(event)
o = Order.objects.create( o = Order.objects.create(

View File

@@ -425,7 +425,8 @@ def test_wrong_event_permission(perf_patch, client, env, perm, url, code, http_m
t = Team( t = Team(
pk=2, organizer=env[2], all_events=True pk=2, organizer=env[2], all_events=True
) )
setattr(t, perm, False) t.all_event_permissions = False
t.limit_event_permissions.pop(perm, None)
t.save() t.save()
t.members.add(env[1]) t.members.add(env[1])
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
@@ -443,7 +444,7 @@ def test_limited_event_permission_for_other_event(perf_patch, client, env, perm,
organizer=env[2], name='Dummy', slug='dummy2', organizer=env[2], name='Dummy', slug='dummy2',
date_from=now(), plugins='pretix.plugins.banktransfer' 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.members.add(env[1])
t.limit_events.add(event2) t.limit_events.add(event2)
@@ -461,13 +462,15 @@ def test_current_permission(client, env):
pk=2, organizer=env[2], all_events=True pk=2, organizer=env[2], all_events=True
) )
setattr(t, 'event.settings.general:write', 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.save()
t.members.add(env[1]) t.members.add(env[1])
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
response = client.get('/control/event/dummy/dummy/settings/') response = client.get('/control/event/dummy/dummy/settings/')
assert response.status_code == 200 assert response.status_code == 200
setattr(t, 'event.settings.general:write', False) t.limit_event_permissions.pop('event.settings.general:write', None)
t.save() t.save()
response = client.get('/control/event/dummy/dummy/settings/') response = client.get('/control/event/dummy/dummy/settings/')
assert response.status_code == 403 assert response.status_code == 403
@@ -477,7 +480,8 @@ def test_current_permission(client, env):
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls) @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): 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) 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.save()
t.members.add(env[1]) t.members.add(env[1])
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
@@ -495,7 +499,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) @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): def test_correct_event_permission_limited(perf_patch, client, env, perm, url, code, http_method):
t = Team(pk=2, organizer=env[2]) 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.save()
t.members.add(env[1]) t.members.add(env[1])
t.limit_events.add(env[0]) t.limit_events.add(env[0])
@@ -590,8 +595,11 @@ organizer_permission_urls = [
@pytest.mark.django_db @pytest.mark.django_db
@pytest.mark.parametrize("perm,url,code", organizer_permission_urls) @pytest.mark.parametrize("perm,url,code", organizer_permission_urls)
def test_wrong_organizer_permission(perf_patch, client, env, perm, url, code): def test_wrong_organizer_permission(perf_patch, client, env, perm, url, code):
t = Team(pk=2, organizer=env[2]) t = Team(pk=2, organizer=env[2], all_events=True)
setattr(t, perm, False) 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.save()
t.members.add(env[1]) t.members.add(env[1])
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
@@ -602,8 +610,14 @@ def test_wrong_organizer_permission(perf_patch, client, env, perm, url, code):
@pytest.mark.django_db @pytest.mark.django_db
@pytest.mark.parametrize("perm,url,code", organizer_permission_urls) @pytest.mark.parametrize("perm,url,code", organizer_permission_urls)
def test_correct_organizer_permission(perf_patch, client, env, perm, url, code): def test_correct_organizer_permission(perf_patch, client, env, perm, url, code):
t = Team(pk=2, organizer=env[2]) t = Team(pk=2, organizer=env[2], all_events=True)
setattr(t, perm, 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.save()
t.members.add(env[1]) t.members.add(env[1])
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')

View File

@@ -140,7 +140,8 @@ def test_typeahead(organizer, admin_user, client, gift_card):
# Unprivileged user can only do exact match # Unprivileged user can only do exact match
team.all_events = True team.all_events = True
team.limit_event_permissions["event.orders:read"] = False team.all_event_permissions = False
team.limit_event_permissions = {"event.vouchers:read": True}
team.save() team.save()
r = client.get('/control/organizer/dummy/ticket_select2?query=' + op.secret[0:3]) r = client.get('/control/organizer/dummy/ticket_select2?query=' + op.secret[0:3])

View File

@@ -98,7 +98,8 @@ class OrderSearchTest(SoupTest):
assert 'DEFFO2' not in resp assert 'DEFFO2' not in resp
def test_team_limit_event_wrong_permission(self): def test_team_limit_event_wrong_permission(self):
self.team.limit_event_permissions["event.orders:read"] = False self.team.all_event_permissions = False
self.team.limit_event_permissions = {"event.vouchers:read": True}
self.team.save() self.team.save()
resp = self.client.get('/control/search/orders/').content.decode() resp = self.client.get('/control/search/orders/').content.decode()
assert 'ABCFO1' not in resp assert 'ABCFO1' not in resp
@@ -113,7 +114,8 @@ class OrderSearchTest(SoupTest):
def test_team_all_events_wrong_permission(self): def test_team_all_events_wrong_permission(self):
self.team.all_events = True self.team.all_events = True
self.team.limit_event_permissions["event.orders:read"] = False self.team.all_event_permissions = False
self.team.limit_event_permissions = {"event.vouchers:read": True}
self.team.save() self.team.save()
resp = self.client.get('/control/search/orders/').content.decode() resp = self.client.get('/control/search/orders/').content.decode()
assert 'ABCFO1' not in resp assert 'ABCFO1' not in resp
@@ -283,7 +285,8 @@ class PaymentSearchTest(SoupTest):
assert 'DEFFO2' not in resp assert 'DEFFO2' not in resp
def test_team_limit_event_wrong_permission(self): def test_team_limit_event_wrong_permission(self):
self.team.limit_event_permissions["event.orders:read"] = False self.team.all_event_permissions = False
self.team.limit_event_permissions = {"event.vouchers:read": True}
self.team.save() self.team.save()
resp = self.client.get('/control/search/payments/').content.decode() resp = self.client.get('/control/search/payments/').content.decode()
assert 'ABCFO1' not in resp assert 'ABCFO1' not in resp
@@ -298,7 +301,8 @@ class PaymentSearchTest(SoupTest):
def test_team_all_events_wrong_permission(self): def test_team_all_events_wrong_permission(self):
self.team.all_events = True self.team.all_events = True
self.team.limit_event_permissions["event.orders:read"] = False self.team.all_event_permissions = False
self.team.limit_event_permissions = {"event.vouchers:read": True}
self.team.save() self.team.save()
resp = self.client.get('/control/search/payments/').content.decode() resp = self.client.get('/control/search/payments/').content.decode()
assert 'ABCFO1' not in resp assert 'ABCFO1' not in resp

View File

@@ -231,15 +231,16 @@ def test_create_team(event, admin_user, admin_team, client):
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
client.post('/control/organizer/dummy/team/add', { client.post('/control/organizer/dummy/team/add', {
'name': 'Foo', 'name': 'Foo',
'organizer.events:create': 'on', 'limit_organizer_permissions': ['organizer.events:create'],
'limit_events': str(event.pk), 'limit_events': str(event.pk),
'event.settings.general:write': 'on' 'limit_event_permissions': ['event.settings.general:write']
}, follow=True) }, follow=True)
with scopes_disabled(): with scopes_disabled():
t = Team.objects.last() t = Team.objects.last()
assert t.can_change_event_settings assert not t.all_event_permissions
assert t.can_create_events assert t.limit_event_permissions == {"event.settings.general:write": True}
assert not t.can_change_organizer_settings 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.limit_events.all()) == [event]
assert list(t.members.all()) == [admin_user] assert list(t.members.all()) == [admin_user]
@@ -249,13 +250,16 @@ def test_update_team(event, admin_user, admin_team, client):
client.login(email='dummy@dummy.dummy', password='dummy') client.login(email='dummy@dummy.dummy', password='dummy')
client.post('/control/organizer/dummy/team/{}/edit'.format(admin_team.pk), { client.post('/control/organizer/dummy/team/{}/edit'.format(admin_team.pk), {
'name': 'Admin', 'name': 'Admin',
'organizer.teams:write': 'on', 'limit_organizer_permissions': ['organizer.teams:write'],
'limit_events': str(event.pk), 'limit_events': str(event.pk),
'event.settings.general:write': 'on' 'all_event_permissions': 'on',
'all_organizer_permissions': '',
}, follow=True) }, follow=True)
admin_team.refresh_from_db() admin_team.refresh_from_db()
assert admin_team.can_change_event_settings assert admin_team.all_event_permissions
assert not admin_team.can_change_organizer_settings 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(): with scopes_disabled():
assert list(admin_team.limit_events.all()) == [event] assert list(admin_team.limit_events.all()) == [event]

View File

@@ -291,7 +291,12 @@ def test_assign_order_organizer_no_permission_for_event(env, client):
state=BankTransaction.STATE_NOMATCH, state=BankTransaction.STATE_NOMATCH,
amount=23, date='unknown') amount=23, date='unknown')
team = env[1].teams.first() 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') client.login(email='dummy@dummy.dummy', password='dummy')
r = json.loads(client.post('/control/organizer/{}/banktransfer/action/'.format(env[0].organizer.slug), { 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), 'action_{}'.format(trans.pk): 'assign:{}-{}'.format(env[0].slug.upper(), env[2].code),

View File

@@ -54,7 +54,7 @@ class TicketLayoutFormTest(SoupTest):
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), 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) self.item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1)
t = Team.objects.create(organizer=self.orga1, all_event_permissions=True) t = Team.objects.create(organizer=self.orga1, all_event_permissions=True, all_organizer_permissions=True)
t.members.add(self.user) t.members.add(self.user)
t.limit_events.add(self.event1) t.limit_events.add(self.event1)
self.client.login(email='dummy@dummy.dummy', password='dummy') self.client.login(email='dummy@dummy.dummy', password='dummy')

View File

@@ -36,7 +36,7 @@ def env():
date_from=now(), plugins='pretix.plugins.ticketoutputpdf' date_from=now(), plugins='pretix.plugins.ticketoutputpdf'
) )
user = User.objects.create_user('dummy@dummy.dummy', 'dummy') user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
t = Team.objects.create(organizer=event.organizer, all_event_permissions=True) t = Team.objects.create(organizer=event.organizer, all_event_permissions=True, all_organizer_permissions=True)
t.members.add(user) t.members.add(user)
t.limit_events.add(event) t.limit_events.add(event)
item1 = Item.objects.create(event=event, name="Ticket", default_price=23) item1 = Item.objects.create(event=event, name="Ticket", default_price=23)