From 02bfb7038e01451ca9fa000067cd47e16bbc938d Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 25 Feb 2026 11:08:35 +0100 Subject: [PATCH] Add permission for outgoing mails --- src/pretix/base/permissions.py | 9 +++++++++ src/pretix/control/navigation.py | 1 + src/pretix/control/views/mail.py | 6 +++--- src/pretix/helpers/permission_migration.py | 3 ++- src/tests/base/test_permissions.py | 8 ++++---- src/tests/control/test_permissions.py | 6 +++--- src/tests/control/test_teams.py | 2 ++ 7 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/pretix/base/permissions.py b/src/pretix/base/permissions.py index 1c3f074cd7..2e9031bae4 100644 --- a/src/pretix/base/permissions.py +++ b/src/pretix/base/permissions.py @@ -329,4 +329,13 @@ def register_default_organizer_permissions(sender, **kwargs): actions=["write"], options=OPTS_ALL_READ, ), + PermissionGroup( + name="organizer.outgoingmails", + label=_("Outgoing emails"), + actions=["read"], + options=[ + PermissionOption(actions=tuple(), label=pgettext_lazy("permission_level", "No access")), + PermissionOption(actions=("read",), label=pgettext_lazy("permission_level", "View")), + ], + ), ] diff --git a/src/pretix/control/navigation.py b/src/pretix/control/navigation.py index 75b4e03c40..fda90dc9ac 100644 --- a/src/pretix/control/navigation.py +++ b/src/pretix/control/navigation.py @@ -702,6 +702,7 @@ def get_organizer_navigation(request): 'active': (url.url_name == 'organizer.datasync.failedjobs'), }]) + if 'organizer.outgoingmails:read' in request.orgapermset: nav.append({ 'label': _('Outgoing emails'), 'url': reverse('control:organizer.outgoingmails', kwargs={ diff --git a/src/pretix/control/views/mail.py b/src/pretix/control/views/mail.py index b9c0c03368..d6e52cface 100644 --- a/src/pretix/control/views/mail.py +++ b/src/pretix/control/views/mail.py @@ -86,7 +86,7 @@ class OutgoingMailListView(OutgoingMailQueryMixin, OrganizerDetailViewMixin, Org template_name = 'pretixcontrol/organizers/outgoing_mails.html' # Assume "the highest" permission level for now because emails could belog to any event, order, or customer. # We plan to add a special permissoin in the future - permission = 'can_change_organizer_settings' + permission = 'organizer.outgoingmails:read' context_object_name = 'mails' paginate_by = 100 @@ -100,7 +100,7 @@ class OutgoingMailListView(OutgoingMailQueryMixin, OrganizerDetailViewMixin, Org class OutgoingMailDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView): model = OutgoingMail template_name = 'pretixcontrol/organizers/outgoing_mail.html' - permission = 'can_change_organizer_settings' + permission = 'organizer.outgoingmails:read' context_object_name = 'mail' def get_object(self, queryset=None): @@ -136,7 +136,7 @@ class OutgoingMailDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequir class OutgoingMailBulkAction(OutgoingMailQueryMixin, OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, View): - permission = 'can_change_organizer_settings' + permission = 'organizer.outgoingmails:read' @transaction.atomic def post(self, request, *args, **kwargs): diff --git a/src/pretix/helpers/permission_migration.py b/src/pretix/helpers/permission_migration.py index 435f801777..9d8b1fc0e0 100644 --- a/src/pretix/helpers/permission_migration.py +++ b/src/pretix/helpers/permission_migration.py @@ -42,7 +42,8 @@ OLD_TO_NEW_EVENT_MIGRATION = { OLD_TO_NEW_ORGANIZER_MIGRATION = { "can_create_events": ["organizer.events:create"], "can_change_organizer_settings": ["organizer.settings.general:write", "organizer.devices:read", - "organizer.devices:write", "organizer.seatingplans:write"], + "organizer.devices:write", "organizer.seatingplans:write", + "organizer.outgoingmails:read"], "can_change_teams": ["organizer.teams:write"], "can_manage_gift_cards": ["organizer.giftcards:read", "organizer.giftcards:write"], "can_manage_customers": ["organizer.customers:read", "organizer.customers:write"], diff --git a/src/tests/base/test_permissions.py b/src/tests/base/test_permissions.py index 1a162f6b67..9ac989a671 100644 --- a/src/tests/base/test_permissions.py +++ b/src/tests/base/test_permissions.py @@ -126,7 +126,7 @@ def test_specific_event_permission_limited(event, user): assert not user.has_event_permission(event.organizer, event, 'event.settings.general:write') assert user.has_event_permission(event.organizer, event, ('event.orders:write', 'event.settings.general:write')) - assert not user.has_event_permission(event.organizer, event, ('organizer.teams:write', 'event.settings.general:write')) + assert not user.has_event_permission(event.organizer, event, ('event.items:write', 'event.settings.general:write')) team.limit_event_permissions = {} team.save() @@ -182,7 +182,7 @@ def test_event_permissions_multiple_teams(event, user): } 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_orders', 'can_change_event_settings', 'can_change_settings', } @@ -337,7 +337,7 @@ def test_check_with_legacy_permission_names(event, user): "organizer.reusablemedia:write", } assert team1.event_permission_set() == { - "event.settings.general:write", "can_change_event_settings", + "event.settings.general:write", "can_change_event_settings", "can_change_settings", } assert team1.event_permission_set(include_legacy=False) == { "event.settings.general:write", @@ -346,7 +346,7 @@ def test_check_with_legacy_permission_names(event, user): # User methods user._teamcache = {} assert user.get_event_permission_set(event.organizer, event) == { - "event.settings.general:write", "can_change_event_settings", + "event.settings.general:write", "can_change_event_settings", "can_change_settings", } assert user.get_organizer_permission_set(event.organizer) == { "organizer.giftcards:read", diff --git a/src/tests/control/test_permissions.py b/src/tests/control/test_permissions.py index 208b935164..aaff20d9ee 100644 --- a/src/tests/control/test_permissions.py +++ b/src/tests/control/test_permissions.py @@ -537,9 +537,9 @@ organizer_permission_urls = [ ("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.settings.general:write", "organizer/dummy/outgoingmails", 200), - ("organizer.settings.general:write", "organizer/dummy/outgoingmail/1/", 404), - ("organizer.settings.general:write", "organizer/dummy/outgoingmail/bulk_action", 405), + ("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), diff --git a/src/tests/control/test_teams.py b/src/tests/control/test_teams.py index 7c90f4690d..ea9c633cd1 100644 --- a/src/tests/control/test_teams.py +++ b/src/tests/control/test_teams.py @@ -239,6 +239,7 @@ def test_create_team(event, admin_user, admin_team, client): '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", @@ -277,6 +278,7 @@ def test_update_team(event, admin_user, admin_team, client): '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",