mirror of
https://github.com/pretix/pretix.git
synced 2026-01-11 22:32:27 +00:00
Compare commits
9 Commits
py310
...
pluggable-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a973484505 | ||
|
|
91d6273f13 | ||
|
|
65fe1f9cdb | ||
|
|
560a4019b2 | ||
|
|
47d0505306 | ||
|
|
871bdebbe6 | ||
|
|
09b66d28c8 | ||
|
|
5d56daeb64 | ||
|
|
41749cc942 |
6
.github/workflows/tests.yml
vendored
6
.github/workflows/tests.yml
vendored
@@ -23,13 +23,13 @@ jobs:
|
||||
name: Tests
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.13"]
|
||||
python-version: ["3.9", "3.10", "3.11"]
|
||||
database: [sqlite, postgres]
|
||||
exclude:
|
||||
- database: sqlite
|
||||
python-version: "3.10"
|
||||
python-version: "3.9"
|
||||
- database: sqlite
|
||||
python-version: "3.11"
|
||||
python-version: "3.10"
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
|
||||
@@ -197,10 +197,11 @@ Permissions & security profiles
|
||||
|
||||
Device authentication is currently hardcoded to grant the following permissions:
|
||||
|
||||
* View event meta data and products etc.
|
||||
* View orders
|
||||
* Change orders
|
||||
* Manage gift cards
|
||||
* Read event meta data and products etc.
|
||||
* Read and write orders
|
||||
* Read and write gift cards
|
||||
* Read and write reusable media
|
||||
* Read vouchers
|
||||
|
||||
Devices cannot change events or products and cannot access vouchers.
|
||||
|
||||
|
||||
@@ -24,21 +24,58 @@ all_events boolean Whether this te
|
||||
limit_events list List of event slugs this team has access to
|
||||
require_2fa boolean Whether members of this team are required to use
|
||||
two-factor authentication
|
||||
can_create_events boolean
|
||||
can_change_teams boolean
|
||||
can_change_organizer_settings boolean
|
||||
can_manage_customers boolean
|
||||
can_manage_reusable_media boolean
|
||||
can_manage_gift_cards boolean
|
||||
can_change_event_settings boolean
|
||||
can_change_items boolean
|
||||
can_view_orders boolean
|
||||
can_change_orders boolean
|
||||
can_view_vouchers boolean
|
||||
can_change_vouchers boolean
|
||||
can_checkin_orders boolean
|
||||
all_event_permissions bool Whether members of this team are granted all event-level
|
||||
permissions, including future additions
|
||||
limit_event_permissions list of strings The event-level permissions team members are granted
|
||||
all_organizer_permissions bool Whether members of this team are granted all organizer-level
|
||||
permissions, including future additions
|
||||
all_organizer_permissions list of strings The organizer-level permissions team members are granted
|
||||
can_create_events boolean **DEPRECATED**. Legacy interface, use ``limit_organizer_permissions``.
|
||||
can_change_teams boolean **DEPRECATED**. Legacy interface, use ``limit_organizer_permissions``.
|
||||
can_change_organizer_settings boolean **DEPRECATED**. Legacy interface, use ``limit_organizer_permissions``.
|
||||
can_manage_customers boolean **DEPRECATED**. Legacy interface, use ``limit_organizer_permissions``.
|
||||
can_manage_reusable_media boolean **DEPRECATED**. Legacy interface, use ``limit_organizer_permissions``.
|
||||
can_manage_gift_cards boolean **DEPRECATED**. Legacy interface, use ``limit_organizer_permissions``.
|
||||
can_change_event_settings boolean **DEPRECATED**. Legacy interface, use ``limit_event_permissions``.
|
||||
can_change_items boolean **DEPRECATED**. Legacy interface, use ``limit_event_permissions``.
|
||||
can_view_orders boolean **DEPRECATED**. Legacy interface, use ``limit_event_permissions``.
|
||||
can_change_orders boolean **DEPRECATED**. Legacy interface, use ``limit_event_permissions``.
|
||||
can_view_vouchers boolean **DEPRECATED**. Legacy interface, use ``limit_event_permissions``.
|
||||
can_change_vouchers boolean **DEPRECATED**. Legacy interface, use ``limit_event_permissions``.
|
||||
can_checkin_orders boolean **DEPRECATED**. Legacy interface, use ``limit_event_permissions``.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Possible values for ``limit_organizer_permissions`` defined in the core pretix system (plugins might add more)::
|
||||
|
||||
organizer.events:create
|
||||
organizer.settings.general:write
|
||||
organizer.teams:write
|
||||
organizer.giftcards:read
|
||||
organizer.giftcards:write
|
||||
organizer.customers:read
|
||||
organizer.customers:write
|
||||
organizer.reusablemedia:read
|
||||
organizer.reusablemedia:write
|
||||
organizer.devices:read
|
||||
organizer.devices:write
|
||||
|
||||
Possible values for ``limit_event_permissions`` defined in the core pretix system (plugins might add more)::
|
||||
|
||||
event.settings.general:write
|
||||
event.settings.payment:write
|
||||
event.settings.plugins:write
|
||||
event.settings.email.sender:write
|
||||
event.settings.tax:write
|
||||
event.settings.invoicing:write
|
||||
event.subevents:write
|
||||
event.items:write
|
||||
event.orders:read
|
||||
event.orders:write
|
||||
event.orders:checkin
|
||||
event.vouchers:read
|
||||
event.vouchers:write
|
||||
event:cancel
|
||||
|
||||
Team member resource
|
||||
--------------------
|
||||
|
||||
@@ -121,6 +158,10 @@ Team endpoints
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"require_2fa": true,
|
||||
"all_event_permissions": true,
|
||||
"limit_event_permissions": [],
|
||||
"all_organizer_permissions": true,
|
||||
"limit_organizer_permissions": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
@@ -159,6 +200,10 @@ Team endpoints
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"require_2fa": true,
|
||||
"all_event_permissions": true,
|
||||
"limit_event_permissions": [],
|
||||
"all_organizer_permissions": true,
|
||||
"limit_organizer_permissions": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
@@ -187,7 +232,10 @@ Team endpoints
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"require_2fa": true,
|
||||
"can_create_events": true,
|
||||
"all_event_permissions": true,
|
||||
"limit_event_permissions": [],
|
||||
"all_organizer_permissions": true,
|
||||
"limit_organizer_permissions": [],
|
||||
...
|
||||
}
|
||||
|
||||
@@ -205,6 +253,10 @@ Team endpoints
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"require_2fa": true,
|
||||
"all_event_permissions": true,
|
||||
"limit_event_permissions": [],
|
||||
"all_organizer_permissions": true,
|
||||
"limit_organizer_permissions": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
@@ -232,7 +284,8 @@ Team endpoints
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"can_create_events": true
|
||||
"all_organizer_permissions": false,
|
||||
"limit_organizer_permissions": ["organizer.events:create"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
@@ -249,6 +302,10 @@ Team endpoints
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"require_2fa": true,
|
||||
"all_event_permissions": true,
|
||||
"limit_event_permissions": [],
|
||||
"all_organizer_permissions": false,
|
||||
"limit_organizer_permissions": ["organizer.events:create"],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
|
||||
@@ -55,12 +55,12 @@ your views:
|
||||
)
|
||||
|
||||
class AdminView(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
...
|
||||
|
||||
|
||||
@event_permission_required('can_view_orders')
|
||||
@event_permission_required('event.orders:read')
|
||||
def admin_view(request, organizer, event):
|
||||
...
|
||||
|
||||
@@ -78,7 +78,7 @@ event-related views, there is also a signal that allows you to add the view to t
|
||||
@receiver(nav_event, dispatch_uid='friends_tickets_nav')
|
||||
def navbar_info(sender, request, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_vouchers'):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.vouchers:read'):
|
||||
return []
|
||||
return [{
|
||||
'label': _('My plugin view'),
|
||||
@@ -118,7 +118,7 @@ for good integration. If you just want to display a form, you could do it like t
|
||||
|
||||
class MySettingsView(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
form_class = MySettingsForm
|
||||
template_name = 'my_plugin/settings.html'
|
||||
|
||||
@@ -204,13 +204,13 @@ In case of ``orga_router`` and ``event_router``, permission checking is done for
|
||||
in the control panel. However, you need to make sure on your own only to return the correct subset of data! ``request
|
||||
.event`` and ``request.organizer`` are available as usual.
|
||||
|
||||
To require a special permission like ``can_view_orders``, you do not need to inherit from a special ViewSet base
|
||||
To require a special permission like ``event.orders:read``, you do not need to inherit from a special ViewSet base
|
||||
class, you can just set the ``permission`` attribute on your viewset:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyViewSet(ModelViewSet):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
...
|
||||
|
||||
If you want to check the permission only for some methods of your viewset, you have to do it yourself. Note here that
|
||||
@@ -220,7 +220,7 @@ following:
|
||||
.. code-block:: python
|
||||
|
||||
perm_holder = (request.auth if isinstance(request.auth, TeamAPIToken) else request.user)
|
||||
if perm_holder.has_event_permission(request.event.organizer, request.event, 'can_view_orders'):
|
||||
if perm_holder.has_event_permission(request.event.organizer, request.event, 'event.orders:read'):
|
||||
...
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ Core
|
||||
: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,
|
||||
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
|
||||
""""""""""""
|
||||
|
||||
@@ -196,7 +196,7 @@ A simple implementation could look like this:
|
||||
.. code-block:: python
|
||||
|
||||
class MyNotificationType(NotificationType):
|
||||
required_permission = "can_view_orders"
|
||||
required_permission = "event.orders:read"
|
||||
action_type = "pretix.event.order.paid"
|
||||
verbose_name = _("Order has been paid")
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Permissions
|
||||
===========
|
||||
|
||||
pretix uses a fine-grained permission system to control who is allowed to control what parts of the system.
|
||||
The central concept here is the concept of *Teams*. You can read more on `configuring teams and permissions <user-teams>`_
|
||||
The central concept here is the concept of *Teams*. You can read more on `configuring teams and permissions`_
|
||||
and the :class:`pretix.base.models.Team` model in the respective parts of the documentation. The basic digest is:
|
||||
An organizer account can have any number of teams, and any number of users can be part of a team. A team can be
|
||||
assigned a set of permissions and connected to some or all of the events of the organizer.
|
||||
@@ -25,8 +25,8 @@ permission level to access a view:
|
||||
|
||||
|
||||
class MyOrgaView(OrganizerPermissionRequiredMixin, View):
|
||||
permission = 'can_change_organizer_settings'
|
||||
# Only users with the permission ``can_change_organizer_settings`` on
|
||||
permission = 'organizer.settings.general:write'
|
||||
# Only users with the permission ``organizer.settings.general:write`` on
|
||||
# this organizer can access this
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@ permission level to access a view:
|
||||
# Only users with *any* permission on this organizer can access this
|
||||
|
||||
|
||||
@organizer_permission_required('can_change_organizer_settings')
|
||||
@organizer_permission_required('organizer.settings.general:write')
|
||||
def my_orga_view(request, organizer, **kwargs):
|
||||
# Only users with the permission ``can_change_organizer_settings`` on
|
||||
# Only users with the permission ``organizer.settings.general:write`` on
|
||||
# this organizer can access this
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ Of course, the same is available on event level:
|
||||
|
||||
|
||||
class MyEventView(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
# Only users with the permission ``can_change_event_settings`` on
|
||||
permission = 'event.settings.general:write'
|
||||
# Only users with the permission ``event.settings.general:write`` on
|
||||
# this event can access this
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ Of course, the same is available on event level:
|
||||
# Only users with *any* permission on this event can access this
|
||||
|
||||
|
||||
@event_permission_required('can_change_event_settings')
|
||||
@event_permission_required('event.settings.general:write')
|
||||
def my_event_view(request, organizer, **kwargs):
|
||||
# Only users with the permission ``can_change_event_settings`` on
|
||||
# Only users with the permission ``event.settings.general:write`` on
|
||||
# this event can access this
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ When creating your own ``viewset`` using Django REST framework, you just need to
|
||||
and pretix will check it automatically for you::
|
||||
|
||||
class MyModelViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
Checking permission in code
|
||||
---------------------------
|
||||
@@ -136,12 +136,12 @@ Return all users that are in any team that is connected to this event::
|
||||
|
||||
Return all users that are in a team with a specific permission for this event::
|
||||
|
||||
>>> event.get_users_with_permission('can_change_event_settings')
|
||||
>>> event.get_users_with_permission('event.orders:read')
|
||||
<QuerySet: …>
|
||||
|
||||
Determine if a user has a certain permission for a specific event::
|
||||
|
||||
>>> user.has_event_permission(organizer, event, 'can_change_event_settings', request=request)
|
||||
>>> user.has_event_permission(organizer, event, 'event.orders:read', request=request)
|
||||
True
|
||||
|
||||
Determine if a user has any permission for a specific event::
|
||||
@@ -153,27 +153,27 @@ In the two previous commands, the ``request`` argument is optional, but required
|
||||
|
||||
The same method exists for organizer-level permissions::
|
||||
|
||||
>>> user.has_organizer_permission(organizer, 'can_change_event_settings', request=request)
|
||||
>>> user.has_organizer_permission(organizer, 'event.orders:read', request=request)
|
||||
True
|
||||
|
||||
Sometimes, it might be more useful to get the set of permissions at once::
|
||||
|
||||
>>> user.get_event_permission_set(organizer, event)
|
||||
{'can_change_event_settings', 'can_view_orders', 'can_change_orders'}
|
||||
{'event.settings.general:write', 'event.orders:read', 'event.orders:write'}
|
||||
|
||||
>>> user.get_organizer_permission_set(organizer, event)
|
||||
{'can_change_organizer_settings', 'can_create_events'}
|
||||
{'organizer.settings.general:write', 'organizer.events:create'}
|
||||
|
||||
Within a view on the ``/control`` subpath, the results of these two methods are already available in the
|
||||
``request.eventpermset`` and ``request.orgapermset`` properties. This makes it convenient to query them in templates::
|
||||
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
…
|
||||
{% endif %}
|
||||
|
||||
You can also do the reverse to get any events a user has access to::
|
||||
|
||||
>>> user.get_events_with_permission('can_change_event_settings', request=request)
|
||||
>>> user.get_events_with_permission('event.settings.general:write', request=request)
|
||||
<QuerySet: …>
|
||||
|
||||
>>> user.get_events_with_any_permission(request=request)
|
||||
@@ -195,3 +195,30 @@ staff mode is active. You can check if a user is in staff mode using their sessi
|
||||
Staff mode has a hard time limit and during staff mode, a middleware will log all requests made by that user. Later,
|
||||
the user is able to also save a message to comment on what they did in their administrative session. This feature is
|
||||
intended to help compliance with data protection rules as imposed e.g. by GDPR.
|
||||
|
||||
Adding permissions
|
||||
------------------
|
||||
|
||||
Plugins can add permissions through the ``register_event_permissions`` and ``register_organizer_permission``.
|
||||
We recommend to use this only for very significant permissions, as the system will become less usable with too many
|
||||
permission levels, also because the team page will show all permission options, even those of disabled plugins.
|
||||
We recommend to prefix the permission string with the plugin name and follow the ``<module>.<thing>:<action>`` pattern.
|
||||
|
||||
Example::
|
||||
|
||||
@receiver(register_event_permissions)
|
||||
def register_default_event_permissions(sender, **kwargs):
|
||||
return [
|
||||
Permission("pretix_myplugin.resource:read", _("Read resources"),
|
||||
"pretix_myplugin", _("Some helptext")),
|
||||
]
|
||||
|
||||
|
||||
@receiver(register_organizer_permissions)
|
||||
def register_default_organizer_permissions(sender, **kwargs):
|
||||
return [
|
||||
Permission("pretix_myplugin.resource:read", _("Read resources"),
|
||||
"pretix_myplugin", _("Some helptext")),
|
||||
]
|
||||
|
||||
.. _configuring teams and permissions: https://docs.pretix.eu/guides/teams/
|
||||
@@ -3,7 +3,7 @@ name = "pretix"
|
||||
dynamic = ["version"]
|
||||
description = "Reinventing presales, one ticket at a time"
|
||||
readme = "README.rst"
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.9"
|
||||
license = {file = "LICENSE"}
|
||||
keywords = ["tickets", "web", "shop", "ecommerce"]
|
||||
authors = [
|
||||
|
||||
@@ -124,12 +124,12 @@ class EventCRUDPermission(EventPermission):
|
||||
def has_permission(self, request, view):
|
||||
if not super(EventCRUDPermission, self).has_permission(request, view):
|
||||
return False
|
||||
elif view.action == 'create' and 'can_create_events' not in request.orgapermset:
|
||||
elif view.action == 'create' and 'organizer.events:create' not in request.orgapermset:
|
||||
return False
|
||||
elif view.action == 'destroy' and 'can_change_event_settings' not in request.eventpermset:
|
||||
elif view.action == 'destroy' and 'event.settings.general:write' not in request.eventpermset:
|
||||
return False
|
||||
elif view.action in ['update', 'partial_update'] \
|
||||
and 'can_change_event_settings' not in request.eventpermset:
|
||||
and 'event.settings.general:write' not in request.eventpermset:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -300,7 +300,7 @@ class EventSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
|
||||
def ignored_meta_properties(self):
|
||||
perm_holder = (self.context['request'].auth if isinstance(self.context['request'].auth, (Device, TeamAPIToken))
|
||||
else self.context['request'].user)
|
||||
if perm_holder.has_organizer_permission(self.context['request'].organizer, 'can_change_organizer_settings', request=self.context['request']):
|
||||
if perm_holder.has_organizer_permission(self.context['request'].organizer, 'organizer.settings.general:write', request=self.context['request']):
|
||||
return []
|
||||
return [k for k, p in self.meta_properties.items() if p.protected]
|
||||
|
||||
@@ -561,7 +561,7 @@ class SubEventSerializer(I18nAwareModelSerializer):
|
||||
def ignored_meta_properties(self):
|
||||
perm_holder = (self.context['request'].auth if isinstance(self.context['request'].auth, (Device, TeamAPIToken))
|
||||
else self.context['request'].user)
|
||||
if perm_holder.has_organizer_permission(self.context['request'].organizer, 'can_change_organizer_settings', request=self.context['request']):
|
||||
if perm_holder.has_organizer_permission(self.context['request'].organizer, 'organizer.settings.general:write', request=self.context['request']):
|
||||
return []
|
||||
return [k for k, p in self.meta_properties.items() if p.protected]
|
||||
|
||||
@@ -1079,16 +1079,16 @@ class SeatSerializer(I18nAwareModelSerializer):
|
||||
|
||||
def prefetch_expanded_data(self, items, request, expand_fields):
|
||||
if 'orderposition' in expand_fields:
|
||||
if 'can_view_orders' not in request.eventpermset:
|
||||
raise PermissionDenied('can_view_orders permission required for expand=orderposition')
|
||||
if 'event.orders:read' not in request.eventpermset:
|
||||
raise PermissionDenied('event.orders:read permission required for expand=orderposition')
|
||||
prefetch_by_id(items, OrderPosition.objects.prefetch_related('order'), 'orderposition_id', 'orderposition')
|
||||
if 'cartposition' in expand_fields:
|
||||
if 'can_view_orders' not in request.eventpermset:
|
||||
raise PermissionDenied('can_view_orders permission required for expand=cartposition')
|
||||
if 'event.orders:read' not in request.eventpermset:
|
||||
raise PermissionDenied('event.orders:read permission required for expand=cartposition')
|
||||
prefetch_by_id(items, CartPosition.objects, 'cartposition_id', 'cartposition')
|
||||
if 'voucher' in expand_fields:
|
||||
if 'can_view_vouchers' not in request.eventpermset:
|
||||
raise PermissionDenied('can_view_vouchers permission required for expand=voucher')
|
||||
if 'event.vouchers:read' not in request.eventpermset:
|
||||
raise PermissionDenied('event.vouchers:read permission required for expand=voucher')
|
||||
prefetch_by_id(items, Voucher.objects, 'voucher_id', 'voucher')
|
||||
|
||||
def __init__(self, instance, *args, **kwargs):
|
||||
|
||||
@@ -613,7 +613,7 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
# /events/…/checkinlists/…/positions/
|
||||
# We're unable to check this on this level if we're on /checkinrpc/, in which case we rely on the view
|
||||
# layer to not set pdf_data=true in the first place.
|
||||
request and hasattr(request, 'eventpermset') and 'can_view_orders' not in request.eventpermset
|
||||
request and hasattr(request, 'eventpermset') and 'event.orders:read' not in request.eventpermset
|
||||
)
|
||||
if ('pdf_data' in self.context and not self.context['pdf_data']) or pdf_data_forbidden:
|
||||
self.fields.pop('pdf_data', None)
|
||||
|
||||
@@ -45,12 +45,19 @@ from pretix.base.models import (
|
||||
SalesChannel, SeatingPlan, Team, TeamAPIToken, TeamInvite, User,
|
||||
)
|
||||
from pretix.base.models.seating import SeatingPlanLayoutValidator
|
||||
from pretix.base.permissions import (
|
||||
get_all_event_permissions, get_all_organizer_permissions,
|
||||
)
|
||||
from pretix.base.plugins import (
|
||||
PLUGIN_LEVEL_EVENT, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID,
|
||||
PLUGIN_LEVEL_ORGANIZER,
|
||||
)
|
||||
from pretix.base.services.mail import SendMailException, mail
|
||||
from pretix.base.settings import validate_organizer_settings
|
||||
from pretix.helpers.permission_migration import (
|
||||
OLD_TO_NEW_EVENT_COMPAT, OLD_TO_NEW_EVENT_MIGRATION,
|
||||
OLD_TO_NEW_ORGANIZER_COMPAT, OLD_TO_NEW_ORGANIZER_MIGRATION,
|
||||
)
|
||||
from pretix.helpers.urls import build_absolute_uri as build_global_uri
|
||||
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||
|
||||
@@ -306,21 +313,97 @@ class EventSlugField(serializers.SlugRelatedField):
|
||||
return self.context['organizer'].events.all()
|
||||
|
||||
|
||||
class PermissionMultipleChoiceField(serializers.MultipleChoiceField):
|
||||
def to_internal_value(self, data):
|
||||
return {
|
||||
p: True for p in super().to_internal_value(data)
|
||||
}
|
||||
|
||||
def to_representation(self, value):
|
||||
return [p for p, v in value.items() if v]
|
||||
|
||||
|
||||
class TeamSerializer(serializers.ModelSerializer):
|
||||
limit_events = EventSlugField(slug_field='slug', many=True)
|
||||
limit_event_permissions = PermissionMultipleChoiceField(choices=[], required=False, allow_null=False, allow_empty=True)
|
||||
limit_organizer_permissions = PermissionMultipleChoiceField(choices=[], required=False, allow_null=False, allow_empty=True)
|
||||
|
||||
# Legacy fields, handled in to_representation and validate
|
||||
can_change_event_settings = serializers.BooleanField(required=False, write_only=True)
|
||||
can_change_items = serializers.BooleanField(required=False, write_only=True)
|
||||
can_view_orders = serializers.BooleanField(required=False, write_only=True)
|
||||
can_change_orders = serializers.BooleanField(required=False, write_only=True)
|
||||
can_checkin_orders = serializers.BooleanField(required=False, write_only=True)
|
||||
can_view_vouchers = serializers.BooleanField(required=False, write_only=True)
|
||||
can_change_vouchers = serializers.BooleanField(required=False, write_only=True)
|
||||
can_create_events = serializers.BooleanField(required=False, write_only=True)
|
||||
can_change_organizer_settings = serializers.BooleanField(required=False, write_only=True)
|
||||
can_change_teams = serializers.BooleanField(required=False, write_only=True)
|
||||
can_manage_gift_cards = serializers.BooleanField(required=False, write_only=True)
|
||||
can_manage_customers = serializers.BooleanField(required=False, write_only=True)
|
||||
can_manage_reusable_media = serializers.BooleanField(required=False, write_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Team
|
||||
fields = (
|
||||
'id', 'name', 'require_2fa', 'all_events', 'limit_events', 'can_create_events', 'can_change_teams',
|
||||
'can_change_organizer_settings', 'can_manage_gift_cards', 'can_change_event_settings',
|
||||
'can_change_items', 'can_view_orders', 'can_change_orders', 'can_view_vouchers',
|
||||
'can_change_vouchers', 'can_checkin_orders', 'can_manage_customers', 'can_manage_reusable_media'
|
||||
'id', 'name', 'require_2fa', 'all_events', 'limit_events', 'all_event_permissions', 'limit_event_permissions',
|
||||
'all_organizer_permissions', 'limit_organizer_permissions', 'can_change_event_settings',
|
||||
'can_change_items', 'can_view_orders', 'can_change_orders', 'can_checkin_orders', 'can_view_vouchers',
|
||||
'can_change_vouchers', 'can_create_events', 'can_change_organizer_settings', 'can_change_teams',
|
||||
'can_manage_gift_cards', 'can_manage_customers', 'can_manage_reusable_media'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['limit_event_permissions'].choices = [(p.name, p.name) for p in get_all_event_permissions().values()]
|
||||
self.fields['limit_organizer_permissions'].choices = [(p.name, p.name) for p in get_all_organizer_permissions().values()]
|
||||
|
||||
def to_representation(self, instance):
|
||||
r = super().to_representation(instance)
|
||||
for old, new in OLD_TO_NEW_EVENT_COMPAT.items():
|
||||
r[old] = instance.all_event_permissions or all(instance.limit_event_permissions.get(n) for n in new)
|
||||
for old, new in OLD_TO_NEW_ORGANIZER_COMPAT.items():
|
||||
r[old] = instance.all_organizer_permissions or all(instance.limit_organizer_permissions.get(n) for n in new)
|
||||
return r
|
||||
|
||||
def validate(self, data):
|
||||
old_data_set = any(k.startswith("can_") for k in data)
|
||||
new_data_set = any(k in data for k in [
|
||||
"all_event_permissions", "limit_event_permissions", "all_organizer_permissions", "limit_organizer_permissions"
|
||||
])
|
||||
if old_data_set and new_data_set:
|
||||
raise ValidationError("You cannot set deprecated and current permission attributes at the same time.")
|
||||
|
||||
full_data = self.to_internal_value(self.to_representation(self.instance)) if self.instance else {}
|
||||
full_data.update(data)
|
||||
|
||||
if new_data_set:
|
||||
if full_data.get('limit_event_permissions') and full_data.get('all_event_permissions'):
|
||||
raise ValidationError('Do not set both limit_event_permissions and all_event_permissions.')
|
||||
if full_data.get('limit_organizer_permissions') and full_data.get('all_organizer_permissions'):
|
||||
raise ValidationError('Do not set both limit_organizer_permissions and all_organizer_permissions.')
|
||||
|
||||
if old_data_set:
|
||||
# Migrate with same logic as in migration 0297_plugable_permissions
|
||||
if all(full_data.get(k) is True for k in OLD_TO_NEW_EVENT_MIGRATION.keys() if k != "can_checkin_orders"):
|
||||
data["all_event_permissions"] = True
|
||||
data["limit_event_permissions"] = {}
|
||||
else:
|
||||
data["all_event_permissions"] = False
|
||||
data["limit_event_permissions"] = {}
|
||||
for k, v in OLD_TO_NEW_EVENT_MIGRATION.items():
|
||||
if full_data.get(k) is True:
|
||||
data["limit_event_permissions"].update({kk: True for kk in v})
|
||||
if all(full_data.get(k) is True for k in OLD_TO_NEW_ORGANIZER_MIGRATION.keys() if k != "can_checkin_orders"):
|
||||
data["all_organizer_permissions"] = True
|
||||
data["limit_organizer_permissions"] = {}
|
||||
else:
|
||||
data["all_organizer_permissions"] = False
|
||||
data["limit_organizer_permissions"] = {}
|
||||
for k, v in OLD_TO_NEW_ORGANIZER_MIGRATION.items():
|
||||
if full_data.get(k) is True:
|
||||
data["limit_organizer_permissions"].update({kk: True for kk in v})
|
||||
|
||||
if full_data.get('limit_events') and full_data.get('all_events'):
|
||||
raise ValidationError('Do not set both limit_events and all_events.')
|
||||
return data
|
||||
|
||||
@@ -52,8 +52,8 @@ class CartPositionViewSet(CreateModelMixin, DestroyModelMixin, viewsets.ReadOnly
|
||||
ordering = ('datetime',)
|
||||
ordering_fields = ('datetime', 'cart_id')
|
||||
lookup_field = 'id'
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return CartPosition.objects.filter(
|
||||
|
||||
@@ -118,11 +118,11 @@ class CheckinListViewSet(viewsets.ModelViewSet):
|
||||
|
||||
def _get_permission_name(self, request):
|
||||
if request.path.endswith('/failed_checkins/'):
|
||||
return 'can_checkin_orders', 'can_change_orders'
|
||||
return 'event.orders:checkin', 'event.orders:write'
|
||||
elif request.method in SAFE_METHODS:
|
||||
return 'can_view_orders', 'can_checkin_orders',
|
||||
return 'event.orders:read', 'event.orders:checkin',
|
||||
else:
|
||||
return 'can_change_event_settings'
|
||||
return 'event.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.request.event.checkin_lists.prefetch_related(
|
||||
@@ -457,7 +457,7 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force,
|
||||
'event': op.order.event,
|
||||
'pdf_data': pdf_data and (
|
||||
user if user and user.is_authenticated else auth
|
||||
).has_event_permission(request.organizer, event, 'can_view_orders', request),
|
||||
).has_event_permission(request.organizer, event, 'event.orders:read', request),
|
||||
}
|
||||
|
||||
common_checkin_args = dict(
|
||||
@@ -822,8 +822,8 @@ class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
}
|
||||
|
||||
filterset_class = CheckinOrderPositionFilter
|
||||
permission = ('can_view_orders', 'can_checkin_orders')
|
||||
write_permission = ('can_change_orders', 'can_checkin_orders')
|
||||
permission = ('event.orders:read', 'event.orders:checkin')
|
||||
write_permission = ('event.orders:write', 'event.orders:checkin')
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
@@ -854,7 +854,7 @@ class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
expand=self.request.query_params.getlist('expand'),
|
||||
)
|
||||
|
||||
if 'pk' not in self.request.resolver_match.kwargs and 'can_view_orders' not in self.request.eventpermset \
|
||||
if 'pk' not in self.request.resolver_match.kwargs and 'event.orders:read' not in self.request.eventpermset \
|
||||
and len(self.request.query_params.get('search', '')) < 3:
|
||||
qs = qs.none()
|
||||
|
||||
@@ -903,9 +903,9 @@ class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class CheckinRPCRedeemView(views.APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
events = self.request.auth.get_events_with_permission(('can_change_orders', 'can_checkin_orders'))
|
||||
events = self.request.auth.get_events_with_permission(('event.orders:write', 'event.orders:checkin'))
|
||||
elif self.request.user.is_authenticated:
|
||||
events = self.request.user.get_events_with_permission(('can_change_orders', 'can_checkin_orders'), self.request).filter(
|
||||
events = self.request.user.get_events_with_permission(('event.orders:write', 'event.orders:checkin'), self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
else:
|
||||
@@ -972,9 +972,9 @@ class CheckinRPCSearchView(ListAPIView):
|
||||
@cached_property
|
||||
def lists(self):
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
events = self.request.auth.get_events_with_permission(('can_view_orders', 'can_checkin_orders'))
|
||||
events = self.request.auth.get_events_with_permission(('event.orders:read', 'event.orders:checkin'))
|
||||
elif self.request.user.is_authenticated:
|
||||
events = self.request.user.get_events_with_permission(('can_view_orders', 'can_checkin_orders'), self.request).filter(
|
||||
events = self.request.user.get_events_with_permission(('event.orders:read', 'event.orders:checkin'), self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
else:
|
||||
@@ -991,9 +991,9 @@ class CheckinRPCSearchView(ListAPIView):
|
||||
@cached_property
|
||||
def has_full_access_permission(self):
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
events = self.request.auth.get_events_with_permission('can_view_orders')
|
||||
events = self.request.auth.get_events_with_permission('event.orders:read')
|
||||
elif self.request.user.is_authenticated:
|
||||
events = self.request.user.get_events_with_permission('can_view_orders', self.request).filter(
|
||||
events = self.request.user.get_events_with_permission('event.orders:read', self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
else:
|
||||
@@ -1020,9 +1020,9 @@ class CheckinRPCSearchView(ListAPIView):
|
||||
class CheckinRPCAnnulView(views.APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
events = self.request.auth.get_events_with_permission(('can_change_orders', 'can_checkin_orders'))
|
||||
events = self.request.auth.get_events_with_permission(('event.orders:write', 'event.orders:checkin'))
|
||||
elif self.request.user.is_authenticated:
|
||||
events = self.request.user.get_events_with_permission(('can_change_orders', 'can_checkin_orders'), self.request).filter(
|
||||
events = self.request.user.get_events_with_permission(('event.orders:write', 'event.orders:checkin'), self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
else:
|
||||
@@ -1100,7 +1100,7 @@ class CheckinViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
filterset_class = CheckinFilter
|
||||
ordering = ('created', 'id')
|
||||
ordering_fields = ('created', 'datetime', 'id',)
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Checkin.all.filter().select_related(
|
||||
|
||||
@@ -57,7 +57,7 @@ class DiscountViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('position', 'id')
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.discounts.prefetch_related(
|
||||
|
||||
@@ -341,7 +341,7 @@ class CloneEventViewSet(viewsets.ModelViewSet):
|
||||
lookup_field = 'slug'
|
||||
lookup_url_kwarg = 'event'
|
||||
http_method_names = ['post']
|
||||
write_permission = 'can_create_events'
|
||||
write_permission = 'event.settings.general:write'
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
@@ -350,6 +350,12 @@ class CloneEventViewSet(viewsets.ModelViewSet):
|
||||
return ctx
|
||||
|
||||
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.instance.log_action(
|
||||
@@ -426,7 +432,7 @@ with scopes_disabled():
|
||||
class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = SubEventSerializer
|
||||
queryset = SubEvent.objects.none()
|
||||
write_permission = 'can_change_event_settings'
|
||||
write_permission = 'event.settings.general:write'
|
||||
filter_backends = (DjangoFilterBackend, TotalOrderingFilter)
|
||||
ordering = ('date_from',)
|
||||
ordering_fields = ('id', 'date_from', 'last_modified')
|
||||
@@ -546,7 +552,7 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
class TaxRuleViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = TaxRuleSerializer
|
||||
queryset = TaxRule.objects.none()
|
||||
write_permission = 'can_change_event_settings'
|
||||
write_permission = 'event.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.tax_rules.all()
|
||||
@@ -589,7 +595,7 @@ class TaxRuleViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
class ItemMetaPropertiesViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = ItemMetaPropertiesSerializer
|
||||
queryset = ItemMetaProperty.objects.none()
|
||||
write_permission = 'can_change_event_settings'
|
||||
write_permission = 'event.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.request.event.item_meta_properties.all()
|
||||
@@ -636,14 +642,14 @@ class ItemMetaPropertiesViewSet(viewsets.ModelViewSet):
|
||||
|
||||
class EventSettingsView(views.APIView):
|
||||
permission = None
|
||||
write_permission = 'can_change_event_settings'
|
||||
write_permission = 'event.settings.general:write'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if isinstance(request.auth, Device):
|
||||
s = DeviceEventSettingsSerializer(instance=request.event.settings, event=request.event, context={
|
||||
'request': request
|
||||
})
|
||||
elif 'can_change_event_settings' in request.eventpermset:
|
||||
elif 'event.settings.general:write' in request.eventpermset:
|
||||
s = EventSettingsSerializer(instance=request.event.settings, event=request.event, context={
|
||||
'request': request
|
||||
})
|
||||
@@ -701,7 +707,7 @@ class SeatFilter(FilterSet):
|
||||
class SeatViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = SeatSerializer
|
||||
queryset = Seat.objects.none()
|
||||
write_permission = 'can_change_event_settings'
|
||||
write_permission = 'event.settings.general:write'
|
||||
filter_backends = (DjangoFilterBackend, )
|
||||
filterset_class = SeatFilter
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ class ExportersMixin:
|
||||
|
||||
|
||||
class EventExportersViewSet(ExportersMixin, viewsets.ViewSet):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_serializer_kwargs(self):
|
||||
return {}
|
||||
@@ -169,7 +169,7 @@ class OrganizerExportersViewSet(ExportersMixin, viewsets.ViewSet):
|
||||
perm_holder = self.request.auth
|
||||
else:
|
||||
perm_holder = self.request.user
|
||||
events = perm_holder.get_events_with_permission('can_view_orders', request=self.request).filter(
|
||||
events = perm_holder.get_events_with_permission('event.orders:read', request=self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
responses = register_multievent_data_exporters.send(self.request.organizer)
|
||||
@@ -196,7 +196,7 @@ class OrganizerExportersViewSet(ExportersMixin, viewsets.ViewSet):
|
||||
else:
|
||||
perm_holder = self.request.user
|
||||
return {
|
||||
'events': perm_holder.get_events_with_permission('can_view_orders', request=self.request).filter(
|
||||
'events': perm_holder.get_events_with_permission('event.orders:read', request=self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
}
|
||||
@@ -222,11 +222,11 @@ class ScheduledExportersViewSet(viewsets.ModelViewSet):
|
||||
class ScheduledEventExportViewSet(ScheduledExportersViewSet):
|
||||
serializer_class = ScheduledEventExportSerializer
|
||||
queryset = ScheduledEventExport.objects.none()
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_queryset(self):
|
||||
perm_holder = self.request.auth if isinstance(self.request.auth, (TeamAPIToken, Device)) else self.request.user
|
||||
if not perm_holder.has_event_permission(self.request.organizer, self.request.event, 'can_change_event_settings',
|
||||
if not perm_holder.has_event_permission(self.request.organizer, self.request.event, 'event.settings.general:write',
|
||||
request=self.request):
|
||||
if self.request.user.is_authenticated:
|
||||
qs = self.request.event.scheduled_exports.filter(owner=self.request.user)
|
||||
@@ -291,7 +291,7 @@ class ScheduledOrganizerExportViewSet(ScheduledExportersViewSet):
|
||||
|
||||
def get_queryset(self):
|
||||
perm_holder = self.request.auth if isinstance(self.request.auth, (TeamAPIToken, Device)) else self.request.user
|
||||
if not perm_holder.has_organizer_permission(self.request.organizer, 'can_change_organizer_settings',
|
||||
if not perm_holder.has_organizer_permission(self.request.organizer, 'organizer.settings.general:write',
|
||||
request=self.request):
|
||||
if self.request.user.is_authenticated:
|
||||
qs = self.request.organizer.scheduled_exports.filter(owner=self.request.user)
|
||||
@@ -324,9 +324,9 @@ class ScheduledOrganizerExportViewSet(ScheduledExportersViewSet):
|
||||
@cached_property
|
||||
def events(self):
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
return self.request.auth.get_events_with_permission('can_view_orders')
|
||||
return self.request.auth.get_events_with_permission('event.orders:read')
|
||||
elif self.request.user.is_authenticated:
|
||||
return self.request.user.get_events_with_permission('can_view_orders', self.request).filter(
|
||||
return self.request.user.get_events_with_permission('event.orders:read', self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ordering = ('position', 'id')
|
||||
filterset_class = ItemFilter
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.items.select_related('tax_rule').prefetch_related(
|
||||
@@ -163,7 +163,7 @@ class ItemVariationViewSet(viewsets.ModelViewSet):
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('id',)
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
@cached_property
|
||||
def item(self):
|
||||
@@ -234,7 +234,7 @@ class ItemBundleViewSet(viewsets.ModelViewSet):
|
||||
ordering_fields = ('id',)
|
||||
ordering = ('id',)
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
@cached_property
|
||||
def item(self):
|
||||
@@ -286,7 +286,7 @@ class ItemProgramTimeViewSet(viewsets.ModelViewSet):
|
||||
ordering_fields = ('id',)
|
||||
ordering = ('id',)
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
@cached_property
|
||||
def item(self):
|
||||
@@ -339,7 +339,7 @@ class ItemAddOnViewSet(viewsets.ModelViewSet):
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('id',)
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
@cached_property
|
||||
def item(self):
|
||||
@@ -398,7 +398,7 @@ class ItemCategoryViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('position', 'id')
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.categories.all()
|
||||
@@ -453,7 +453,7 @@ class QuestionViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('position', 'id')
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.questions.prefetch_related('options').all()
|
||||
@@ -497,7 +497,7 @@ class QuestionOptionViewSet(viewsets.ModelViewSet):
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('position',)
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
def get_queryset(self):
|
||||
q = get_object_or_404(Question, pk=self.kwargs['question'], event=self.request.event)
|
||||
@@ -564,7 +564,7 @@ class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ordering_fields = ('id', 'size')
|
||||
ordering = ('id',)
|
||||
permission = None
|
||||
write_permission = 'can_change_items'
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.quotas.select_related('subevent').prefetch_related('items', 'variations').all()
|
||||
|
||||
@@ -62,8 +62,8 @@ 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'
|
||||
permission = 'organizer.reusablemedia:read'
|
||||
write_permission = 'organizer.reusablemedia:write'
|
||||
filter_backends = (DjangoFilterBackend, OrderingFilter)
|
||||
ordering = ('-updated', '-id')
|
||||
ordering_fields = ('created', 'updated', 'identifier', 'type', 'id')
|
||||
|
||||
@@ -317,7 +317,7 @@ class OrderViewSetMixin:
|
||||
|
||||
class OrganizerOrderViewSet(OrderViewSetMixin, viewsets.ReadOnlyModelViewSet):
|
||||
def get_base_queryset(self):
|
||||
perm = "can_view_orders" if self.request.method in SAFE_METHODS else "can_change_orders"
|
||||
perm = "event.orders:read" if self.request.method in SAFE_METHODS else "event.orders:write"
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
return Order.objects.filter(
|
||||
event__organizer=self.request.organizer,
|
||||
@@ -338,8 +338,8 @@ class OrganizerOrderViewSet(OrderViewSetMixin, viewsets.ReadOnlyModelViewSet):
|
||||
|
||||
|
||||
class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
@@ -1078,8 +1078,8 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
||||
ordering = ('order__datetime', 'positionid')
|
||||
ordering_fields = ('order__code', 'order__datetime', 'positionid', 'attendee_name', 'order__status',)
|
||||
filterset_class = OrderPositionFilter
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
ordering_custom = {
|
||||
'attendee_name': {
|
||||
'_order': F('display_name').asc(nulls_first=True),
|
||||
@@ -1580,8 +1580,8 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
||||
class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = OrderPaymentSerializer
|
||||
queryset = OrderPayment.objects.none()
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
lookup_field = 'local_id'
|
||||
|
||||
def get_serializer_context(self):
|
||||
@@ -1757,8 +1757,8 @@ class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = OrderRefundSerializer
|
||||
queryset = OrderRefund.objects.none()
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
lookup_field = 'local_id'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -1915,13 +1915,18 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
ordering = ('nr',)
|
||||
ordering_fields = ('nr', 'date')
|
||||
filterset_class = InvoiceFilter
|
||||
permission = 'can_view_orders'
|
||||
lookup_url_kwarg = 'number'
|
||||
lookup_field = 'nr'
|
||||
write_permission = 'can_change_orders'
|
||||
|
||||
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):
|
||||
perm = "can_view_orders" if self.request.method in SAFE_METHODS else "can_change_orders"
|
||||
perm = "event.orders:read" if self.request.method in SAFE_METHODS else "event.orders:write"
|
||||
if getattr(self.request, 'event', None):
|
||||
qs = self.request.event.invoices
|
||||
elif isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
@@ -2062,8 +2067,8 @@ class RevokedSecretViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
ordering = ('-created',)
|
||||
ordering_fields = ('created', 'secret')
|
||||
filterset_class = RevokedSecretFilter
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return RevokedTicketSecret.objects.filter(event=self.request.event)
|
||||
@@ -2084,8 +2089,8 @@ class BlockedSecretViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
filter_backends = (DjangoFilterBackend, TotalOrderingFilter)
|
||||
ordering = ('-updated', '-pk')
|
||||
filterset_class = BlockedSecretFilter
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return BlockedTicketSecret.objects.filter(event=self.request.event)
|
||||
@@ -2120,7 +2125,7 @@ class TransactionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
ordering = ('datetime', 'pk')
|
||||
ordering_fields = ('datetime', 'created', 'id',)
|
||||
filterset_class = TransactionFilter
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_queryset(self):
|
||||
return Transaction.objects.filter(order__event=self.request.event).select_related("order")
|
||||
@@ -2137,11 +2142,11 @@ class OrganizerTransactionViewSet(TransactionViewSet):
|
||||
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
qs = qs.filter(
|
||||
order__event__in=self.request.auth.get_events_with_permission("can_view_orders"),
|
||||
order__event__in=self.request.auth.get_events_with_permission("event.orders:read"),
|
||||
)
|
||||
elif self.request.user.is_authenticated:
|
||||
qs = qs.filter(
|
||||
order__event__in=self.request.user.get_events_with_permission("can_view_orders", request=self.request)
|
||||
order__event__in=self.request.user.get_events_with_permission("event.orders:read", request=self.request)
|
||||
)
|
||||
else:
|
||||
raise PermissionDenied("Unknown authentication scheme")
|
||||
|
||||
@@ -70,7 +70,7 @@ class OrganizerViewSet(mixins.UpdateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
filter_backends = (TotalOrderingFilter,)
|
||||
ordering = ('slug',)
|
||||
ordering_fields = ('name', 'slug')
|
||||
write_permission = "can_change_organizer_settings"
|
||||
write_permission = "organizer.settings.general:write"
|
||||
|
||||
def get_queryset(self):
|
||||
if self.request.user.is_authenticated:
|
||||
@@ -154,8 +154,8 @@ class OrganizerViewSet(mixins.UpdateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
class SeatingPlanViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = SeatingPlanSerializer
|
||||
queryset = SeatingPlan.objects.none()
|
||||
permission = 'can_change_organizer_settings'
|
||||
write_permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
write_permission = 'organizer.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.organizer.seating_plans.order_by('name')
|
||||
@@ -221,8 +221,8 @@ with scopes_disabled():
|
||||
class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = GiftCardSerializer
|
||||
queryset = GiftCard.objects.none()
|
||||
permission = 'can_manage_gift_cards'
|
||||
write_permission = 'can_manage_gift_cards'
|
||||
permission = 'organizer.giftcards:write'
|
||||
write_permission = 'organizer.giftcards:write'
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = GiftCardFilter
|
||||
|
||||
@@ -323,8 +323,8 @@ class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
class GiftCardTransactionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = GiftCardTransactionSerializer
|
||||
queryset = GiftCardTransaction.objects.none()
|
||||
permission = 'can_manage_gift_cards'
|
||||
write_permission = 'can_manage_gift_cards'
|
||||
permission = 'organizer.giftcards:write'
|
||||
write_permission = 'organizer.giftcards:write'
|
||||
|
||||
@cached_property
|
||||
def giftcard(self):
|
||||
@@ -341,8 +341,8 @@ class GiftCardTransactionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class TeamViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = TeamSerializer
|
||||
queryset = Team.objects.none()
|
||||
permission = 'can_change_teams'
|
||||
write_permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
write_permission = 'organizer.teams:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.organizer.teams.order_by('pk')
|
||||
@@ -381,8 +381,8 @@ class TeamViewSet(viewsets.ModelViewSet):
|
||||
class TeamMemberViewSet(DestroyModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = TeamMemberSerializer
|
||||
queryset = User.objects.none()
|
||||
permission = 'can_change_teams'
|
||||
write_permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
write_permission = 'organizer.teams:write'
|
||||
|
||||
@cached_property
|
||||
def team(self):
|
||||
@@ -410,8 +410,8 @@ class TeamMemberViewSet(DestroyModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
class TeamInviteViewSet(CreateModelMixin, DestroyModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = TeamInviteSerializer
|
||||
queryset = TeamInvite.objects.none()
|
||||
permission = 'can_change_teams'
|
||||
write_permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
write_permission = 'organizer.teams:write'
|
||||
|
||||
@cached_property
|
||||
def team(self):
|
||||
@@ -447,8 +447,8 @@ class TeamInviteViewSet(CreateModelMixin, DestroyModelMixin, viewsets.ReadOnlyMo
|
||||
class TeamAPITokenViewSet(CreateModelMixin, DestroyModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = TeamAPITokenSerializer
|
||||
queryset = TeamAPIToken.objects.none()
|
||||
permission = 'can_change_teams'
|
||||
write_permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
write_permission = 'organizer.teams:write'
|
||||
|
||||
@cached_property
|
||||
def team(self):
|
||||
@@ -511,8 +511,8 @@ class DeviceViewSet(mixins.CreateModelMixin,
|
||||
GenericViewSet):
|
||||
serializer_class = DeviceSerializer
|
||||
queryset = Device.objects.none()
|
||||
permission = 'can_change_organizer_settings'
|
||||
write_permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
write_permission = 'organizer.settings.general:write'
|
||||
lookup_field = 'device_id'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -547,7 +547,7 @@ class DeviceViewSet(mixins.CreateModelMixin,
|
||||
|
||||
class OrganizerSettingsView(views.APIView):
|
||||
permission = None
|
||||
write_permission = 'can_change_organizer_settings'
|
||||
write_permission = 'organizer.settings.general:write'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
s = OrganizerSettingsSerializer(instance=request.organizer.settings, organizer=request.organizer, context={
|
||||
@@ -597,7 +597,7 @@ with scopes_disabled():
|
||||
class CustomerViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = CustomerSerializer
|
||||
queryset = Customer.objects.none()
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
lookup_field = 'identifier'
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = CustomerFilter
|
||||
@@ -657,7 +657,7 @@ class CustomerViewSet(viewsets.ModelViewSet):
|
||||
class MembershipTypeViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = MembershipTypeSerializer
|
||||
queryset = MembershipType.objects.none()
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.request.organizer.membership_types.all()
|
||||
@@ -714,7 +714,7 @@ with scopes_disabled():
|
||||
class MembershipViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = MembershipSerializer
|
||||
queryset = Membership.objects.none()
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = MembershipFilter
|
||||
|
||||
@@ -764,8 +764,8 @@ with scopes_disabled():
|
||||
class SalesChannelViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = SalesChannelSerializer
|
||||
queryset = SalesChannel.objects.none()
|
||||
permission = 'can_change_organizer_settings'
|
||||
write_permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
write_permission = 'organizer.settings.general:write'
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = SalesChannelFilter
|
||||
lookup_field = 'identifier'
|
||||
|
||||
@@ -204,7 +204,7 @@ class ShreddersMixin:
|
||||
|
||||
|
||||
class EventShreddersViewSet(ShreddersMixin, viewsets.ViewSet):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def get_serializer_kwargs(self):
|
||||
return {}
|
||||
|
||||
@@ -62,8 +62,8 @@ class VoucherViewSet(viewsets.ModelViewSet):
|
||||
ordering = ('id',)
|
||||
ordering_fields = ('id', 'code', 'max_usages', 'valid_until', 'value')
|
||||
filterset_class = VoucherFilter
|
||||
permission = 'can_view_vouchers'
|
||||
write_permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:read'
|
||||
write_permission = 'event.vouchers:write'
|
||||
|
||||
@scopes_disabled() # we have an event check here, and we can save some performance on subqueries
|
||||
def get_queryset(self):
|
||||
|
||||
@@ -51,8 +51,8 @@ class WaitingListViewSet(viewsets.ModelViewSet):
|
||||
ordering = ('created', 'pk',)
|
||||
ordering_fields = ('id', 'created', 'email', 'item')
|
||||
filterset_class = WaitingListFilter
|
||||
permission = 'can_view_orders'
|
||||
write_permission = 'can_change_orders'
|
||||
permission = 'event.orders:read'
|
||||
write_permission = 'event.orders:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.waitinglistentries.all()
|
||||
|
||||
@@ -35,8 +35,8 @@ class WebhookFilter(FilterSet):
|
||||
class WebHookViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = WebHookSerializer
|
||||
queryset = WebHook.objects.none()
|
||||
permission = 'can_change_organizer_settings'
|
||||
write_permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
write_permission = 'organizer.settings.general:write'
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = WebhookFilter
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ class HistoryPasswordValidator:
|
||||
).delete()
|
||||
|
||||
|
||||
def has_event_access_permission(request, permission='can_change_event_settings'):
|
||||
def has_event_access_permission(request, permission='event.settings.general:write'):
|
||||
return (
|
||||
request.user.is_authenticated and
|
||||
request.user.has_event_permission(request.organizer, request.event, permission, request=request)
|
||||
|
||||
@@ -184,7 +184,7 @@ class OrganizerLevelExportMixin:
|
||||
The permission level required to use this exporter. Only useful for organizer-level exports,
|
||||
not for event-level exports.
|
||||
"""
|
||||
return 'can_view_orders'
|
||||
return 'event.orders:read'
|
||||
|
||||
|
||||
class ListExporter(BaseExporter):
|
||||
|
||||
@@ -47,7 +47,7 @@ from ..signals import register_multievent_data_exporters
|
||||
class CustomerListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
identifier = 'customerlist'
|
||||
verbose_name = gettext_lazy('Customer accounts')
|
||||
organizer_required_permission = 'can_manage_customers'
|
||||
organizer_required_permission = 'organizer.customers:write'
|
||||
category = pgettext_lazy('export_category', 'Customer accounts')
|
||||
description = gettext_lazy('Download a spreadsheet of all currently registered customer accounts.')
|
||||
|
||||
|
||||
@@ -1200,7 +1200,7 @@ class QuotaListExporter(ListExporter):
|
||||
class GiftcardTransactionListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
identifier = 'giftcardtransactionlist'
|
||||
verbose_name = gettext_lazy('Gift card transactions')
|
||||
organizer_required_permission = 'can_manage_gift_cards'
|
||||
organizer_required_permission = 'organizer.giftcards:write'
|
||||
category = pgettext_lazy('export_category', 'Gift cards')
|
||||
description = gettext_lazy('Download a spreadsheet of all gift card transactions.')
|
||||
repeatable_read = False
|
||||
@@ -1307,7 +1307,7 @@ class GiftcardRedemptionListExporter(ListExporter):
|
||||
class GiftcardListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
identifier = 'giftcardlist'
|
||||
verbose_name = gettext_lazy('Gift cards')
|
||||
organizer_required_permission = 'can_manage_gift_cards'
|
||||
organizer_required_permission = 'organizer.giftcards:write'
|
||||
category = pgettext_lazy('export_category', 'Gift cards')
|
||||
description = gettext_lazy('Download a spreadsheet of all gift cards including their current value.')
|
||||
|
||||
|
||||
129
src/pretix/base/migrations/0297_pluggable_permissions.py
Normal file
129
src/pretix/base/migrations/0297_pluggable_permissions.py
Normal file
@@ -0,0 +1,129 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
from pretix.helpers.permission_migration import (
|
||||
OLD_TO_NEW_EVENT_MIGRATION, OLD_TO_NEW_ORGANIZER_MIGRATION,
|
||||
)
|
||||
|
||||
|
||||
def migrate_teams_forward(apps, schema_editor):
|
||||
Team = apps.get_model("pretixbase", "Team")
|
||||
|
||||
for team in Team.objects.iterator():
|
||||
if all(getattr(team, k) for k in OLD_TO_NEW_EVENT_MIGRATION.keys() if k != "can_checkin_orders"):
|
||||
team.all_event_permissions = True
|
||||
team.limit_event_permissions = {}
|
||||
else:
|
||||
team.all_event_permissions = False
|
||||
for k, v in OLD_TO_NEW_EVENT_MIGRATION.items():
|
||||
if getattr(team, k):
|
||||
team.limit_event_permissions.update({kk: True for kk in v})
|
||||
|
||||
if all(getattr(team, k) for k in OLD_TO_NEW_ORGANIZER_MIGRATION.keys()):
|
||||
team.all_organizer_permissions = True
|
||||
team.limit_organizer_permissions = {}
|
||||
else:
|
||||
team.all_organizer_permissions = False
|
||||
for k, v in OLD_TO_NEW_ORGANIZER_MIGRATION.items():
|
||||
if getattr(team, k):
|
||||
team.limit_organizer_permissions.update({kk: True for kk in v})
|
||||
|
||||
team.save(update_fields=[
|
||||
"all_event_permissions", "limit_event_permissions", "all_organizer_permissions", "limit_organizer_permissions"
|
||||
])
|
||||
|
||||
|
||||
def migrate_teams_backward(apps, schema_editor):
|
||||
Team = apps.get_model("pretixbase", "Team")
|
||||
|
||||
for team in Team.objects.iterator():
|
||||
for k, v in OLD_TO_NEW_EVENT_MIGRATION.items():
|
||||
setattr(team, k, team.all_event_permissions or all(team.limit_event_permissions.get(kk) for kk in v))
|
||||
for k, v in OLD_TO_NEW_ORGANIZER_MIGRATION.items():
|
||||
setattr(team, k, team.all_organizer_permissions or all(team.limit_organizer_permissions.get(kk) for kk in v))
|
||||
team.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pretixbase", "0296_invoice_invoice_from_state"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="team",
|
||||
name="all_event_permissions",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="team",
|
||||
name="all_organizer_permissions",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="team",
|
||||
name="limit_event_permissions",
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="team",
|
||||
name="limit_organizer_permissions",
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
migrations.RunPython(
|
||||
migrate_teams_forward,
|
||||
migrate_teams_backward,
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_change_event_settings",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_change_items",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_change_orders",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_change_organizer_settings",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_change_teams",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_change_vouchers",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_checkin_orders",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_create_events",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_manage_customers",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_manage_gift_cards",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_manage_reusable_media",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_view_orders",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="can_view_vouchers",
|
||||
),
|
||||
]
|
||||
@@ -472,7 +472,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
:return: set
|
||||
"""
|
||||
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:
|
||||
return set.union(*sets)
|
||||
else:
|
||||
@@ -486,7 +486,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
:return: set
|
||||
"""
|
||||
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:
|
||||
return set.union(*sets)
|
||||
else:
|
||||
@@ -501,7 +501,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
|
||||
:param organizer: The organizer of the event
|
||||
:param event: The event to check
|
||||
:param perm_name: The permission, e.g. ``can_change_teams``
|
||||
:param perm_name: The permission, e.g. ``event.orders:read``
|
||||
:param request: The current request (optional)
|
||||
:param session_key: The current session key (optional)
|
||||
:return: bool
|
||||
@@ -513,8 +513,8 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
if teams:
|
||||
self._teamcache['e{}'.format(event.pk)] = teams
|
||||
if isinstance(perm_name, (tuple, list)):
|
||||
return any([any(team.has_permission(p) for team in teams) for p in perm_name])
|
||||
if not perm_name or any([team.has_permission(perm_name) for team in teams]):
|
||||
return any([any(team.has_event_permission(p) for team in teams) for p in perm_name])
|
||||
if not perm_name or any([team.has_event_permission(perm_name) for team in teams]):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -524,7 +524,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
to the organizer ``organizer``.
|
||||
|
||||
:param organizer: The organizer to check
|
||||
:param perm_name: The permission, e.g. ``can_change_teams``
|
||||
:param perm_name: The permission, e.g. ``organizer.events:create``
|
||||
:param request: The current request (optional). Required to detect staff sessions properly.
|
||||
:return: bool
|
||||
"""
|
||||
@@ -533,8 +533,8 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
teams = self._get_teams_for_organizer(organizer)
|
||||
if teams:
|
||||
if isinstance(perm_name, (tuple, list)):
|
||||
return any([any(team.has_permission(p) for team in teams) for p in perm_name])
|
||||
if not perm_name or any([team.has_permission(perm_name) for team in teams]):
|
||||
return any([any(team.has_organizer_permission(p) for team in teams) for p in perm_name])
|
||||
if not perm_name or any([team.has_organizer_permission(perm_name) for team in teams]):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -565,14 +565,15 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
:return: Iterable of Events
|
||||
"""
|
||||
from .event import Event
|
||||
from .organizer import TeamQuerySet
|
||||
|
||||
if request and self.has_active_staff_session(request.session.session_key):
|
||||
return Event.objects.all()
|
||||
|
||||
if isinstance(permission, (tuple, list)):
|
||||
q = reduce(operator.or_, [Q(**{p: True}) for p in permission])
|
||||
q = reduce(operator.or_, [TeamQuerySet.event_permission_q(p) for p in permission])
|
||||
else:
|
||||
q = Q(**{permission: True})
|
||||
q = TeamQuerySet.event_permission_q(permission)
|
||||
|
||||
return Event.objects.filter(
|
||||
Q(organizer_id__in=self.teams.filter(q, all_events=True).values_list('organizer', flat=True))
|
||||
@@ -605,14 +606,13 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
:return: Iterable of Organizers
|
||||
"""
|
||||
from .event import Organizer
|
||||
from .organizer import TeamQuerySet
|
||||
|
||||
if request and self.has_active_staff_session(request.session.session_key):
|
||||
return Organizer.objects.all()
|
||||
|
||||
kwargs = {permission: True}
|
||||
|
||||
return Organizer.objects.filter(
|
||||
id__in=self.teams.filter(**kwargs).values_list('organizer', flat=True)
|
||||
id__in=self.teams.filter(TeamQuerySet.organizer_permission_q(permission)).values_list('organizer', flat=True)
|
||||
)
|
||||
|
||||
def has_active_staff_session(self, session_key=None):
|
||||
|
||||
@@ -189,13 +189,19 @@ class Device(LoggedModel):
|
||||
kwargs['update_fields'] = {'device_id'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def permission_set(self) -> set:
|
||||
def _event_permission_set(self) -> set:
|
||||
return {
|
||||
'can_view_orders',
|
||||
'can_change_orders',
|
||||
'can_view_vouchers',
|
||||
'can_manage_gift_cards',
|
||||
'can_manage_reusable_media',
|
||||
'event.orders:read',
|
||||
'event.orders:write',
|
||||
'event.vouchers:read',
|
||||
}
|
||||
|
||||
def _organizer_permission_set(self) -> set:
|
||||
return {
|
||||
'organizer.giftcards:read',
|
||||
'organizer.giftcards:write',
|
||||
'organizer.reusablemedia:read',
|
||||
'organizer.reusablemedia:write',
|
||||
}
|
||||
|
||||
def get_event_permission_set(self, organizer, event) -> set:
|
||||
@@ -209,7 +215,7 @@ class Device(LoggedModel):
|
||||
has_event_access = (self.all_events and organizer == self.organizer) or (
|
||||
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:
|
||||
"""
|
||||
@@ -218,7 +224,7 @@ class Device(LoggedModel):
|
||||
:param organizer: The organizer of the event
|
||||
: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:
|
||||
"""
|
||||
@@ -227,7 +233,7 @@ class Device(LoggedModel):
|
||||
|
||||
:param organizer: The organizer of the event
|
||||
:param event: The event to check
|
||||
:param perm_name: The permission, e.g. ``can_change_teams``
|
||||
:param perm_name: The permission, e.g. ``event.orders:read``
|
||||
:param request: This parameter is ignored and only defined for compatibility reasons.
|
||||
:return: bool
|
||||
"""
|
||||
@@ -235,8 +241,8 @@ class Device(LoggedModel):
|
||||
event in self.limit_events.all()
|
||||
)
|
||||
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 (not perm_name or perm_name in self.permission_set())
|
||||
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._event_permission_set())
|
||||
|
||||
def has_organizer_permission(self, organizer, perm_name=None, request=None):
|
||||
"""
|
||||
@@ -244,13 +250,13 @@ class Device(LoggedModel):
|
||||
to the organizer ``organizer``.
|
||||
|
||||
:param organizer: The organizer to check
|
||||
:param perm_name: The permission, e.g. ``can_change_teams``
|
||||
:param perm_name: The permission, e.g. ``organizer.events:create``
|
||||
:param request: This parameter is ignored and only defined for compatibility reasons.
|
||||
:return: bool
|
||||
"""
|
||||
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 (not perm_name or perm_name in self.permission_set())
|
||||
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._organizer_permission_set())
|
||||
|
||||
def get_events_with_any_permission(self):
|
||||
"""
|
||||
@@ -271,8 +277,8 @@ class Device(LoggedModel):
|
||||
:return: Iterable of Events
|
||||
"""
|
||||
if (
|
||||
isinstance(permission, (list, tuple)) and any(p in self.permission_set() for p in permission)
|
||||
) or (isinstance(permission, str) and permission in self.permission_set()):
|
||||
isinstance(permission, (list, tuple)) and any(p in self._event_permission_set() for p in permission)
|
||||
) or (isinstance(permission, str) and permission in self._event_permission_set()):
|
||||
return self.get_events_with_any_permission()
|
||||
else:
|
||||
return self.organizer.events.none()
|
||||
|
||||
@@ -1386,14 +1386,13 @@ class Event(EventMixin, LoggedModel):
|
||||
from .auth import User
|
||||
|
||||
if permission:
|
||||
kwargs = {permission: True}
|
||||
qs = Team.objects.with_event_permission(permission)
|
||||
else:
|
||||
kwargs = {}
|
||||
qs = Team.objects.all()
|
||||
|
||||
team_with_perm = Team.objects.filter(
|
||||
team_with_perm = qs.filter(
|
||||
members__pk=OuterRef('pk'),
|
||||
organizer=self.organizer,
|
||||
**kwargs
|
||||
).filter(
|
||||
Q(all_events=True) | Q(limit_events__pk=self.pk)
|
||||
)
|
||||
|
||||
@@ -31,9 +31,10 @@
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
import operator
|
||||
import string
|
||||
from datetime import date, datetime, time
|
||||
from functools import reduce
|
||||
|
||||
import pytz_deprecation_shim
|
||||
from django.conf import settings
|
||||
@@ -53,6 +54,10 @@ from i18nfield.strings import LazyI18nString
|
||||
from pretix.base.models.base import LoggedModel
|
||||
from pretix.base.validators import OrganizerSlugBanlistValidator
|
||||
|
||||
from ...helpers.permission_migration import (
|
||||
OLD_TO_NEW_EVENT_COMPAT, OLD_TO_NEW_ORGANIZER_COMPAT,
|
||||
LegacyPermissionProperty,
|
||||
)
|
||||
from ..settings import settings_hierarkey
|
||||
from .auth import User
|
||||
|
||||
@@ -309,6 +314,32 @@ def generate_api_token():
|
||||
return get_random_string(length=64, allowed_chars=string.ascii_lowercase + string.digits)
|
||||
|
||||
|
||||
class TeamQuerySet(models.QuerySet):
|
||||
@classmethod
|
||||
def event_permission_q(cls, perm_name):
|
||||
if perm_name.startswith('can_') and perm_name in OLD_TO_NEW_EVENT_COMPAT: # legacy
|
||||
return reduce(operator.and_, [cls.event_permission_q(p) for p in OLD_TO_NEW_EVENT_COMPAT[perm_name]])
|
||||
return (
|
||||
Q(all_event_permissions=True) |
|
||||
Q(**{f'limit_event_permissions__{perm_name}': True})
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def organizer_permission_q(cls, perm_name):
|
||||
if perm_name.startswith('can_') and perm_name in OLD_TO_NEW_ORGANIZER_COMPAT: # legacy
|
||||
return reduce(operator.and_, [cls.organizer_permission_q(p) for p in OLD_TO_NEW_ORGANIZER_COMPAT[perm_name]])
|
||||
return (
|
||||
Q(all_organizer_permissions=True) |
|
||||
Q(**{f'limit_organizer_permissions__{perm_name}': True})
|
||||
)
|
||||
|
||||
def with_event_permission(self, perm_name):
|
||||
return self.filter(self.event_permission_q(perm_name))
|
||||
|
||||
def with_organizer_permission(self, perm_name):
|
||||
return self.filter(self.organizer_permission_q(perm_name))
|
||||
|
||||
|
||||
class Team(LoggedModel):
|
||||
"""
|
||||
A team is a collection of people given certain access rights to one or more events of an organizer.
|
||||
@@ -321,36 +352,10 @@ class Team(LoggedModel):
|
||||
:param all_events: Whether this team has access to all events of this organizer
|
||||
:type all_events: bool
|
||||
:param limit_events: A set of events this team has access to. Irrelevant if ``all_events`` is ``True``.
|
||||
:param can_create_events: Whether or not the members can create new events with this organizer account.
|
||||
:type can_create_events: bool
|
||||
:param can_change_teams: If ``True``, the members can change the teams of this organizer account.
|
||||
:type can_change_teams: bool
|
||||
:param can_manage_customers: If ``True``, the members can view and change organizer-level customer accounts.
|
||||
:type can_manage_customers: bool
|
||||
:param can_manage_reusable_media: If ``True``, the members can view and change organizer-level reusable media.
|
||||
:type can_manage_reusable_media: bool
|
||||
:param can_change_organizer_settings: If ``True``, the members can change the settings of this organizer account.
|
||||
:type can_change_organizer_settings: bool
|
||||
:param can_change_event_settings: If ``True``, the members can change the settings of the associated events.
|
||||
:type can_change_event_settings: bool
|
||||
:param can_change_items: If ``True``, the members can change and add items and related objects for the associated events.
|
||||
:type can_change_items: bool
|
||||
:param can_view_orders: If ``True``, the members can inspect details of all orders of the associated events.
|
||||
:type can_view_orders: bool
|
||||
:param can_change_orders: If ``True``, the members can change details of orders of the associated events.
|
||||
:type can_change_orders: bool
|
||||
:param can_checkin_orders: If ``True``, the members can perform check-in related actions.
|
||||
:type can_checkin_orders: bool
|
||||
:param can_view_vouchers: If ``True``, the members can inspect details of all vouchers of the associated events.
|
||||
:type can_view_vouchers: bool
|
||||
:param can_change_vouchers: If ``True``, the members can change and create vouchers for the associated events.
|
||||
:type can_change_vouchers: bool
|
||||
"""
|
||||
organizer = models.ForeignKey(Organizer, related_name="teams", on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=190, verbose_name=_("Team name"))
|
||||
members = models.ManyToManyField(User, related_name="teams", verbose_name=_("Team members"))
|
||||
all_events = models.BooleanField(default=False, verbose_name=_("All events (including newly created ones)"))
|
||||
limit_events = models.ManyToManyField('Event', verbose_name=_("Limit to events"), blank=True)
|
||||
require_2fa = models.BooleanField(
|
||||
default=False, verbose_name=_("Require all members of this team to use two-factor authentication"),
|
||||
help_text=_("If you turn this on, all members of the team will be required to either set up two-factor "
|
||||
@@ -358,62 +363,33 @@ class Team(LoggedModel):
|
||||
"all users.")
|
||||
)
|
||||
|
||||
can_create_events = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can create events"),
|
||||
)
|
||||
can_change_teams = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can change teams and permissions"),
|
||||
)
|
||||
can_change_organizer_settings = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can change organizer settings"),
|
||||
help_text=_('Someone with this setting can get access to most data of all of your events, i.e. via privacy '
|
||||
'reports, so be careful who you add to this team!')
|
||||
)
|
||||
can_manage_customers = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can manage customer accounts")
|
||||
)
|
||||
can_manage_reusable_media = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can manage reusable media")
|
||||
)
|
||||
can_manage_gift_cards = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can manage gift cards")
|
||||
)
|
||||
can_change_event_settings = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can change event settings")
|
||||
)
|
||||
can_change_items = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can change product settings")
|
||||
)
|
||||
can_view_orders = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can view orders")
|
||||
)
|
||||
can_change_orders = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can change orders")
|
||||
)
|
||||
can_checkin_orders = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can perform check-ins"),
|
||||
help_text=_('This includes searching for attendees, which can be used to obtain personal information about '
|
||||
'attendees. Users with "can change orders" can also perform check-ins.')
|
||||
)
|
||||
can_view_vouchers = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can view vouchers")
|
||||
)
|
||||
can_change_vouchers = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("Can change vouchers")
|
||||
)
|
||||
# Scope
|
||||
all_events = models.BooleanField(default=False, verbose_name=_("All events (including newly created ones)"))
|
||||
limit_events = models.ManyToManyField('Event', verbose_name=_("Limit to events"), blank=True)
|
||||
|
||||
# Permissions
|
||||
# We store them as {key: True} instead of [key] because otherwise not all lookups we need are supported on SQLite
|
||||
all_event_permissions = models.BooleanField(default=False, verbose_name=_("All event permissions"))
|
||||
limit_event_permissions = models.JSONField(default=dict, verbose_name=_("Event permissions"))
|
||||
all_organizer_permissions = models.BooleanField(default=False, verbose_name=_("All organizer permissions"))
|
||||
limit_organizer_permissions = models.JSONField(default=dict, verbose_name=_("Organizer permissions"))
|
||||
|
||||
# Legacy lookups for plugin compatibility
|
||||
can_change_event_settings = LegacyPermissionProperty()
|
||||
can_change_items = LegacyPermissionProperty()
|
||||
can_view_orders = LegacyPermissionProperty()
|
||||
can_change_orders = LegacyPermissionProperty()
|
||||
can_checkin_orders = LegacyPermissionProperty()
|
||||
can_view_vouchers = LegacyPermissionProperty()
|
||||
can_change_vouchers = LegacyPermissionProperty()
|
||||
can_create_events = LegacyPermissionProperty()
|
||||
can_change_organizer_settings = LegacyPermissionProperty()
|
||||
can_change_teams = LegacyPermissionProperty()
|
||||
can_manage_gift_cards = LegacyPermissionProperty()
|
||||
can_manage_customers = LegacyPermissionProperty()
|
||||
can_manage_reusable_media = LegacyPermissionProperty()
|
||||
|
||||
objects = TeamQuerySet.as_manager()
|
||||
|
||||
def __str__(self) -> str:
|
||||
return _("%(name)s on %(object)s") % {
|
||||
@@ -421,21 +397,51 @@ class Team(LoggedModel):
|
||||
'object': str(self.organizer),
|
||||
}
|
||||
|
||||
def permission_set(self) -> set:
|
||||
attribs = dir(self)
|
||||
return {
|
||||
a for a in attribs if a.startswith('can_') and self.has_permission(a)
|
||||
}
|
||||
def event_permission_set(self, include_legacy=True) -> set:
|
||||
from ..permissions import get_all_event_permissions
|
||||
|
||||
result = set()
|
||||
for permission in get_all_event_permissions().keys():
|
||||
if self.all_event_permissions or self.limit_event_permissions.get(permission):
|
||||
result.add(permission)
|
||||
|
||||
if include_legacy:
|
||||
# Add legacy permissions as well for plugin compatibility
|
||||
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):
|
||||
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():
|
||||
if self.all_organizer_permissions or all(self.limit_organizer_permissions.get(kk) for kk in v):
|
||||
result.add(k)
|
||||
|
||||
return result
|
||||
|
||||
@property
|
||||
def can_change_settings(self): # Legacy compatiblilty
|
||||
def can_change_settings(self): # Legacy compatibility
|
||||
return self.can_change_event_settings
|
||||
|
||||
def has_permission(self, perm_name):
|
||||
try:
|
||||
def has_event_permission(self, perm_name):
|
||||
if perm_name.startswith('can_') and hasattr(self, perm_name): # legacy
|
||||
return getattr(self, perm_name)
|
||||
except AttributeError:
|
||||
raise ValueError('Invalid required permission: %s' % perm_name)
|
||||
return self.all_event_permissions or self.limit_event_permissions.get(perm_name, False)
|
||||
|
||||
def has_organizer_permission(self, perm_name):
|
||||
if perm_name.startswith('can_') and hasattr(self, perm_name): # legacy
|
||||
return getattr(self, perm_name)
|
||||
return self.all_organizer_permissions or self.limit_organizer_permissions.get(perm_name, False)
|
||||
|
||||
def permission_for_event(self, event):
|
||||
if self.all_events:
|
||||
@@ -447,6 +453,19 @@ class Team(LoggedModel):
|
||||
def active_tokens(self):
|
||||
return self.tokens.filter(active=True)
|
||||
|
||||
def save(self, **kwargs):
|
||||
if not isinstance(self.limit_event_permissions, dict):
|
||||
raise TypeError("Permissions must be a dictionary")
|
||||
if not isinstance(self.limit_organizer_permissions, dict):
|
||||
raise TypeError("Permissions must be a dictionary")
|
||||
for k in self.limit_event_permissions.values():
|
||||
if k is not True:
|
||||
raise TypeError("Permissions must only contain True values")
|
||||
for k in self.limit_organizer_permissions.values():
|
||||
if k is not True:
|
||||
raise TypeError("Permissions must only contain True values")
|
||||
return super().save(**kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Team")
|
||||
verbose_name_plural = _("Teams")
|
||||
@@ -503,7 +522,7 @@ class TeamAPIToken(models.Model):
|
||||
has_event_access = (self.team.all_events and organizer == self.team.organizer) or (
|
||||
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:
|
||||
"""
|
||||
@@ -512,7 +531,7 @@ class TeamAPIToken(models.Model):
|
||||
:param organizer: The organizer of the event
|
||||
: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:
|
||||
"""
|
||||
@@ -521,7 +540,7 @@ class TeamAPIToken(models.Model):
|
||||
|
||||
:param organizer: The organizer of the event
|
||||
:param event: The event to check
|
||||
:param perm_name: The permission, e.g. ``can_change_teams``
|
||||
:param perm_name: The permission, e.g. ``event.orders:read``
|
||||
:param request: This parameter is ignored and only defined for compatibility reasons.
|
||||
:return: bool
|
||||
"""
|
||||
@@ -529,8 +548,8 @@ class TeamAPIToken(models.Model):
|
||||
event in self.team.limit_events.all()
|
||||
)
|
||||
if isinstance(perm_name, (tuple, list)):
|
||||
return has_event_access and any(self.team.has_permission(p) for p in perm_name)
|
||||
return has_event_access and (not perm_name or self.team.has_permission(perm_name))
|
||||
return has_event_access and any(self.team.has_event_permission(p) for p in perm_name)
|
||||
return has_event_access and (not perm_name or self.team.has_event_permission(perm_name))
|
||||
|
||||
def has_organizer_permission(self, organizer, perm_name=None, request=None):
|
||||
"""
|
||||
@@ -538,13 +557,13 @@ class TeamAPIToken(models.Model):
|
||||
to the organizer ``organizer``.
|
||||
|
||||
:param organizer: The organizer to check
|
||||
:param perm_name: The permission, e.g. ``can_change_teams``
|
||||
:param perm_name: The permission, e.g. ``organizer:events.create``
|
||||
:param request: This parameter is ignored and only defined for compatibility reasons.
|
||||
:return: bool
|
||||
"""
|
||||
if isinstance(perm_name, (tuple, list)):
|
||||
return organizer == self.team.organizer and any(self.team.has_permission(p) for p in perm_name)
|
||||
return organizer == self.team.organizer and (not perm_name or self.team.has_permission(perm_name))
|
||||
return organizer == self.team.organizer and any(self.team.has_organizer_permission(p) for p in perm_name)
|
||||
return organizer == self.team.organizer and (not perm_name or self.team.has_organizer_permission(perm_name))
|
||||
|
||||
def get_events_with_any_permission(self):
|
||||
"""
|
||||
@@ -565,8 +584,8 @@ class TeamAPIToken(models.Model):
|
||||
:return: Iterable of Events
|
||||
"""
|
||||
if (
|
||||
isinstance(permission, (list, tuple)) and any(getattr(self.team, p, False) for p in permission)
|
||||
) or (isinstance(permission, str) and getattr(self.team, permission, False)):
|
||||
isinstance(permission, (list, tuple)) and any(self.team.has_event_permission(p) for p in permission)
|
||||
) or (isinstance(permission, str) and self.team.has_event_permission(permission)):
|
||||
return self.get_events_with_any_permission()
|
||||
else:
|
||||
return self.team.organizer.events.none()
|
||||
|
||||
@@ -151,7 +151,7 @@ def get_all_notification_types(event=None):
|
||||
|
||||
|
||||
class ParametrizedOrderNotificationType(NotificationType):
|
||||
required_permission = "can_view_orders"
|
||||
required_permission = "event.orders:read"
|
||||
|
||||
def __init__(self, event, action_type, verbose_name, title):
|
||||
self._action_type = action_type
|
||||
|
||||
113
src/pretix/base/permissions.py
Normal file
113
src/pretix/base/permissions.py
Normal file
@@ -0,0 +1,113 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-today pretix GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import logging
|
||||
from collections import OrderedDict, namedtuple
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
from pretix.base.signals import (
|
||||
register_event_permissions, register_organizer_permissions,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_ALL_EVENT_PERMISSIONS = None
|
||||
_ALL_ORGANIZER_PERMISSIONS = None
|
||||
|
||||
|
||||
Permission = namedtuple('Permission', ('name', 'label', 'plugin_name', 'help_text'))
|
||||
|
||||
|
||||
def get_all_event_permissions():
|
||||
global _ALL_EVENT_PERMISSIONS
|
||||
|
||||
if _ALL_EVENT_PERMISSIONS:
|
||||
return _ALL_EVENT_PERMISSIONS
|
||||
|
||||
types = OrderedDict()
|
||||
for recv, ret in register_event_permissions.send(None):
|
||||
if isinstance(ret, (list, tuple)):
|
||||
for r in ret:
|
||||
types[r.name] = r
|
||||
else:
|
||||
types[ret.name] = ret
|
||||
_ALL_EVENT_PERMISSIONS = types
|
||||
return types
|
||||
|
||||
|
||||
def get_all_organizer_permissions():
|
||||
global _ALL_ORGANIZER_PERMISSIONS
|
||||
|
||||
if _ALL_ORGANIZER_PERMISSIONS:
|
||||
return _ALL_ORGANIZER_PERMISSIONS
|
||||
|
||||
types = OrderedDict()
|
||||
for recv, ret in register_organizer_permissions.send(None):
|
||||
if isinstance(ret, (list, tuple)):
|
||||
for r in ret:
|
||||
types[r.name] = r
|
||||
else:
|
||||
types[ret.name] = ret
|
||||
_ALL_ORGANIZER_PERMISSIONS = types
|
||||
return types
|
||||
|
||||
|
||||
@receiver(register_event_permissions, dispatch_uid="base_register_default_event_permissions")
|
||||
def register_default_event_permissions(sender, **kwargs):
|
||||
return [
|
||||
Permission("event.settings.general:write", _("Change general settings"), None,
|
||||
_("This includes access to all settings not listed explicitly below, including plugin settings.")),
|
||||
Permission("event.settings.payment:write", _("Change payment settings"), None, None),
|
||||
Permission("event.settings.plugins:write", _("Change plugin settings"), None, None),
|
||||
Permission("event.settings.email.sender:write", _("Change email sending settings"), None, None),
|
||||
Permission("event.settings.tax:write", _("Change tax rules"), None, None),
|
||||
Permission("event.settings.invoicing:write", _("Change invoicing settings"), None, None),
|
||||
Permission("event.subevents:write", pgettext_lazy("subevent", "Change event series dates"), None, None),
|
||||
Permission("event.items:write", _("Change products and quotas"), None, None), # and questions but that might change?
|
||||
Permission("event.orders:read", _("View orders"), None, None),
|
||||
Permission("event.orders:write", _("Change orders"), None, _("This includes the ability to cancel and refund individual orders.")),
|
||||
Permission("event.orders:checkin", _("Check-in orders"), None, None),
|
||||
Permission("event.vouchers:read", _("View vouchers"), None, None),
|
||||
Permission("event.vouchers:write", _("Change vouchers"), None, None),
|
||||
Permission("event:cancel", pgettext_lazy("subevent", " entire event or date"), None, None),
|
||||
]
|
||||
|
||||
|
||||
@receiver(register_organizer_permissions, dispatch_uid="base_register_default_organizer_permissions")
|
||||
def register_default_organizer_permissions(sender, **kwargs):
|
||||
return [
|
||||
Permission("organizer.events:create", _("Create events"), None, None),
|
||||
Permission("organizer.settings.general:write", _("Change settings"), None,
|
||||
_("This includes access to all organizer-level functionality not listed explicitly below, including plugin settings.")),
|
||||
Permission("organizer.teams:write", _("Change teams"), None,
|
||||
_("This includes the ability to give someone (including oneself) additional permissions.")),
|
||||
Permission("organizer.giftcards:read", _("View gift cards"), None, None),
|
||||
Permission("organizer.giftcards:write", _("Change gift cards"), None, None),
|
||||
Permission("organizer.customers:read", _("View customer accounts"), None, None),
|
||||
Permission("organizer.customers:write", _("Change customer accounts"), None, None),
|
||||
Permission("organizer.reusablemedia:read", _("View reusable media"), None, None),
|
||||
Permission("organizer.reusablemedia:write", _("Change reusable media"), None, None),
|
||||
Permission("organizer.devices:read", _("View devices"), None, None),
|
||||
Permission("organizer.devices:write", _("Change devices"), None,
|
||||
_("This includes the ability to give access to events and data oneself does not have access to.")),
|
||||
]
|
||||
@@ -106,7 +106,7 @@ def multiexport(self, organizer: Organizer, user: User, device: int, token: int,
|
||||
device = Device.objects.get(pk=device)
|
||||
if token:
|
||||
device = TeamAPIToken.objects.get(pk=token)
|
||||
allowed_events = (device or token or user).get_events_with_permission('can_view_orders')
|
||||
allowed_events = (device or token or user).get_events_with_permission('event.orders:read')
|
||||
if user and staff_session:
|
||||
allowed_events = organizer.events.all()
|
||||
|
||||
@@ -291,7 +291,7 @@ def _run_scheduled_export(schedule, context: Union[Event, Organizer], exporter,
|
||||
def scheduled_organizer_export(self, organizer: Organizer, schedule: int) -> None:
|
||||
schedule = organizer.scheduled_exports.get(pk=schedule)
|
||||
|
||||
allowed_events = schedule.owner.get_events_with_permission('can_view_orders')
|
||||
allowed_events = schedule.owner.get_events_with_permission('event.orders:read')
|
||||
if schedule.export_form_data.get('events') is not None and not schedule.export_form_data.get('all_events'):
|
||||
if isinstance(schedule.export_form_data['events'][0], str):
|
||||
events = allowed_events.filter(slug__in=schedule.export_form_data.get('events'), organizer=organizer)
|
||||
@@ -346,7 +346,7 @@ def scheduled_event_export(self, event: Event, schedule: int) -> None:
|
||||
exporter = ex
|
||||
break
|
||||
|
||||
has_permission = schedule.owner.is_active and schedule.owner.has_event_permission(event.organizer, event, 'can_view_orders')
|
||||
has_permission = schedule.owner.is_active and schedule.owner.has_event_permission(event.organizer, event, 'event.orders:read')
|
||||
|
||||
_run_scheduled_export(
|
||||
schedule,
|
||||
|
||||
@@ -561,6 +561,18 @@ however for this signal, the ``sender`` **may also be None** to allow creating t
|
||||
notification settings!
|
||||
"""
|
||||
|
||||
register_event_permissions = GlobalSignal()
|
||||
"""
|
||||
This signal is sent out to get all known permissions. Receivers should return an
|
||||
instance of pretix.base.permissions.Permission or a list of such instances.
|
||||
"""
|
||||
|
||||
register_organizer_permissions = GlobalSignal()
|
||||
"""
|
||||
This signal is sent out to get all known permissions. Receivers should return an
|
||||
instance of pretix.base.permissions.Permission or a list of such instances.
|
||||
"""
|
||||
|
||||
notification = EventPluginSignal()
|
||||
"""
|
||||
Arguments: ``logentry_id``, ``notification_type``
|
||||
|
||||
@@ -102,7 +102,7 @@ def _default_context(request):
|
||||
complain_testmode_orders = request.event.orders.filter(testmode=True).exists()
|
||||
request.event.cache.set('complain_testmode_orders', complain_testmode_orders, 30)
|
||||
ctx['complain_testmode_orders'] = complain_testmode_orders and request.user.has_event_permission(
|
||||
request.organizer, request.event, 'can_view_orders', request=request
|
||||
request.organizer, request.event, 'event.orders:read', request=request
|
||||
)
|
||||
else:
|
||||
ctx['complain_testmode_orders'] = False
|
||||
|
||||
@@ -62,6 +62,7 @@ from pretix.base.forms import (
|
||||
)
|
||||
from pretix.base.models import Event, Organizer, TaxRule, Team
|
||||
from pretix.base.models.event import EventFooterLink, EventMetaValue, SubEvent
|
||||
from pretix.base.models.organizer import TeamQuerySet
|
||||
from pretix.base.models.tax import TAX_CODE_LISTS
|
||||
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
|
||||
from pretix.base.services.placeholders import FormPlaceholderMixin
|
||||
@@ -104,7 +105,7 @@ class EventWizardFoundationForm(forms.Form):
|
||||
qs = Organizer.objects.all()
|
||||
if not self.user.has_active_staff_session(self.session.session_key):
|
||||
qs = qs.filter(
|
||||
id__in=self.user.teams.filter(can_create_events=True).values_list('organizer', flat=True)
|
||||
id__in=self.user.teams.filter(TeamQuerySet.organizer_permission_q("organizer.events:create")).values_list('organizer', flat=True)
|
||||
)
|
||||
self.fields['organizer'] = forms.ModelChoiceField(
|
||||
label=_("Organizer"),
|
||||
@@ -262,8 +263,12 @@ class EventWizardBasicsForm(I18nModelForm):
|
||||
@staticmethod
|
||||
def has_control_rights(user, organizer, session):
|
||||
return user.teams.filter(
|
||||
organizer=organizer, all_events=True, can_change_event_settings=True, can_change_items=True,
|
||||
can_change_orders=True, can_change_vouchers=True
|
||||
TeamQuerySet.event_permission_q("event.items:write"),
|
||||
TeamQuerySet.event_permission_q("event.orders:write"),
|
||||
TeamQuerySet.event_permission_q("event.vouchers:write"),
|
||||
TeamQuerySet.event_permission_q("event.settings.general:write"),
|
||||
organizer=organizer,
|
||||
all_events=True,
|
||||
).exists() or user.has_active_staff_session(session.session_key)
|
||||
|
||||
|
||||
@@ -294,9 +299,14 @@ class EventWizardCopyForm(forms.Form):
|
||||
return Event.objects.all()
|
||||
return Event.objects.filter(
|
||||
Q(organizer_id__in=user.teams.filter(
|
||||
all_events=True, can_change_event_settings=True, can_change_items=True
|
||||
# TODO: review these!
|
||||
# Restrict cross-organizer copying further than same-organizer copying?
|
||||
TeamQuerySet.event_permission_q("event.settings.general:write"),
|
||||
TeamQuerySet.event_permission_q("event.items:write"),
|
||||
all_events=True,
|
||||
).values_list('organizer', flat=True)) | Q(id__in=user.teams.filter(
|
||||
can_change_event_settings=True, can_change_items=True
|
||||
TeamQuerySet.event_permission_q("event.settings.general:write"),
|
||||
TeamQuerySet.event_permission_q("event.items:write"),
|
||||
).values_list('limit_events__id', flat=True))
|
||||
)
|
||||
|
||||
|
||||
@@ -1110,7 +1110,7 @@ class OrderPaymentSearchFilterForm(forms.Form):
|
||||
self.fields['organizer'].queryset = Organizer.objects.filter(
|
||||
pk__in=self.request.user.teams.values_list('organizer', flat=True)
|
||||
)
|
||||
self.fields['event'].queryset = self.request.user.get_events_with_permission('can_view_orders')
|
||||
self.fields['event'].queryset = self.request.user.get_events_with_permission('event.orders:read')
|
||||
|
||||
self.fields['provider'].choices += get_all_payment_providers()
|
||||
|
||||
|
||||
@@ -75,7 +75,10 @@ from pretix.base.models import (
|
||||
ReusableMedium, SalesChannel, Team,
|
||||
)
|
||||
from pretix.base.models.customers import CustomerSSOClient, CustomerSSOProvider
|
||||
from pretix.base.models.organizer import OrganizerFooterLink
|
||||
from pretix.base.models.organizer import OrganizerFooterLink, TeamQuerySet
|
||||
from pretix.base.permissions import (
|
||||
get_all_event_permissions, get_all_organizer_permissions,
|
||||
)
|
||||
from pretix.base.settings import (
|
||||
PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS, validate_organizer_settings,
|
||||
)
|
||||
@@ -297,6 +300,18 @@ class MembershipTypeForm(I18nModelForm):
|
||||
fields = ['name', 'transferable', 'allow_parallel_usage', 'max_usages']
|
||||
|
||||
|
||||
class PermissionMultipleChoiceField(forms.MultipleChoiceField):
|
||||
def to_python(self, value):
|
||||
return {
|
||||
k: True for k in super().to_python(value) if k
|
||||
}
|
||||
|
||||
def prepare_value(self, value):
|
||||
if isinstance(value, dict):
|
||||
return [k for k, v in value.items() if v is True]
|
||||
return super().prepare_value(value)
|
||||
|
||||
|
||||
class TeamForm(forms.ModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -305,16 +320,50 @@ class TeamForm(forms.ModelForm):
|
||||
self.fields['limit_events'].queryset = organizer.events.all().order_by(
|
||||
'-has_subevents', '-date_from'
|
||||
)
|
||||
self.fields['limit_event_permissions'] = PermissionMultipleChoiceField(
|
||||
label=self.fields['limit_event_permissions'].label,
|
||||
choices=[
|
||||
(
|
||||
p.name,
|
||||
format_html(
|
||||
'{} <span class="fa fa-info-circle text-muted" data-toggle="tooltip" title="{}"></span> (<code>{}</code>)',
|
||||
p.label, p.help_text, p.name
|
||||
) if p.help_text
|
||||
else format_html('{} (<code>{}</code>)', p.label, p.name)
|
||||
)
|
||||
for p in get_all_event_permissions().values()
|
||||
],
|
||||
widget=forms.CheckboxSelectMultiple(attrs={
|
||||
'data-inverse-dependency': '#id_all_event_permissions',
|
||||
'class': 'scrolling-multiple-choice scrolling-multiple-choice-large',
|
||||
}),
|
||||
required=False,
|
||||
)
|
||||
self.fields['limit_organizer_permissions'] = PermissionMultipleChoiceField(
|
||||
label=self.fields['limit_organizer_permissions'].label,
|
||||
choices=[
|
||||
(
|
||||
p.name,
|
||||
format_html(
|
||||
'{} <span class="fa fa-info-circle text-muted" data-toggle="tooltip" title="{}"></span> (<code>{}</code>)',
|
||||
p.label, p.help_text, p.name
|
||||
) if p.help_text
|
||||
else format_html('{} (<code>{}</code>)', p.label, p.name)
|
||||
)
|
||||
for p in get_all_organizer_permissions().values()
|
||||
],
|
||||
widget=forms.CheckboxSelectMultiple(attrs={
|
||||
'data-inverse-dependency': '#id_all_organizer_permissions',
|
||||
'class': 'scrolling-multiple-choice scrolling-multiple-choice-large',
|
||||
}),
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Team
|
||||
fields = ['name', 'require_2fa', 'all_events', 'limit_events', 'can_create_events',
|
||||
'can_change_teams', 'can_change_organizer_settings',
|
||||
'can_manage_gift_cards', 'can_manage_customers',
|
||||
'can_manage_reusable_media',
|
||||
'can_change_event_settings', 'can_change_items',
|
||||
'can_view_orders', 'can_change_orders', 'can_checkin_orders',
|
||||
'can_view_vouchers', 'can_change_vouchers']
|
||||
fields = ['name', 'require_2fa', 'all_events', 'limit_events',
|
||||
'all_event_permissions', 'limit_event_permissions',
|
||||
'all_organizer_permissions', 'limit_organizer_permissions']
|
||||
widgets = {
|
||||
'limit_events': forms.CheckboxSelectMultiple(attrs={
|
||||
'data-inverse-dependency': '#id_all_events',
|
||||
@@ -327,9 +376,10 @@ class TeamForm(forms.ModelForm):
|
||||
|
||||
def clean(self):
|
||||
data = super().clean()
|
||||
if self.instance.pk and not data['can_change_teams']:
|
||||
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(
|
||||
can_change_teams=True, members__isnull=False
|
||||
TeamQuerySet.organizer_permission_q("organizer.teams:write"),
|
||||
members__isnull=False
|
||||
).exists():
|
||||
raise ValidationError(_('The changes could not be saved because there would be no remaining team with '
|
||||
'the permission to change teams and permissions.'))
|
||||
|
||||
@@ -43,7 +43,7 @@ def get_event_navigation(request: HttpRequest):
|
||||
'icon': 'dashboard',
|
||||
}
|
||||
]
|
||||
if 'can_change_event_settings' in request.eventpermset:
|
||||
if 'event.settings.general:write' in request.eventpermset:
|
||||
event_settings = [
|
||||
{
|
||||
'label': _('General'),
|
||||
@@ -133,7 +133,7 @@ def get_event_navigation(request: HttpRequest):
|
||||
'children': event_settings
|
||||
})
|
||||
|
||||
if 'can_change_items' in request.eventpermset:
|
||||
if 'event.items:write' in request.eventpermset:
|
||||
nav.append({
|
||||
'label': _('Products'),
|
||||
'url': reverse('control:event.items', kwargs={
|
||||
@@ -187,7 +187,7 @@ def get_event_navigation(request: HttpRequest):
|
||||
]
|
||||
})
|
||||
|
||||
if 'can_change_event_settings' in request.eventpermset:
|
||||
if 'event.settings.general:write' in request.eventpermset:
|
||||
if request.event.has_subevents:
|
||||
nav.append({
|
||||
'label': pgettext_lazy('subevent', 'Dates'),
|
||||
@@ -199,7 +199,7 @@ def get_event_navigation(request: HttpRequest):
|
||||
'icon': 'calendar',
|
||||
})
|
||||
|
||||
if 'can_view_orders' in request.eventpermset:
|
||||
if 'event.orders:read' in request.eventpermset:
|
||||
children = [
|
||||
{
|
||||
'label': _('All orders'),
|
||||
@@ -242,7 +242,7 @@ def get_event_navigation(request: HttpRequest):
|
||||
'active': 'event.orders.waitinglist' in url.url_name,
|
||||
},
|
||||
]
|
||||
if 'can_change_orders' in request.eventpermset:
|
||||
if 'event.orders:write' in request.eventpermset:
|
||||
children.append({
|
||||
'label': _('Import'),
|
||||
'url': reverse('control:event.orders.import', kwargs={
|
||||
@@ -262,7 +262,7 @@ def get_event_navigation(request: HttpRequest):
|
||||
'children': children
|
||||
})
|
||||
|
||||
if 'can_view_vouchers' in request.eventpermset:
|
||||
if 'event.vouchers:read' in request.eventpermset:
|
||||
nav.append({
|
||||
'label': _('Vouchers'),
|
||||
'url': reverse('control:event.vouchers', kwargs={
|
||||
@@ -291,7 +291,7 @@ def get_event_navigation(request: HttpRequest):
|
||||
]
|
||||
})
|
||||
|
||||
if 'can_view_orders' in request.eventpermset:
|
||||
if 'event.orders:read' in request.eventpermset:
|
||||
nav.append({
|
||||
'label': pgettext_lazy('navigation', 'Check-in'),
|
||||
'url': reverse('control:event.orders.checkinlists', kwargs={
|
||||
@@ -480,7 +480,7 @@ def get_organizer_navigation(request):
|
||||
'icon': 'calendar',
|
||||
},
|
||||
]
|
||||
if 'can_change_organizer_settings' in request.orgapermset:
|
||||
if 'organizer.settings.general:write' in request.orgapermset:
|
||||
nav.append({
|
||||
'label': _('Settings'),
|
||||
'url': reverse('control:organizer.edit', kwargs={
|
||||
@@ -534,7 +534,7 @@ def get_organizer_navigation(request):
|
||||
]
|
||||
})
|
||||
|
||||
if 'can_change_teams' in request.orgapermset:
|
||||
if 'organizer.teams:write' in request.orgapermset:
|
||||
nav.append({
|
||||
'label': _('Teams'),
|
||||
'url': reverse('control:organizer.teams', kwargs={
|
||||
@@ -544,7 +544,7 @@ def get_organizer_navigation(request):
|
||||
'icon': 'group',
|
||||
})
|
||||
|
||||
if 'can_manage_gift_cards' in request.orgapermset:
|
||||
if 'organizer.giftcards:write' in request.orgapermset:
|
||||
children = []
|
||||
children.append({
|
||||
'label': _('Gift cards'),
|
||||
@@ -554,7 +554,7 @@ def get_organizer_navigation(request):
|
||||
'active': 'organizer.giftcard' in url.url_name and 'acceptance' not in url.url_name,
|
||||
'children': children,
|
||||
})
|
||||
if 'can_change_organizer_settings' in request.orgapermset:
|
||||
if 'organizer.settings.general:write' in request.orgapermset:
|
||||
children.append(
|
||||
{
|
||||
'label': _('Acceptance'),
|
||||
@@ -575,7 +575,7 @@ def get_organizer_navigation(request):
|
||||
|
||||
if request.organizer.settings.customer_accounts:
|
||||
children = []
|
||||
if 'can_manage_customers' in request.orgapermset:
|
||||
if 'organizer.customers:write' in request.orgapermset:
|
||||
children.append(
|
||||
{
|
||||
'label': _('Customers'),
|
||||
@@ -585,7 +585,7 @@ def get_organizer_navigation(request):
|
||||
'active': 'organizer.customer' in url.url_name,
|
||||
}
|
||||
)
|
||||
if 'can_change_organizer_settings' in request.orgapermset:
|
||||
if 'organizer.settings.general:write' in request.orgapermset:
|
||||
children.append(
|
||||
{
|
||||
'label': _('Membership types'),
|
||||
@@ -633,7 +633,7 @@ def get_organizer_navigation(request):
|
||||
'active': 'organizer.reusable_medi' in url.url_name,
|
||||
})
|
||||
|
||||
if 'can_change_organizer_settings' in request.orgapermset:
|
||||
if 'organizer.settings.general:write' in request.orgapermset:
|
||||
nav.append({
|
||||
'label': _('Devices'),
|
||||
'url': reverse('control:organizer.devices', kwargs={
|
||||
@@ -667,7 +667,7 @@ def get_organizer_navigation(request):
|
||||
'icon': 'download',
|
||||
})
|
||||
|
||||
if 'can_change_organizer_settings' in request.orgapermset:
|
||||
if 'organizer.settings.general:write' in request.orgapermset:
|
||||
merge_in(nav, [{
|
||||
'parent': reverse('control:organizer.export', kwargs={
|
||||
'organizer': request.organizer.slug,
|
||||
|
||||
@@ -53,9 +53,9 @@ def event_permission_required(permission):
|
||||
This view decorator rejects all requests with a 403 response which are not from
|
||||
users having the given permission for the event the request is associated with.
|
||||
"""
|
||||
if permission == 'can_change_settings':
|
||||
if permission == 'event.settings.general:write':
|
||||
# Legacy support
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def decorator(function):
|
||||
def wrapper(request, *args, **kw):
|
||||
@@ -92,9 +92,9 @@ def organizer_permission_required(permission):
|
||||
This view decorator rejects all requests with a 403 response which are not from
|
||||
users having the given permission for the event the request is associated with.
|
||||
"""
|
||||
if permission == 'can_change_settings':
|
||||
if permission == 'event.settings.general:write':
|
||||
# Legacy support
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
|
||||
def decorator(function):
|
||||
def wrapper(request, *args, **kw):
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% blocktrans with name=checkinlist.name %}Check-in list: {{ name }}{% endblocktrans %}
|
||||
{% if 'can_change_event_settings' in request.eventpermset %}
|
||||
{% if 'event.settings.general:write' in request.eventpermset %}
|
||||
<a href="{% url "control:event.orders.checkinlists.edit" event=request.event.slug organizer=request.event.organizer.slug list=checkinlist.pk %}"
|
||||
class="btn btn-default">
|
||||
<span class="fa fa-wrench"></span>
|
||||
@@ -87,7 +87,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{% if "can_change_orders" in request.eventpermset or "can_checkin_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset or "event.orders:checkin" in request.eventpermset %}
|
||||
<label aria-label="{% trans "select all rows for batch-operation" %}"
|
||||
class="batch-select-label"><input type="checkbox" data-toggle-table/></label>
|
||||
{% endif %}
|
||||
@@ -132,7 +132,7 @@
|
||||
{% for e in entries %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if "can_change_orders" in request.eventpermset or "can_checkin_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset or "event.orders:checkin" in request.eventpermset %}
|
||||
<input type="checkbox" name="checkin" id="id_checkin" class="" value="{{ e.pk }}"/>
|
||||
{% endif %}
|
||||
</td>
|
||||
@@ -207,7 +207,7 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="batch-select-actions">
|
||||
{% if "can_change_orders" in request.eventpermset or "can_checkin_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset or "event.orders:checkin" in request.eventpermset %}
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
<span class="fa fa-sign-in" aria-hidden="true"></span>
|
||||
{% trans "Check-In selected attendees" %}
|
||||
@@ -217,7 +217,7 @@
|
||||
{% trans "Check-Out selected attendees" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<button type="submit" class="btn btn-danger btn-save" name="revert"
|
||||
formaction="{% url "control:event.orders.checkinlists.bulk_revert" event=request.event.slug organizer=request.event.organizer.slug list=checkinlist.pk %}"
|
||||
data-no-asynctask
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.orders.checkinlists.add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-primary btn-lg"><i class="fa fa-plus"></i> {% trans "Create a new check-in list" %}
|
||||
</a>
|
||||
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<p>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.orders.checkinlists.add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new check-in list" %}</a>
|
||||
{% endif %}
|
||||
@@ -83,7 +83,7 @@
|
||||
<a href="{% url "control:organizer.devices" organizer=request.organizer.slug %}"
|
||||
class="btn btn-default"><i class="fa fa-tablet"></i> {% trans "Connected devices" %}</a>
|
||||
{% endif %}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.orders.checkinlists.reset" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default">
|
||||
<span class="fa fa-repeat"></span>
|
||||
@@ -158,7 +158,7 @@
|
||||
<td class="text-right flip">
|
||||
<a href="{% url "control:event.orders.checkinlists.show" organizer=request.event.organizer.slug event=request.event.slug list=cl.id %}"
|
||||
class="btn btn-default btn-sm"><i class="fa fa-eye"></i></a>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.orders.checkinlists.add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ cl.id }}"
|
||||
class="btn btn-sm btn-default" title="{% trans "Clone" %}" data-toggle="tooltip">
|
||||
<span class="fa fa-copy"></span>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% block inside %}
|
||||
<h1>
|
||||
{% blocktrans with name=checkinlist.name %}Check-in list: {{ name }}{% endblocktrans %}
|
||||
{% if 'can_change_event_settings' in request.eventpermset %}
|
||||
{% if 'event.settings.general:write' in request.eventpermset %}
|
||||
<a href="{% url "control:event.orders.checkinlists.edit" event=request.event.slug organizer=request.event.organizer.slug list=checkinlist.pk %}"
|
||||
class="btn btn-default">
|
||||
<span class="fa fa-wrench"></span>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% block inside %}
|
||||
<h1>
|
||||
{% blocktrans with name=quota.name %}Quota: {{ name }}{% endblocktrans %}
|
||||
{% if 'can_change_items' in request.eventpermset %}
|
||||
{% if 'event.items:write' in request.eventpermset %}
|
||||
<a href="{% url "control:event.items.quotas.edit" event=request.event.slug organizer=request.event.organizer.slug quota=quota.pk %}"
|
||||
class="btn btn-default">
|
||||
<span class="fa fa-edit"></span>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
{% endif %}
|
||||
{% include "pretixcontrol/orders/fragment_order_status.html" with order=order class="pull-right flip" %}
|
||||
</h1>
|
||||
{% if 'can_change_orders' in request.eventpermset %}
|
||||
{% if 'event.orders:write' in request.eventpermset %}
|
||||
<form action="{% url "control:event.order.transition" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}"
|
||||
method="post">
|
||||
{% csrf_token %}
|
||||
@@ -193,7 +193,7 @@
|
||||
<dt>{% trans "Order locale" %}</dt>
|
||||
<dd>
|
||||
{{ display_locale }}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.order.locale" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default btn-xs">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
@@ -220,7 +220,7 @@
|
||||
{{ order.customer.identifier }} – {{ order.customer.email }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.order.contact" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default btn-xs">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
@@ -233,7 +233,7 @@
|
||||
{% if order.email and order.email_known_to_work %}
|
||||
<span class="fa fa-check-circle text-success" data-toggle="tooltip" title="{% trans "We know that this email address works because the user clicked a link we sent them." %}"></span>
|
||||
{% endif %}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.order.contact" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default btn-xs">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
@@ -257,7 +257,7 @@
|
||||
<dt>{% trans "Phone number" %}</dt>
|
||||
<dd>
|
||||
{{ order.phone|default_if_none:""|phone_format }}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.order.contact" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default btn-xs">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
@@ -371,7 +371,7 @@
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if can_generate_invoice and 'can_change_orders' in request.eventpermset %}
|
||||
{% if can_generate_invoice and 'event.orders:write' in request.eventpermset %}
|
||||
<br/>
|
||||
<form class="form-inline helper-display-inline" method="post"
|
||||
action="{% url "control:event.order.geninvoice" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
|
||||
@@ -382,7 +382,7 @@
|
||||
</form>
|
||||
{% endif %}
|
||||
</dd>
|
||||
{% elif can_generate_invoice and 'can_change_orders' in request.eventpermset %}
|
||||
{% elif can_generate_invoice and 'event.orders:write' in request.eventpermset %}
|
||||
<dt>{% trans "Invoices" %}</dt>
|
||||
<dd>
|
||||
<form class="form-inline helper-display-inline" method="post"
|
||||
@@ -400,7 +400,7 @@
|
||||
<div class="panel panel-default items">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right flip">
|
||||
{% if 'can_change_orders' in request.eventpermset %}
|
||||
{% if 'event.orders:write' in request.eventpermset %}
|
||||
<a href="{% url "control:event.order.info" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
|
||||
<span class="fa fa-edit"></span>
|
||||
{% trans "Change answers" %}
|
||||
@@ -893,7 +893,7 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if order.payment_refund_sum > 0 and "can_change_orders" in request.eventpermset %}
|
||||
{% if order.payment_refund_sum > 0 and "event.orders:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.order.refunds.start" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default">
|
||||
{% trans "Create a refund" %}
|
||||
</a>
|
||||
@@ -1012,7 +1012,7 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right flip">
|
||||
{% if 'can_change_orders' in request.eventpermset %}
|
||||
{% if 'event.orders:write' in request.eventpermset %}
|
||||
<a href="{% url "control:event.order.info" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
|
||||
<span class="fa fa-edit"></span>
|
||||
{% trans "Change" %}
|
||||
@@ -1088,7 +1088,7 @@
|
||||
{% bootstrap_field comment_form.custom_followup_at %}
|
||||
{% bootstrap_field comment_form.checkin_attention show_help=True show_label=False %}
|
||||
{% bootstrap_field comment_form.checkin_text show_help=True show_label=False %}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<button class="btn btn-default">
|
||||
{% trans "Update comment" %}
|
||||
</button>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
<table class="table table-condensed table-hover table-orders">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<th>
|
||||
<label aria-label="{% trans "select all rows for batch-operation" %}"
|
||||
class="batch-select-label"><input type="checkbox" data-toggle-table/></label>
|
||||
@@ -154,7 +154,7 @@
|
||||
<a href="?{% url_replace request 'ordering' 'status' %}"><i class="fa fa-caret-up"></i></a>
|
||||
</th>
|
||||
</tr>
|
||||
{% if page_obj.paginator.num_pages > 1 and "can_change_orders" in request.eventpermset %}
|
||||
{% if page_obj.paginator.num_pages > 1 and "event.orders:write" in request.eventpermset %}
|
||||
<tr class="table-select-all warning hidden">
|
||||
<td>
|
||||
<input type="checkbox" name="__ALL" id="__all"
|
||||
@@ -171,7 +171,7 @@
|
||||
<tbody>
|
||||
{% for o in orders %}
|
||||
<tr>
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<td>
|
||||
<label aria-label="{% trans "select row for batch-operation" %}"
|
||||
class="batch-select-label"><input type="checkbox" name="order"
|
||||
@@ -281,7 +281,7 @@
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<div class="batch-select-actions">
|
||||
<div class="btn-group dropup">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% blocktrans with name=request.organizer.name %}Organizer: {{ name }}{% endblocktrans %}
|
||||
</h1>
|
||||
{% if events|length == 0 and not filter_form.filtered %}
|
||||
{% if "can_create_events" in request.orgapermset %}
|
||||
{% if "organizer.events:create" in request.orgapermset %}
|
||||
<p>
|
||||
<a href="{% url "control:events.add" %}?organizer={{ request.organizer.slug }}" class="btn btn-primary">
|
||||
<span class="fa fa-plus"></span>
|
||||
@@ -50,7 +50,7 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% if "can_create_events" in request.orgapermset %}
|
||||
{% if "organizer.events:create" in request.orgapermset %}
|
||||
<p>
|
||||
<a href="{% url "control:events.add" %}?organizer={{ request.organizer.slug }}" class="btn btn-primary">
|
||||
<span class="fa fa-plus"></span>
|
||||
@@ -125,7 +125,7 @@
|
||||
data-toggle="tooltip">
|
||||
<span class="fa fa-eye"></span>
|
||||
</a>
|
||||
{% if "can_create_events" in request.orgapermset %}
|
||||
{% if "organizer.events:create" in request.orgapermset %}
|
||||
<a href="{% url "control:events.add" %}?clone={{ e.pk }}" class="btn btn-sm btn-default"
|
||||
title="{% trans "Clone event" %}" data-toggle="tooltip">
|
||||
<span class="fa fa-copy"></span>
|
||||
|
||||
@@ -22,25 +22,16 @@
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Organizer permissions" %}</legend>
|
||||
{% bootstrap_field form.can_create_events layout="control" %}
|
||||
{% bootstrap_field form.can_manage_gift_cards layout="control" %}
|
||||
{% bootstrap_field form.can_manage_customers layout="control" %}
|
||||
{% bootstrap_field form.can_manage_reusable_media layout="control" %}
|
||||
{% bootstrap_field form.can_change_teams layout="control" %}
|
||||
{% bootstrap_field form.can_change_organizer_settings layout="control" %}
|
||||
{% bootstrap_field form.all_organizer_permissions layout="control" %}
|
||||
{% bootstrap_field form.limit_organizer_permissions layout="control" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Event permissions" %}</legend>
|
||||
|
||||
{% bootstrap_field form.all_events layout="control" %}
|
||||
{% bootstrap_field form.limit_events layout="control" %}
|
||||
{% bootstrap_field form.can_change_event_settings layout="control" %}
|
||||
{% bootstrap_field form.can_change_items layout="control" %}
|
||||
{% bootstrap_field form.can_view_orders layout="control" %}
|
||||
{% bootstrap_field form.can_change_orders layout="control" %}
|
||||
{% bootstrap_field form.can_checkin_orders layout="control" %}
|
||||
{% bootstrap_field form.can_view_vouchers layout="control" %}
|
||||
{% bootstrap_field form.can_change_vouchers layout="control" %}
|
||||
{% bootstrap_field form.all_event_permissions layout="control" %}
|
||||
{% bootstrap_field form.limit_event_permissions layout="control" %}
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.subevents:write" in request.eventpermset %}
|
||||
<p>
|
||||
<a href="{% url "control:event.subevents.add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default"><i class="fa fa-plus"></i>
|
||||
@@ -85,7 +85,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.subevents:write" in request.eventpermset %}
|
||||
<label aria-label="{% trans "select all rows for batch-operation" %}" class="batch-select-label"><input type="checkbox" data-toggle-table/></label>
|
||||
{% endif %}
|
||||
</th>
|
||||
@@ -107,7 +107,7 @@
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% if "can_change_event_settings" in request.eventpermset and page_obj.paginator.num_pages > 1 %}
|
||||
{% if "event.subevents:write" in request.eventpermset and page_obj.paginator.num_pages > 1 %}
|
||||
<tr class="table-select-all warning hidden">
|
||||
<td>
|
||||
<input type="checkbox" name="__ALL" id="__all" data-results-total="{{ page_obj.paginator.count }}">
|
||||
@@ -124,7 +124,7 @@
|
||||
{% for s in subevents %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.subevents:write" in request.eventpermset %}
|
||||
<label aria-label="{% trans "select row for batch-operation" %}" class="batch-select-label"><input type="checkbox" name="subevent" class="batch-select-checkbox" value="{{ s.pk }}"/></label>
|
||||
{% endif %}
|
||||
</td>
|
||||
@@ -201,7 +201,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.subevents:write" in request.eventpermset %}
|
||||
<div class="batch-select-actions">
|
||||
<button type="submit" class="btn btn-danger btn-save" name="action" value="delete">
|
||||
<i class="fa fa-trash"></i>{% trans "Delete selected" %}
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if "can_change_vouchers" in request.eventpermset %}
|
||||
{% if "event.vouchers:write" in request.eventpermset %}
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if "can_change_vouchers" in request.eventpermset %}
|
||||
{% if "event.vouchers:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.vouchers.add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-primary btn-lg"><i class="fa fa-plus"></i> {% trans "Create a new voucher" %}</a>
|
||||
<a href="{% url "control:event.vouchers.bulk" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
@@ -83,7 +83,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<p>
|
||||
{% if "can_change_vouchers" in request.eventpermset %}
|
||||
{% if "event.vouchers:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.vouchers.add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new voucher" %}</a>
|
||||
<a href="{% url "control:event.vouchers.bulk" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
@@ -103,7 +103,7 @@
|
||||
<table class="table table-hover table-quotas">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if "can_change_vouchers" in request.eventpermset %}
|
||||
{% if "event.vouchers:write" in request.eventpermset %}
|
||||
<th>
|
||||
<label aria-label="{% trans "select all rows for batch-operation" %}" class="batch-select-label">
|
||||
<input type="checkbox" data-toggle-table />
|
||||
@@ -148,7 +148,7 @@
|
||||
<tbody>
|
||||
{% for v in vouchers %}
|
||||
<tr>
|
||||
{% if "can_change_vouchers" in request.eventpermset %}
|
||||
{% if "event.vouchers:write" in request.eventpermset %}
|
||||
<td>
|
||||
<label aria-label="{% trans "select row for batch-operation" %}" class="batch-select-label">
|
||||
<input type="checkbox" name="voucher" class="batch-select-checkbox" value="{{ v.pk }}"/>
|
||||
@@ -192,7 +192,7 @@
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="text-right flip">
|
||||
{% if "can_change_vouchers" in request.eventpermset %}
|
||||
{% if "event.vouchers:write" in request.eventpermset %}
|
||||
<a href="{% url "control:event.vouchers.bulk" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ v.id }}"
|
||||
class="btn btn-sm btn-default" title="{% trans "Use as a template for new vouchers" %}" data-toggle="tooltip">
|
||||
<span class="fa fa-copy"></span>
|
||||
@@ -205,7 +205,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if "can_change_vouchers" in request.eventpermset %}
|
||||
{% if "event.vouchers:write" in request.eventpermset %}
|
||||
<div class="batch-select-actions">
|
||||
<button type="submit" class="btn btn-danger" name="action" value="delete">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
{% if 'can_change_orders' in request.eventpermset %}
|
||||
{% if 'event.orders:write' in request.eventpermset %}
|
||||
<form method="post" class="col-md-6"
|
||||
action="{% url "control:event.orders.waitinglist.auto" event=request.event.slug organizer=request.organizer.slug %}"
|
||||
data-asynctask>
|
||||
@@ -80,7 +80,7 @@
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
<div class="{% if 'can_change_orders' in request.eventpermset %}col-md-6{% else %}col-md-12{% endif %}">
|
||||
<div class="{% if 'event.orders:write' in request.eventpermset %}col-md-6{% else %}col-md-12{% endif %}">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
{% trans "Sales estimate" %}
|
||||
@@ -151,7 +151,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<label aria-label="{% trans "select all rows for batch-operation" %}" class="batch-select-label"><input type="checkbox" data-toggle-table/></label>
|
||||
{% endif %}
|
||||
</th>
|
||||
@@ -171,7 +171,7 @@
|
||||
<th>{% trans "Voucher" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% if "can_change_orders" in request.eventpermset and page_obj.paginator.num_pages > 1 %}
|
||||
{% if "event.orders:write" in request.eventpermset and page_obj.paginator.num_pages > 1 %}
|
||||
<tr class="table-select-all warning hidden">
|
||||
<td>
|
||||
<input type="checkbox" name="__ALL" id="__all" data-results-total="{{ page_obj.paginator.count }}">
|
||||
@@ -188,7 +188,7 @@
|
||||
{% for e in entries %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<label aria-label="{% trans "select row for batch-operation" %}" class="batch-select-label"><input type="checkbox" name="entry" class="batch-select-checkbox" value="{{ e.pk }}"/></label>
|
||||
{% endif %}
|
||||
</td>
|
||||
@@ -290,7 +290,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
{% if "event.orders:write" in request.eventpermset %}
|
||||
<div class="batch-select-actions">
|
||||
<button type="submit" class="btn btn-danger btn-save" name="action" value="delete">
|
||||
<i class="fa fa-trash"></i>
|
||||
|
||||
@@ -150,7 +150,7 @@ class CheckInListShow(EventPermissionRequiredMixin, PaginationMixin, CheckInList
|
||||
model = Checkin
|
||||
context_object_name = 'entries'
|
||||
template_name = 'pretixcontrol/checkin/index.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.list = get_object_or_404(self.request.event.checkin_lists.all(), pk=kwargs.get("list"))
|
||||
@@ -211,7 +211,7 @@ class CheckInListBulkRevertConfirmView(CheckInListQueryMixin, EventPermissionReq
|
||||
|
||||
|
||||
class CheckInListBulkActionView(CheckInListQueryMixin, EventPermissionRequiredMixin, AsyncPostView):
|
||||
permission = ('can_change_orders', 'can_checkin_orders')
|
||||
permission = ('event.orders:write', 'event.orders:checkin')
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.list = get_object_or_404(self.request.event.checkin_lists.all(), pk=kwargs.get("list"))
|
||||
@@ -228,7 +228,7 @@ class CheckInListBulkActionView(CheckInListQueryMixin, EventPermissionRequiredMi
|
||||
self.list = get_object_or_404(request.event.checkin_lists.all(), pk=kwargs.get("list"))
|
||||
positions = self.get_queryset()
|
||||
if request.POST.get('revert') == 'true':
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_orders', request=request):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.orders:write', request=request):
|
||||
raise PermissionDenied()
|
||||
for op in positions:
|
||||
if op.order.status == Order.STATUS_PAID or (
|
||||
@@ -295,7 +295,7 @@ class CheckInListBulkActionView(CheckInListQueryMixin, EventPermissionRequiredMi
|
||||
class CheckinListList(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
model = CheckinList
|
||||
context_object_name = 'checkinlists'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
template_name = 'pretixcontrol/checkin/lists.html'
|
||||
ordering = ('subevent__date_from', 'name', 'pk')
|
||||
|
||||
@@ -319,7 +319,7 @@ class CheckinListList(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
|
||||
ctx['can_change_organizer_settings'] = self.request.user.has_organizer_permission(
|
||||
self.request.organizer,
|
||||
'can_change_organizer_settings',
|
||||
'organizer.settings.general:write',
|
||||
self.request
|
||||
)
|
||||
ctx['filter_form'] = self.filter_form
|
||||
@@ -335,7 +335,7 @@ class CheckinListCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = CheckinList
|
||||
form_class = CheckinListForm
|
||||
template_name = 'pretixcontrol/checkin/list_edit.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'checkinlist'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
@@ -386,7 +386,7 @@ class CheckinListUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = CheckinList
|
||||
form_class = CheckinListForm
|
||||
template_name = 'pretixcontrol/checkin/list_edit.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'checkinlist'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
@@ -445,7 +445,7 @@ class CheckinListUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
class CheckinListDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = CheckinList
|
||||
template_name = 'pretixcontrol/checkin/list_delete.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'checkinlist'
|
||||
|
||||
def get_object(self, queryset=None) -> CheckinList:
|
||||
@@ -476,7 +476,7 @@ class CheckinListDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
class CheckinListView(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
model = Checkin
|
||||
context_object_name = 'checkins'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
template_name = 'pretixcontrol/checkin/checkins.html'
|
||||
ordering = ('-datetime', '-pk')
|
||||
|
||||
@@ -505,7 +505,7 @@ class CheckinListView(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
|
||||
class CheckInListSimulator(EventPermissionRequiredMixin, FormView):
|
||||
template_name = 'pretixcontrol/checkin/simulator.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
form_class = CheckinListSimulatorForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
@@ -575,7 +575,7 @@ class CheckInListSimulator(EventPermissionRequiredMixin, FormView):
|
||||
|
||||
class CheckInResetView(CheckInListQueryMixin, EventPermissionRequiredMixin, AsyncFormView):
|
||||
form_class = CheckinResetForm
|
||||
permission = "can_change_orders"
|
||||
permission = "event.orders:write"
|
||||
template_name = "pretixcontrol/checkin/reset.html"
|
||||
|
||||
def get_error_url(self, *args):
|
||||
|
||||
@@ -66,6 +66,7 @@ from pretix.control.signals import (
|
||||
from pretix.helpers.daterange import daterange
|
||||
|
||||
from ...base.models.orders import CancellationRequest
|
||||
from ...base.models.organizer import TeamQuerySet
|
||||
from ...base.templatetags.money import money_filter
|
||||
from ..logdisplay import OVERVIEW_BANLIST
|
||||
|
||||
@@ -350,10 +351,10 @@ def event_index(request, organizer, event):
|
||||
except SubEvent.DoesNotExist:
|
||||
pass
|
||||
|
||||
can_view_orders = request.user.has_event_permission(request.organizer, request.event, 'can_view_orders',
|
||||
can_view_orders = request.user.has_event_permission(request.organizer, request.event, 'event.orders:read',
|
||||
request=request)
|
||||
can_change_event_settings = request.user.has_event_permission(request.organizer, request.event,
|
||||
'can_change_event_settings', request=request)
|
||||
'event.settings.general:write', request=request)
|
||||
|
||||
widgets = []
|
||||
if can_view_orders:
|
||||
@@ -425,11 +426,11 @@ def event_index_log_lazy(request, organizer, event):
|
||||
'device').order_by('-datetime')
|
||||
qs = qs.exclude(action_type__in=OVERVIEW_BANLIST)
|
||||
|
||||
can_view_orders = request.user.has_event_permission(request.organizer, request.event, 'can_view_orders',
|
||||
can_view_orders = request.user.has_event_permission(request.organizer, request.event, 'event.orders:read',
|
||||
request=request)
|
||||
can_change_event_settings = request.user.has_event_permission(request.organizer, request.event,
|
||||
'can_change_event_settings', request=request)
|
||||
can_view_vouchers = request.user.has_event_permission(request.organizer, request.event, 'can_view_vouchers',
|
||||
'event.settings.general:write', request=request)
|
||||
can_view_vouchers = request.user.has_event_permission(request.organizer, request.event, 'event.vouchers:read',
|
||||
request=request)
|
||||
|
||||
if not can_view_orders:
|
||||
@@ -441,7 +442,7 @@ def event_index_log_lazy(request, organizer, event):
|
||||
ContentType.objects.get_for_model(Voucher),
|
||||
ContentType.objects.get_for_model(Order)
|
||||
]
|
||||
if request.user.has_event_permission(request.organizer, request.event, 'can_change_items', request=request):
|
||||
if request.user.has_event_permission(request.organizer, request.event, 'event.items:write', request=request):
|
||||
allowed_types += [
|
||||
ContentType.objects.get_for_model(Item),
|
||||
ContentType.objects.get_for_model(ItemCategory),
|
||||
@@ -491,8 +492,13 @@ def widgets_for_event_qs(request, qs, user, nmax, lazy=False):
|
||||
# Get set of events where we have the permission to show the # of orders
|
||||
if not lazy:
|
||||
events_with_orders = set(qs.filter(
|
||||
Q(organizer_id__in=user.teams.filter(all_events=True, can_view_orders=True).values_list('organizer', flat=True))
|
||||
| Q(id__in=user.teams.filter(can_view_orders=True).values_list('limit_events__id', flat=True))
|
||||
Q(organizer_id__in=user.teams.filter(
|
||||
TeamQuerySet.event_permission_q("event.orders:read"),
|
||||
all_events=True,
|
||||
).values_list('organizer', flat=True))
|
||||
| Q(id__in=user.teams.filter(
|
||||
TeamQuerySet.event_permission_q("event.orders:read"),
|
||||
).values_list('limit_events__id', flat=True))
|
||||
).values_list('id', flat=True))
|
||||
|
||||
tpl = """
|
||||
@@ -635,7 +641,7 @@ def user_index(request):
|
||||
|
||||
ctx = {
|
||||
'widgets': rearrange(widgets),
|
||||
'can_create_event': request.user.teams.filter(can_create_events=True).exists(),
|
||||
'can_create_event': request.user.teams.with_organizer_permission("organizer:events.create").exists(),
|
||||
'upcoming': widgets_for_event_qs(
|
||||
request,
|
||||
annotated_event_query(request, lazy=True).filter(
|
||||
|
||||
@@ -72,7 +72,7 @@ def on_control_order_info(sender: Event, request, order: Order, **kwargs):
|
||||
|
||||
|
||||
class ControlSyncJob(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, request, provider, *args, **kwargs):
|
||||
prov, meta = datasync_providers.get(active_in=self.request.event, identifier=provider)
|
||||
@@ -154,7 +154,7 @@ class GlobalFailedSyncJobsView(AdministratorPermissionRequiredMixin, FailedSyncJ
|
||||
|
||||
|
||||
class OrganizerFailedSyncJobsView(OrganizerPermissionRequiredMixin, FailedSyncJobsView):
|
||||
permission = "can_change_organizer_settings"
|
||||
permission = "organizer.settings.general:write"
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(
|
||||
@@ -163,7 +163,7 @@ class OrganizerFailedSyncJobsView(OrganizerPermissionRequiredMixin, FailedSyncJo
|
||||
|
||||
|
||||
class EventFailedSyncJobsView(EventPermissionRequiredMixin, FailedSyncJobsView):
|
||||
permission = "can_change_event_settings"
|
||||
permission = "event.settings.general:write"
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(
|
||||
|
||||
@@ -50,7 +50,7 @@ from . import CreateView, PaginationMixin, UpdateView
|
||||
class DiscountDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Discount
|
||||
template_name = 'pretixcontrol/items/discount_delete.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'discount'
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
@@ -96,7 +96,7 @@ class DiscountUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Discount
|
||||
form_class = DiscountForm
|
||||
template_name = 'pretixcontrol/items/discount.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'discount'
|
||||
|
||||
def get_object(self, queryset=None) -> Discount:
|
||||
@@ -139,7 +139,7 @@ class DiscountCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = Discount
|
||||
form_class = DiscountForm
|
||||
template_name = 'pretixcontrol/items/discount.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'discount'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
@@ -227,7 +227,7 @@ def discount_move(request, discount, up=True):
|
||||
messages.success(request, _('The order of discounts has been updated.'))
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def discount_move_up(request, organizer, event, discount):
|
||||
discount_move(request, discount, up=True)
|
||||
@@ -236,7 +236,7 @@ def discount_move_up(request, organizer, event, discount):
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def discount_move_down(request, organizer, event, discount):
|
||||
discount_move(request, discount, up=False)
|
||||
@@ -246,7 +246,7 @@ def discount_move_down(request, organizer, event, discount):
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_discounts(request, organizer, event):
|
||||
try:
|
||||
|
||||
@@ -155,7 +155,7 @@ class MetaDataEditorMixin:
|
||||
property=p,
|
||||
disabled=(
|
||||
p.protected and
|
||||
not self.request.user.has_organizer_permission(self.request.organizer, 'can_change_organizer_settings', request=self.request)
|
||||
not self.request.user.has_organizer_permission(self.request.organizer, 'organizer.settings.general:write', request=self.request)
|
||||
),
|
||||
instance=val_instances.get(p.pk, self.meta_model(property=p, event=self.object)),
|
||||
data=(self.request.POST if self.request.method == "POST" else None)
|
||||
@@ -187,7 +187,7 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
model = Event
|
||||
form_class = EventUpdateForm
|
||||
template_name = 'pretixcontrol/event/settings.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
@cached_property
|
||||
def object(self) -> Event:
|
||||
@@ -346,7 +346,7 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
|
||||
model = Event
|
||||
context_object_name = 'event'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
template_name = 'pretixcontrol/event/plugins.html'
|
||||
|
||||
def get_object(self, queryset=None) -> Event:
|
||||
@@ -447,7 +447,7 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
|
||||
continue
|
||||
|
||||
if getattr(pluginmeta, 'level', PLUGIN_LEVEL_EVENT) == PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID:
|
||||
if not request.user.has_organizer_permission(request.organizer, "can_change_organizer_settings", request):
|
||||
if not request.user.has_organizer_permission(request.organizer, "organizer.settings.general:write", request):
|
||||
messages.error(
|
||||
request,
|
||||
_("You do not have sufficient permission to enable plugins that need to be enabled "
|
||||
@@ -502,7 +502,7 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
|
||||
class PaymentProviderSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
|
||||
model = Event
|
||||
context_object_name = 'event'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
template_name = 'pretixcontrol/event/payment_provider.html'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
@@ -581,7 +581,7 @@ class PaymentProviderSettings(EventSettingsViewMixin, EventPermissionRequiredMix
|
||||
|
||||
class EventSettingsFormView(EventPermissionRequiredMixin, DecoupleMixin, FormView):
|
||||
model = Event
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
@@ -621,7 +621,7 @@ class EventSettingsFormView(EventPermissionRequiredMixin, DecoupleMixin, FormVie
|
||||
class PaymentSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
template_name = 'pretixcontrol/event/payment.html'
|
||||
form_class = PaymentSettingsForm
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.settings.payment', kwargs={
|
||||
@@ -650,7 +650,7 @@ class PaymentSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
class TaxSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
template_name = 'pretixcontrol/event/tax.html'
|
||||
form_class = TaxSettingsForm
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.settings.tax', kwargs={
|
||||
@@ -670,7 +670,7 @@ class InvoiceSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
form_class = InvoiceSettingsForm
|
||||
template_name = 'pretixcontrol/event/invoicing.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
types = get_transmission_types()
|
||||
@@ -704,7 +704,7 @@ class CancelSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
form_class = CancelSettingsForm
|
||||
template_name = 'pretixcontrol/event/cancel.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.settings.cancel', kwargs={
|
||||
@@ -738,7 +738,7 @@ class CancelSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
|
||||
|
||||
class InvoicePreview(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
fname, ftype, fcontent = build_preview_invoice_pdf(request.event)
|
||||
@@ -753,7 +753,7 @@ class InvoicePreview(EventPermissionRequiredMixin, View):
|
||||
|
||||
|
||||
class DangerZone(EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
template_name = 'pretixcontrol/event/dangerzone.html'
|
||||
|
||||
|
||||
@@ -769,7 +769,7 @@ class MailSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
form_class = MailSettingsForm
|
||||
template_name = 'pretixcontrol/event/mail.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.settings.mail', kwargs={
|
||||
@@ -801,7 +801,7 @@ class MailSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
|
||||
|
||||
class MailSettingsSetup(EventPermissionRequiredMixin, MailSettingsSetupView):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
basetpl = 'pretixcontrol/event/base.html'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
@@ -817,7 +817,7 @@ class MailSettingsSetup(EventPermissionRequiredMixin, MailSettingsSetupView):
|
||||
|
||||
|
||||
class MailSettingsPreview(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
# create index-language mapping
|
||||
@cached_property
|
||||
@@ -883,7 +883,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
|
||||
|
||||
|
||||
class MailSettingsRendererPreview(MailSettingsPreview):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
return HttpResponse(status=405)
|
||||
@@ -931,7 +931,7 @@ class MailSettingsRendererPreview(MailSettingsPreview):
|
||||
|
||||
|
||||
class TicketSettingsPreview(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
@cached_property
|
||||
def output(self):
|
||||
@@ -963,7 +963,7 @@ class TicketSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, FormV
|
||||
model = Event
|
||||
form_class = TicketSettingsForm
|
||||
template_name = 'pretixcontrol/event/tickets.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
@@ -1074,7 +1074,7 @@ class EventPermissions(EventSettingsViewMixin, EventPermissionRequiredMixin, Tem
|
||||
|
||||
|
||||
class EventLive(EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
template_name = 'pretixcontrol/event/live.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -1141,12 +1141,12 @@ class EventLive(EventPermissionRequiredMixin, TemplateView):
|
||||
|
||||
|
||||
class EventTransferSession(EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
template_name = 'pretixcontrol/event/transfer_session.html'
|
||||
|
||||
|
||||
class EventDelete(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, FormView):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
template_name = 'pretixcontrol/event/delete.html'
|
||||
form_class = EventDeleteForm
|
||||
|
||||
@@ -1214,20 +1214,20 @@ class EventLog(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
'user', 'content_type', 'api_token', 'oauth_application', 'device'
|
||||
).order_by('-datetime', '-pk')
|
||||
qs = qs.exclude(action_type__in=OVERVIEW_BANLIST)
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'can_view_orders',
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'event.orders:read',
|
||||
request=self.request):
|
||||
qs = qs.exclude(content_type=ContentType.objects.get_for_model(Order))
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'can_view_vouchers',
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'event.vouchers:read',
|
||||
request=self.request):
|
||||
qs = qs.exclude(content_type=ContentType.objects.get_for_model(Voucher))
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event,
|
||||
'can_change_event_settings', request=self.request):
|
||||
'event.settings.general:write', request=self.request):
|
||||
allowed_types = [
|
||||
ContentType.objects.get_for_model(Voucher),
|
||||
ContentType.objects.get_for_model(Order)
|
||||
]
|
||||
if self.request.user.has_event_permission(self.request.organizer, self.request.event,
|
||||
'can_change_items', request=self.request):
|
||||
'event.items:write', request=self.request):
|
||||
allowed_types += [
|
||||
ContentType.objects.get_for_model(Item),
|
||||
ContentType.objects.get_for_model(ItemCategory),
|
||||
@@ -1264,7 +1264,7 @@ class EventLog(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
|
||||
|
||||
class EventComment(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
form = CommentForm(self.request.POST)
|
||||
@@ -1293,7 +1293,7 @@ class TaxCreate(EventSettingsViewMixin, EventPermissionRequiredMixin, CreateView
|
||||
model = TaxRule
|
||||
form_class = TaxRuleForm
|
||||
template_name = 'pretixcontrol/event/tax_edit.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'taxrule'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
@@ -1354,7 +1354,7 @@ class TaxUpdate(EventSettingsViewMixin, EventPermissionRequiredMixin, UpdateView
|
||||
model = TaxRule
|
||||
form_class = TaxRuleForm
|
||||
template_name = 'pretixcontrol/event/tax_edit.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'rule'
|
||||
|
||||
def get_object(self, queryset=None) -> TaxRule:
|
||||
@@ -1418,7 +1418,7 @@ class TaxUpdate(EventSettingsViewMixin, EventPermissionRequiredMixin, UpdateView
|
||||
|
||||
class TaxDefault(EventSettingsViewMixin, EventPermissionRequiredMixin, DetailView):
|
||||
model = TaxRule
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_object(self, queryset=None) -> TaxRule:
|
||||
try:
|
||||
@@ -1463,7 +1463,7 @@ class TaxDefault(EventSettingsViewMixin, EventPermissionRequiredMixin, DetailVie
|
||||
class TaxDelete(EventSettingsViewMixin, EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = TaxRule
|
||||
template_name = 'pretixcontrol/event/tax_delete.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'taxrule'
|
||||
|
||||
def get_object(self, queryset=None) -> TaxRule:
|
||||
@@ -1500,7 +1500,7 @@ class TaxDelete(EventSettingsViewMixin, EventPermissionRequiredMixin, CompatDele
|
||||
|
||||
class WidgetSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, FormView):
|
||||
template_name = 'pretixcontrol/event/widget.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
form_class = WidgetCodeForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -1529,7 +1529,7 @@ class WidgetSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, FormV
|
||||
|
||||
class QuickSetupView(FormView):
|
||||
template_name = 'pretixcontrol/event/quick_setup.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
form_class = QuickSetupForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
|
||||
@@ -159,7 +159,7 @@ def item_move(request, item, up=True):
|
||||
messages.success(request, _('The order of items has been updated.'))
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def item_move_up(request, organizer, event, item):
|
||||
item_move(request, item, up=True)
|
||||
@@ -168,7 +168,7 @@ def item_move_up(request, organizer, event, item):
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def item_move_down(request, organizer, event, item):
|
||||
item_move(request, item, up=False)
|
||||
@@ -178,7 +178,7 @@ def item_move_down(request, organizer, event, item):
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_items(request, organizer, event, category):
|
||||
try:
|
||||
@@ -215,7 +215,7 @@ def reorder_items(request, organizer, event, category):
|
||||
class CategoryDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = ItemCategory
|
||||
template_name = 'pretixcontrol/items/category_delete.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'category'
|
||||
|
||||
def get_object(self, queryset=None) -> ItemCategory:
|
||||
@@ -249,7 +249,7 @@ class CategoryUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = ItemCategory
|
||||
form_class = CategoryForm
|
||||
template_name = 'pretixcontrol/items/category.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'category'
|
||||
|
||||
def get_object(self, queryset=None) -> ItemCategory:
|
||||
@@ -287,7 +287,7 @@ class CategoryCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = ItemCategory
|
||||
form_class = CategoryForm
|
||||
template_name = 'pretixcontrol/items/category.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'category'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
@@ -371,7 +371,7 @@ def category_move(request, category, up=True):
|
||||
messages.success(request, _('The order of categories has been updated.'))
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def category_move_up(request, organizer, event, category):
|
||||
category_move(request, category, up=True)
|
||||
@@ -380,7 +380,7 @@ def category_move_up(request, organizer, event, category):
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def category_move_down(request, organizer, event, category):
|
||||
category_move(request, category, up=False)
|
||||
@@ -390,7 +390,7 @@ def category_move_down(request, organizer, event, category):
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_categories(request, organizer, event):
|
||||
try:
|
||||
@@ -522,7 +522,7 @@ class QuestionList(ListView):
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@event_permission_required("can_change_items")
|
||||
@event_permission_required("event.items:write")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_questions(request, organizer, event):
|
||||
try:
|
||||
@@ -570,7 +570,7 @@ def reorder_questions(request, organizer, event):
|
||||
class QuestionDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Question
|
||||
template_name = 'pretixcontrol/items/question_delete.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'question'
|
||||
|
||||
def get_object(self, queryset=None) -> Question:
|
||||
@@ -664,7 +664,7 @@ class QuestionMixin:
|
||||
class QuestionView(EventPermissionRequiredMixin, ChartContainingView, DetailView):
|
||||
model = Question
|
||||
template_name = 'pretixcontrol/items/question.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
template_name_field = 'question'
|
||||
|
||||
@cached_property
|
||||
@@ -753,7 +753,7 @@ class QuestionUpdate(EventPermissionRequiredMixin, QuestionMixin, UpdateView):
|
||||
model = Question
|
||||
form_class = QuestionForm
|
||||
template_name = 'pretixcontrol/items/question_edit.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'question'
|
||||
|
||||
def get_object(self, queryset=None) -> Question:
|
||||
@@ -794,7 +794,7 @@ class QuestionCreate(EventPermissionRequiredMixin, QuestionMixin, CreateView):
|
||||
model = Question
|
||||
form_class = QuestionForm
|
||||
template_name = 'pretixcontrol/items/question_edit.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'question'
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -888,7 +888,7 @@ class QuotaCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = Quota
|
||||
form_class = QuotaForm
|
||||
template_name = 'pretixcontrol/items/quota_edit.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'quota'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
@@ -1055,7 +1055,7 @@ class QuotaView(ChartContainingView, DetailView):
|
||||
raise Http404(_("The requested quota does not exist."))
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_items', request):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.items:write', request):
|
||||
raise PermissionDenied()
|
||||
quota = self.get_object()
|
||||
if 'reopen' in request.POST:
|
||||
@@ -1085,7 +1085,7 @@ class QuotaUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Quota
|
||||
form_class = QuotaForm
|
||||
template_name = 'pretixcontrol/items/quota_edit.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'quota'
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
@@ -1143,7 +1143,7 @@ class QuotaUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
class QuotaDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Quota
|
||||
template_name = 'pretixcontrol/items/quota_delete.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'quota'
|
||||
|
||||
def get_object(self, queryset=None) -> Quota:
|
||||
@@ -1246,7 +1246,7 @@ class MetaDataEditorMixin:
|
||||
class ItemCreate(EventPermissionRequiredMixin, MetaDataEditorMixin, CreateView):
|
||||
form_class = ItemCreateForm
|
||||
template_name = 'pretixcontrol/item/create.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.item', kwargs={
|
||||
@@ -1322,7 +1322,7 @@ class ItemCreate(EventPermissionRequiredMixin, MetaDataEditorMixin, CreateView):
|
||||
class ItemUpdateGeneral(ItemDetailMixin, EventPermissionRequiredMixin, MetaDataEditorMixin, UpdateView):
|
||||
form_class = ItemUpdateForm
|
||||
template_name = 'pretixcontrol/item/index.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
|
||||
@cached_property
|
||||
def plugin_forms(self):
|
||||
@@ -1584,7 +1584,7 @@ class ItemUpdateGeneral(ItemDetailMixin, EventPermissionRequiredMixin, MetaDataE
|
||||
class ItemDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Item
|
||||
template_name = 'pretixcontrol/item/delete.html'
|
||||
permission = 'can_change_items'
|
||||
permission = 'event.items:write'
|
||||
context_object_name = 'item'
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
|
||||
@@ -51,6 +51,7 @@ from i18nfield.strings import LazyI18nString
|
||||
from pretix.base.forms import SafeSessionWizardView
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import Event, EventMetaValue, Organizer, Quota, Team
|
||||
from pretix.base.models.organizer import TeamQuerySet
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.control.forms.event import (
|
||||
EventWizardBasicsForm, EventWizardCopyForm, EventWizardFoundationForm,
|
||||
@@ -190,7 +191,9 @@ class EventWizard(SafeSessionWizardView):
|
||||
qs = Organizer.objects.all()
|
||||
if not self.request.user.has_active_staff_session(self.request.session.session_key):
|
||||
qs = qs.filter(
|
||||
id__in=self.request.user.teams.filter(can_create_events=True).values_list('organizer', flat=True)
|
||||
id__in=self.request.user.teams.filter(
|
||||
TeamQuerySet.organizer_permission_q("organizer.events:create"),
|
||||
).values_list('organizer', flat=True)
|
||||
)
|
||||
organizer = qs.get(slug=self.request.GET.get('organizer'))
|
||||
initial['organizer'] = organizer
|
||||
@@ -210,9 +213,9 @@ class EventWizard(SafeSessionWizardView):
|
||||
else:
|
||||
allow = (
|
||||
request.user.has_event_permission(clone_from.organizer, clone_from,
|
||||
'can_change_event_settings', request)
|
||||
'event.settings.general:write', request)
|
||||
and request.user.has_event_permission(clone_from.organizer, clone_from,
|
||||
'can_change_items', request)
|
||||
'event.items:write', request)
|
||||
)
|
||||
if not allow:
|
||||
messages.error(self.request, _('You do not have permission to clone this event.'))
|
||||
@@ -222,7 +225,7 @@ class EventWizard(SafeSessionWizardView):
|
||||
|
||||
def get_context_data(self, form, **kwargs):
|
||||
ctx = super().get_context_data(form, **kwargs)
|
||||
ctx['has_organizer'] = self.request.user.teams.filter(can_create_events=True).exists()
|
||||
ctx['has_organizer'] = self.request.user.teams.filter(TeamQuerySet.organizer_permission_q("organizer.events:create")).exists()
|
||||
if self.steps.current == 'basics':
|
||||
ctx['organizer'] = self.get_cleaned_data_for_step('foundation').get('organizer')
|
||||
return ctx
|
||||
@@ -284,21 +287,16 @@ class EventWizard(SafeSessionWizardView):
|
||||
name=_('Team {event}').format(
|
||||
event=str(event.name)[:100] + "…" if len(str(event.name)) > 100 else str(event.name)
|
||||
),
|
||||
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_organizer_permissions=False,
|
||||
all_event_permissions=True,
|
||||
)
|
||||
t.members.add(self.request.user)
|
||||
t.limit_events.add(event)
|
||||
t.log_action('pretix.team.created', user=self.request.user, data={
|
||||
'_created_by_event_wizard': True,
|
||||
'name': t.name,
|
||||
'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_organizer_permissions': False,
|
||||
'all_event_permissions': True,
|
||||
'limit_events': [event.pk],
|
||||
})
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ class BaseProcessView(AsyncAction, FormView):
|
||||
|
||||
class OrderImportView(EventPermissionRequiredMixin, BaseImportView):
|
||||
template_name = 'pretixcontrol/orders/import_start.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def get_process_url(self, request, cf, charset):
|
||||
return reverse('control:event.orders.import.process', kwargs={
|
||||
@@ -225,7 +225,7 @@ class OrderImportView(EventPermissionRequiredMixin, BaseImportView):
|
||||
|
||||
|
||||
class OrderProcessView(EventPermissionRequiredMixin, BaseProcessView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
template_name = 'pretixcontrol/orders/import_process.html'
|
||||
form_class = OrdersProcessForm
|
||||
task = import_orders
|
||||
@@ -257,7 +257,7 @@ class OrderProcessView(EventPermissionRequiredMixin, BaseProcessView):
|
||||
|
||||
class VoucherImportView(EventPermissionRequiredMixin, BaseImportView):
|
||||
template_name = 'pretixcontrol/vouchers/import_start.html'
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
|
||||
def get_process_url(self, request, cf, charset):
|
||||
return reverse('control:event.vouchers.import.process', kwargs={
|
||||
@@ -268,7 +268,7 @@ class VoucherImportView(EventPermissionRequiredMixin, BaseImportView):
|
||||
|
||||
|
||||
class VoucherProcessView(EventPermissionRequiredMixin, BaseProcessView):
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
template_name = 'pretixcontrol/vouchers/import_process.html'
|
||||
form_class = VouchersProcessForm
|
||||
task = import_vouchers
|
||||
|
||||
@@ -170,7 +170,7 @@ class OrderSearchMixin:
|
||||
|
||||
class OrderSearch(OrderSearchMixin, EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/orders/search.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
@@ -200,7 +200,7 @@ class OrderSearch(OrderSearchMixin, EventPermissionRequiredMixin, TemplateView):
|
||||
|
||||
class BaseOrderBulkActionView(OrderSearchMixin, EventPermissionRequiredMixin, AsyncFormView):
|
||||
template_name = 'pretixcontrol/orders/bulk_action.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
form_class = forms.Form
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -403,7 +403,7 @@ class OrderList(OrderSearchMixin, EventPermissionRequiredMixin, PaginationMixin,
|
||||
model = Order
|
||||
context_object_name = 'orders'
|
||||
template_name = 'pretixcontrol/orders/index.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Order.objects.filter(
|
||||
@@ -526,7 +526,7 @@ class OrderView(EventPermissionRequiredMixin, DetailView):
|
||||
|
||||
class OrderDetail(OrderView):
|
||||
template_name = 'pretixcontrol/order/index.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
@@ -626,7 +626,7 @@ class OrderDetail(OrderView):
|
||||
|
||||
class OrderTransactions(OrderView):
|
||||
template_name = 'pretixcontrol/order/transactions.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
@@ -645,7 +645,7 @@ class OrderTransactions(OrderView):
|
||||
|
||||
class OrderDownload(AsyncAction, OrderView):
|
||||
task = generate
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_success_url(self, value):
|
||||
return self.get_self_url()
|
||||
@@ -744,7 +744,7 @@ class OrderDownload(AsyncAction, OrderView):
|
||||
|
||||
|
||||
class OrderComment(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
form = CommentForm(self.request.POST)
|
||||
@@ -784,7 +784,7 @@ class OrderComment(OrderView):
|
||||
|
||||
|
||||
class OrderApprove(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
if self.order.require_approval:
|
||||
@@ -803,7 +803,7 @@ class OrderApprove(OrderView):
|
||||
|
||||
|
||||
class OrderDelete(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
if self.order.testmode:
|
||||
@@ -833,7 +833,7 @@ class OrderDelete(OrderView):
|
||||
|
||||
|
||||
class OrderDeny(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if self.order.require_approval:
|
||||
@@ -859,7 +859,7 @@ class OrderDeny(OrderView):
|
||||
|
||||
|
||||
class OrderPaymentCancel(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def payment(self):
|
||||
@@ -898,7 +898,7 @@ class OrderPaymentCancel(OrderView):
|
||||
|
||||
|
||||
class OrderRefundCancel(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def refund(self):
|
||||
@@ -928,7 +928,7 @@ class OrderRefundCancel(OrderView):
|
||||
|
||||
|
||||
class OrderRefundProcess(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def refund(self):
|
||||
@@ -967,7 +967,7 @@ class OrderRefundProcess(OrderView):
|
||||
|
||||
|
||||
class OrderRefundDone(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def refund(self):
|
||||
@@ -990,7 +990,7 @@ class OrderRefundDone(OrderView):
|
||||
|
||||
|
||||
class OrderCancellationRequestDelete(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def req(self):
|
||||
@@ -1024,7 +1024,7 @@ class OrderCancellationRequestDelete(OrderView):
|
||||
|
||||
|
||||
class OrderPaymentConfirm(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def payment(self):
|
||||
@@ -1082,7 +1082,7 @@ class OrderPaymentConfirm(OrderView):
|
||||
|
||||
|
||||
class OrderRefundView(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def start_form(self):
|
||||
@@ -1427,7 +1427,7 @@ class OrderRefundView(OrderView):
|
||||
|
||||
|
||||
class OrderTransition(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def req(self):
|
||||
@@ -1595,7 +1595,7 @@ class OrderTransition(OrderView):
|
||||
|
||||
|
||||
class OrderInvoiceCreate(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
with transaction.atomic():
|
||||
@@ -1621,7 +1621,7 @@ class OrderInvoiceCreate(OrderView):
|
||||
|
||||
|
||||
class OrderCheckVATID(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
try:
|
||||
@@ -1661,7 +1661,7 @@ class OrderCheckVATID(OrderView):
|
||||
|
||||
|
||||
class OrderInvoiceRegenerate(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
try:
|
||||
@@ -1694,7 +1694,7 @@ class OrderInvoiceRegenerate(OrderView):
|
||||
|
||||
|
||||
class OrderInvoiceRetransmit(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
with transaction.atomic(durable=True):
|
||||
@@ -1725,7 +1725,7 @@ class OrderInvoiceRetransmit(OrderView):
|
||||
|
||||
|
||||
class OrderInvoiceReissue(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
with transaction.atomic():
|
||||
@@ -1775,7 +1775,7 @@ class OrderInvoiceInspect(AdministratorPermissionRequiredMixin, OrderView):
|
||||
|
||||
|
||||
class OrderResendLink(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
try:
|
||||
@@ -1796,7 +1796,7 @@ class OrderResendLink(OrderView):
|
||||
|
||||
|
||||
class InvoiceDownload(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_order_url(self):
|
||||
return reverse('control:event.order', kwargs={
|
||||
@@ -1840,7 +1840,7 @@ class InvoiceDownload(EventPermissionRequiredMixin, View):
|
||||
|
||||
|
||||
class OrderExtend(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
if self.form.is_valid():
|
||||
@@ -1888,7 +1888,7 @@ class OrderExtend(OrderView):
|
||||
|
||||
|
||||
class OrderReactivate(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
@cached_property
|
||||
def reactivate_form(self):
|
||||
@@ -1938,7 +1938,7 @@ class OrderReactivate(OrderView):
|
||||
|
||||
|
||||
class OrderChange(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
template_name = 'pretixcontrol/order/change.html'
|
||||
|
||||
@cached_property
|
||||
@@ -2195,7 +2195,7 @@ class OrderChange(OrderView):
|
||||
|
||||
|
||||
class OrderModifyInformation(OrderQuestionsViewMixin, OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
template_name = 'pretixcontrol/order/change_questions.html'
|
||||
only_user_visible = False
|
||||
all_optional = True
|
||||
@@ -2248,7 +2248,7 @@ class OrderModifyInformation(OrderQuestionsViewMixin, OrderView):
|
||||
|
||||
|
||||
class OrderContactChange(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
template_name = 'pretixcontrol/order/change_contact.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -2263,7 +2263,7 @@ class OrderContactChange(OrderView):
|
||||
data=self.request.POST if self.request.method == "POST" else None,
|
||||
customers=self.request.organizer.settings.customer_accounts and (
|
||||
self.request.user.has_organizer_permission(
|
||||
self.request.organizer, 'can_manage_customers', request=self.request
|
||||
self.request.organizer, 'organizer.customers:write', request=self.request
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -2332,7 +2332,7 @@ class OrderContactChange(OrderView):
|
||||
|
||||
|
||||
class OrderLocaleChange(OrderView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
template_name = 'pretixcontrol/order/change_locale.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -2388,7 +2388,7 @@ class OrderViewMixin:
|
||||
|
||||
class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
|
||||
template_name = 'pretixcontrol/order/sendmail.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
form_class = OrderMailForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -2522,7 +2522,7 @@ class OrderPositionSendMail(OrderSendMail):
|
||||
|
||||
class OrderEmailHistory(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
template_name = 'pretixcontrol/order/mail_history.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
model = LogEntry
|
||||
context_object_name = 'logs'
|
||||
paginate_by = 10
|
||||
@@ -2559,7 +2559,7 @@ class OrderEmailHistory(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
|
||||
|
||||
class AnswerDownload(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
answid = kwargs.get('answer')
|
||||
@@ -2583,7 +2583,7 @@ class AnswerDownload(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
|
||||
class OverView(EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/orders/overview.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
@cached_property
|
||||
def filter_form(self):
|
||||
@@ -2622,7 +2622,7 @@ class OverView(EventPermissionRequiredMixin, TemplateView):
|
||||
|
||||
|
||||
class OrderGo(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_order(self, code):
|
||||
try:
|
||||
@@ -2707,7 +2707,7 @@ class ExportMixin:
|
||||
return ex
|
||||
|
||||
def get_scheduled_queryset(self):
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'can_change_event_settings',
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'event.settings.general:write',
|
||||
request=self.request):
|
||||
qs = self.request.event.scheduled_exports.filter(owner=self.request.user)
|
||||
else:
|
||||
@@ -2729,7 +2729,7 @@ class ExportMixin:
|
||||
|
||||
|
||||
class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, TemplateView):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
known_errortypes = ['ExportError', 'ExportEmptyError']
|
||||
task = export
|
||||
template_name = 'pretixcontrol/orders/export_form.html'
|
||||
@@ -2778,7 +2778,7 @@ class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, Templ
|
||||
|
||||
|
||||
class ExportView(EventPermissionRequiredMixin, ExportMixin, ListView):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
paginate_by = 25
|
||||
context_object_name = 'scheduled'
|
||||
|
||||
@@ -2864,7 +2864,7 @@ class ExportView(EventPermissionRequiredMixin, ExportMixin, ListView):
|
||||
return self.get_scheduled_queryset()
|
||||
|
||||
def has_permission(self):
|
||||
return self.request.user.has_event_permission(self.request.organizer, self.request.event, "can_view_orders")
|
||||
return self.request.user.has_event_permission(self.request.organizer, self.request.event, "event.orders:read")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
@@ -2890,7 +2890,7 @@ class ExportView(EventPermissionRequiredMixin, ExportMixin, ListView):
|
||||
|
||||
|
||||
class DeleteScheduledExportView(EventPermissionRequiredMixin, ExportMixin, CompatDeleteView):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
template_name = 'pretixcontrol/orders/export_delete.html'
|
||||
context_object_name = 'export'
|
||||
|
||||
@@ -2939,7 +2939,7 @@ class RefundList(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
model = OrderRefund
|
||||
context_object_name = 'refunds'
|
||||
template_name = 'pretixcontrol/orders/refunds.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = OrderRefund.objects.filter(
|
||||
@@ -2964,7 +2964,7 @@ class RefundList(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
|
||||
class EventCancel(EventPermissionRequiredMixin, AsyncAction, FormView):
|
||||
template_name = 'pretixcontrol/orders/cancel.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
form_class = EventCancelForm
|
||||
task = cancel_event
|
||||
known_errortypes = ['OrderError']
|
||||
@@ -3049,7 +3049,7 @@ class EventCancel(EventPermissionRequiredMixin, AsyncAction, FormView):
|
||||
|
||||
class EventCancelConfirm(EventPermissionRequiredMixin, AsyncAction, FormView):
|
||||
template_name = 'pretixcontrol/orders/cancel_confirm.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
form_class = EventCancelConfirmForm
|
||||
task = cancel_event
|
||||
known_errortypes = ['OrderError']
|
||||
|
||||
@@ -95,7 +95,9 @@ from pretix.base.models.giftcards import (
|
||||
GiftCardAcceptance, GiftCardTransaction, gen_giftcard_secret,
|
||||
)
|
||||
from pretix.base.models.orders import CancellationRequest
|
||||
from pretix.base.models.organizer import SalesChannel, TeamAPIToken
|
||||
from pretix.base.models.organizer import (
|
||||
SalesChannel, TeamAPIToken, TeamQuerySet,
|
||||
)
|
||||
from pretix.base.payment import PaymentException
|
||||
from pretix.base.plugins import (
|
||||
PLUGIN_LEVEL_EVENT, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID,
|
||||
@@ -242,13 +244,13 @@ class OrganizerDetail(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
|
||||
class OrganizerTeamView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
|
||||
model = Organizer
|
||||
template_name = 'pretixcontrol/organizers/teams.html'
|
||||
permission = 'can_change_permissions'
|
||||
permission = 'organizer.teams:write'
|
||||
context_object_name = 'organizer'
|
||||
|
||||
|
||||
class OrganizerSettingsFormView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, FormView):
|
||||
model = Organizer
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
@@ -279,7 +281,7 @@ class OrganizerSettingsFormView(OrganizerDetailViewMixin, OrganizerPermissionReq
|
||||
class OrganizerMailSettings(OrganizerSettingsFormView):
|
||||
form_class = MailSettingsForm
|
||||
template_name = 'pretixcontrol/organizers/mail.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('control:organizer.settings.mail', kwargs={
|
||||
@@ -305,7 +307,7 @@ class OrganizerMailSettings(OrganizerSettingsFormView):
|
||||
|
||||
|
||||
class MailSettingsSetup(OrganizerPermissionRequiredMixin, MailSettingsSetupView):
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
basetpl = 'pretixcontrol/base.html'
|
||||
|
||||
def get_success_url(self):
|
||||
@@ -320,7 +322,7 @@ class MailSettingsSetup(OrganizerPermissionRequiredMixin, MailSettingsSetupView)
|
||||
|
||||
|
||||
class MailSettingsPreview(OrganizerPermissionRequiredMixin, View):
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
|
||||
# return the origin text if key is missing in dict
|
||||
class SafeDict(dict):
|
||||
@@ -452,7 +454,7 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = Organizer
|
||||
form_class = OrganizerUpdateForm
|
||||
template_name = 'pretixcontrol/organizers/edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'organizer'
|
||||
|
||||
@cached_property
|
||||
@@ -580,10 +582,7 @@ class OrganizerCreate(CreateView):
|
||||
ret = super().form_valid(form)
|
||||
t = Team.objects.create(
|
||||
organizer=form.instance, name=_('Administrators'),
|
||||
all_events=True, can_create_events=True, can_change_teams=True, can_manage_gift_cards=True,
|
||||
can_change_organizer_settings=True, can_change_event_settings=True, can_change_items=True,
|
||||
can_manage_customers=True, can_manage_reusable_media=True,
|
||||
can_view_orders=True, can_change_orders=True, can_view_vouchers=True, can_change_vouchers=True
|
||||
all_events=True, all_event_permissions=True, all_organizer_permissions=True,
|
||||
)
|
||||
t.members.add(self.request.user)
|
||||
return ret
|
||||
@@ -597,7 +596,7 @@ class OrganizerCreate(CreateView):
|
||||
class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, TemplateView, SingleObjectMixin):
|
||||
model = Organizer
|
||||
context_object_name = 'organizer'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
template_name = 'pretixcontrol/organizers/plugins.html'
|
||||
|
||||
def get_object(self, queryset=None) -> Organizer:
|
||||
@@ -769,14 +768,14 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
||||
class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, FormView):
|
||||
model = Organizer
|
||||
context_object_name = 'organizer'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
template_name = 'pretixcontrol/organizers/plugin_events.html'
|
||||
form_class = OrganizerPluginEventsForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["events"] = self.request.user.get_events_with_permission(
|
||||
"can_change_event_settings", request=self.request
|
||||
"event.settings.general:write", request=self.request
|
||||
).filter(organizer=self.request.organizer)
|
||||
kwargs["initial"] = {
|
||||
"events": self.request.organizer.events.filter(plugins__regex='(^|,)' + self.plugin.module + '(,|$)')
|
||||
@@ -854,7 +853,7 @@ class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequire
|
||||
class TeamListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
model = Team
|
||||
template_name = 'pretixcontrol/organizers/teams.html'
|
||||
permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
context_object_name = 'teams'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -880,7 +879,7 @@ class TeamListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, P
|
||||
class TeamCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = Team
|
||||
template_name = 'pretixcontrol/organizers/team_edit.html'
|
||||
permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
form_class = TeamForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -917,7 +916,7 @@ class TeamCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
class TeamUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = Team
|
||||
template_name = 'pretixcontrol/organizers/team_edit.html'
|
||||
permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
context_object_name = 'team'
|
||||
form_class = TeamForm
|
||||
|
||||
@@ -953,7 +952,7 @@ class TeamUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
class TeamDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Team
|
||||
template_name = 'pretixcontrol/organizers/team_delete.html'
|
||||
permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
context_object_name = 'team'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -971,7 +970,8 @@ class TeamDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
|
||||
def is_allowed(self) -> bool:
|
||||
return self.request.organizer.teams.exclude(pk=self.kwargs.get('team')).filter(
|
||||
can_change_teams=True, members__isnull=False
|
||||
TeamQuerySet.organizer_permission_q("organizer.teams:write"),
|
||||
members__isnull=False
|
||||
).exists() or self.request.user.has_active_staff_session(self.request.session.session_key)
|
||||
|
||||
@transaction.atomic
|
||||
@@ -1012,7 +1012,7 @@ class TeamDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
class TeamMemberView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
|
||||
template_name = 'pretixcontrol/organizers/team_members.html'
|
||||
context_object_name = 'team'
|
||||
permission = 'can_change_teams'
|
||||
permission = 'organizer.teams:write'
|
||||
model = Team
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -1066,9 +1066,10 @@ class TeamMemberView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
pass
|
||||
else:
|
||||
other_admin_teams = self.request.organizer.teams.exclude(pk=self.object.pk).filter(
|
||||
can_change_teams=True, members__isnull=False
|
||||
TeamQuerySet.organizer_permission_q("organizer.teams:write"),
|
||||
members__isnull=False
|
||||
).exists() or self.request.user.has_active_staff_session(self.request.session.session_key)
|
||||
if not other_admin_teams and self.object.can_change_teams 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 '
|
||||
'be left with the permission to change teams.'))
|
||||
return redirect(self.get_success_url())
|
||||
@@ -1232,7 +1233,7 @@ class DeviceQueryMixin:
|
||||
class DeviceListView(DeviceQueryMixin, OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = Device
|
||||
template_name = 'pretixcontrol/organizers/devices.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'devices'
|
||||
paginate_by = 100
|
||||
|
||||
@@ -1245,7 +1246,7 @@ class DeviceListView(DeviceQueryMixin, OrganizerDetailViewMixin, OrganizerPermis
|
||||
class DeviceCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = Device
|
||||
template_name = 'pretixcontrol/organizers/device_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = DeviceForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -1276,7 +1277,7 @@ class DeviceCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
||||
|
||||
class DeviceLogView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
template_name = 'pretixcontrol/organizers/device_logs.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
model = LogEntry
|
||||
context_object_name = 'logs'
|
||||
paginate_by = 20
|
||||
@@ -1304,7 +1305,7 @@ class DeviceLogView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
class DeviceUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = Device
|
||||
template_name = 'pretixcontrol/organizers/device_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'device'
|
||||
form_class = DeviceForm
|
||||
|
||||
@@ -1347,7 +1348,7 @@ class DeviceUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
||||
|
||||
class DeviceBulkUpdateView(DeviceQueryMixin, OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, FormView):
|
||||
template_name = 'pretixcontrol/organizers/device_bulk_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'device'
|
||||
form_class = DeviceBulkEditForm
|
||||
|
||||
@@ -1461,7 +1462,7 @@ class DeviceBulkUpdateView(DeviceQueryMixin, OrganizerDetailViewMixin, Organizer
|
||||
class DeviceConnectView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
|
||||
model = Device
|
||||
template_name = 'pretixcontrol/organizers/device_connect.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'device'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -1493,7 +1494,7 @@ class DeviceConnectView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
|
||||
class DeviceRevokeView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
|
||||
model = Device
|
||||
template_name = 'pretixcontrol/organizers/device_revoke.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'device'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -1523,7 +1524,7 @@ class DeviceRevokeView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
||||
class WebHookListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = WebHook
|
||||
template_name = 'pretixcontrol/organizers/webhooks.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'webhooks'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -1533,7 +1534,7 @@ class WebHookListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
|
||||
class WebHookCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = WebHook
|
||||
template_name = 'pretixcontrol/organizers/webhook_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = WebHookForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -1567,7 +1568,7 @@ class WebHookCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
|
||||
class WebHookUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = WebHook
|
||||
template_name = 'pretixcontrol/organizers/webhook_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'webhook'
|
||||
form_class = WebHookForm
|
||||
|
||||
@@ -1610,7 +1611,7 @@ class WebHookUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
|
||||
class WebHookLogsView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = WebHook
|
||||
template_name = 'pretixcontrol/organizers/webhook_logs.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'calls'
|
||||
paginate_by = 50
|
||||
|
||||
@@ -1652,7 +1653,7 @@ class WebHookLogsView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
|
||||
class GiftCardAcceptanceInviteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, FormView):
|
||||
model = GiftCardAcceptance
|
||||
template_name = 'pretixcontrol/organizers/giftcard_acceptance_invite.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = GiftCardAcceptanceInviteForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -1682,7 +1683,7 @@ class GiftCardAcceptanceInviteView(OrganizerDetailViewMixin, OrganizerPermission
|
||||
class GiftCardAcceptanceListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = GiftCardAcceptance
|
||||
template_name = 'pretixcontrol/organizers/giftcard_acceptance_list.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'acceptor_acceptance'
|
||||
paginate_by = 50
|
||||
|
||||
@@ -1742,7 +1743,7 @@ class GiftCardAcceptanceListView(OrganizerDetailViewMixin, OrganizerPermissionRe
|
||||
class GiftCardListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = GiftCard
|
||||
template_name = 'pretixcontrol/organizers/giftcards.html'
|
||||
permission = 'can_manage_gift_cards'
|
||||
permission = 'organizer.giftcards:read'
|
||||
context_object_name = 'giftcards'
|
||||
paginate_by = 50
|
||||
|
||||
@@ -1765,7 +1766,7 @@ class GiftCardListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['filter_form'] = self.filter_form
|
||||
ctx['other_organizers'] = self.request.user.get_organizers_with_permission(
|
||||
'can_manage_gift_cards', self.request
|
||||
'organizer.giftcards:write', self.request
|
||||
).exclude(pk=self.request.organizer.pk)
|
||||
return ctx
|
||||
|
||||
@@ -1776,7 +1777,7 @@ class GiftCardListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
||||
|
||||
class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
|
||||
template_name = 'pretixcontrol/organizers/giftcard.html'
|
||||
permission = 'can_manage_gift_cards'
|
||||
permission = 'organizer.giftcards:read'
|
||||
context_object_name = 'card'
|
||||
|
||||
def get_object(self, queryset=None) -> Organizer:
|
||||
@@ -1787,6 +1788,8 @@ class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
|
||||
@transaction.atomic()
|
||||
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)
|
||||
if 'revert' in request.POST:
|
||||
t = get_object_or_404(self.object.transactions.all(), pk=request.POST.get('revert'), order__isnull=False)
|
||||
@@ -1866,7 +1869,7 @@ class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
|
||||
class GiftCardCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
template_name = 'pretixcontrol/organizers/giftcard_create.html'
|
||||
permission = 'can_manage_gift_cards'
|
||||
permission = 'organizer.giftcards:write'
|
||||
form_class = GiftCardCreateForm
|
||||
success_url = 'invalid'
|
||||
|
||||
@@ -1908,7 +1911,7 @@ class GiftCardCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
|
||||
class GiftCardUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
template_name = 'pretixcontrol/organizers/giftcard_edit.html'
|
||||
permission = 'can_manage_gift_cards'
|
||||
permission = 'organizer.giftcards:write'
|
||||
form_class = GiftCardUpdateForm
|
||||
success_url = 'invalid'
|
||||
context_object_name = 'card'
|
||||
@@ -1999,7 +2002,7 @@ class ExportMixin:
|
||||
|
||||
@cached_property
|
||||
def events(self):
|
||||
return self.request.user.get_events_with_permission('can_view_orders', request=self.request).filter(
|
||||
return self.request.user.get_events_with_permission('event.orders:read', request=self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
|
||||
@@ -2033,7 +2036,7 @@ class ExportMixin:
|
||||
return ctx
|
||||
|
||||
def get_scheduled_queryset(self):
|
||||
if not self.request.user.has_organizer_permission(self.request.organizer, 'can_change_organizer_settings',
|
||||
if not self.request.user.has_organizer_permission(self.request.organizer, 'organizer.settings.general:write',
|
||||
request=self.request):
|
||||
qs = self.request.organizer.scheduled_exports.filter(owner=self.request.user)
|
||||
else:
|
||||
@@ -2267,7 +2270,7 @@ class RunScheduledExportView(OrganizerPermissionRequiredMixin, ExportMixin, View
|
||||
class GateListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = Gate
|
||||
template_name = 'pretixcontrol/organizers/gates.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'gates'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -2277,7 +2280,7 @@ class GateListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, L
|
||||
class GateCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = Gate
|
||||
template_name = 'pretixcontrol/organizers/gate_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = GateForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -2311,7 +2314,7 @@ class GateCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
class GateUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = Gate
|
||||
template_name = 'pretixcontrol/organizers/gate_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'gate'
|
||||
form_class = GateForm
|
||||
|
||||
@@ -2346,7 +2349,7 @@ class GateUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
class GateDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Gate
|
||||
template_name = 'pretixcontrol/organizers/gate_delete.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'gate'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2370,7 +2373,7 @@ class GateDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
||||
class EventMetaPropertyListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = EventMetaProperty
|
||||
template_name = 'pretixcontrol/organizers/properties.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'properties'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -2421,7 +2424,7 @@ class EventMetaPropertyEditorMixin:
|
||||
|
||||
class EventMetaPropertyCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, EventMetaPropertyEditorMixin, CreateView):
|
||||
model = EventMetaProperty
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return EventMetaProperty()
|
||||
@@ -2451,7 +2454,7 @@ class EventMetaPropertyCreateView(OrganizerDetailViewMixin, OrganizerPermissionR
|
||||
|
||||
class EventMetaPropertyUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, EventMetaPropertyEditorMixin, UpdateView):
|
||||
model = EventMetaProperty
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'property'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2483,7 +2486,7 @@ class EventMetaPropertyUpdateView(OrganizerDetailViewMixin, OrganizerPermissionR
|
||||
class EventMetaPropertyDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
model = EventMetaProperty
|
||||
template_name = 'pretixcontrol/organizers/property_delete.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'property'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2527,7 +2530,7 @@ def meta_property_move(request, property, up=True):
|
||||
messages.success(request, _('The order of properties has been updated.'))
|
||||
|
||||
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@organizer_permission_required("organizer.settings.general:write")
|
||||
@require_http_methods(["POST"])
|
||||
def meta_property_move_up(request, organizer, property):
|
||||
meta_property_move(request, property, up=True)
|
||||
@@ -2535,7 +2538,7 @@ def meta_property_move_up(request, organizer, property):
|
||||
organizer=request.organizer.slug)
|
||||
|
||||
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@organizer_permission_required("organizer.settings.general:write")
|
||||
@require_http_methods(["POST"])
|
||||
def meta_property_move_down(request, organizer, property):
|
||||
meta_property_move(request, property, up=False)
|
||||
@@ -2544,7 +2547,7 @@ def meta_property_move_down(request, organizer, property):
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@organizer_permission_required("organizer.settings.general:write")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_meta_properties(request, organizer):
|
||||
try:
|
||||
@@ -2576,7 +2579,7 @@ def reorder_meta_properties(request, organizer):
|
||||
|
||||
class LogView(OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
template_name = 'pretixcontrol/organizers/logs.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
model = LogEntry
|
||||
context_object_name = 'logs'
|
||||
|
||||
@@ -2601,7 +2604,7 @@ class LogView(OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
class MembershipTypeListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = MembershipType
|
||||
template_name = 'pretixcontrol/organizers/membershiptypes.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'types'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -2611,7 +2614,7 @@ class MembershipTypeListView(OrganizerDetailViewMixin, OrganizerPermissionRequir
|
||||
class MembershipTypeCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = MembershipType
|
||||
template_name = 'pretixcontrol/organizers/membershiptype_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = MembershipTypeForm
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2645,7 +2648,7 @@ class MembershipTypeCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequ
|
||||
class MembershipTypeUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = MembershipType
|
||||
template_name = 'pretixcontrol/organizers/membershiptype_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'type'
|
||||
form_class = MembershipTypeForm
|
||||
|
||||
@@ -2680,7 +2683,7 @@ class MembershipTypeUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequ
|
||||
class MembershipTypeDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
model = MembershipType
|
||||
template_name = 'pretixcontrol/organizers/membershiptype_delete.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'type'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2710,7 +2713,7 @@ class MembershipTypeDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequ
|
||||
class SSOProviderListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = CustomerSSOProvider
|
||||
template_name = 'pretixcontrol/organizers/ssoproviders.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'providers'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -2720,7 +2723,7 @@ class SSOProviderListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredM
|
||||
class SSOProviderCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = CustomerSSOProvider
|
||||
template_name = 'pretixcontrol/organizers/ssoprovider_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = SSOProviderForm
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2754,7 +2757,7 @@ class SSOProviderCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequire
|
||||
class SSOProviderUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = CustomerSSOProvider
|
||||
template_name = 'pretixcontrol/organizers/ssoprovider_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'provider'
|
||||
form_class = SSOProviderForm
|
||||
|
||||
@@ -2796,7 +2799,7 @@ class SSOProviderUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequire
|
||||
class SSOProviderDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
model = CustomerSSOProvider
|
||||
template_name = 'pretixcontrol/organizers/ssoprovider_delete.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'provider'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2826,7 +2829,7 @@ class SSOProviderDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequire
|
||||
class SSOClientListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = CustomerSSOClient
|
||||
template_name = 'pretixcontrol/organizers/ssoclients.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'clients'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -2836,7 +2839,7 @@ class SSOClientListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
|
||||
class SSOClientCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = CustomerSSOClient
|
||||
template_name = 'pretixcontrol/organizers/ssoclient_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = SSOClientForm
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2876,7 +2879,7 @@ class SSOClientCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredM
|
||||
class SSOClientUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
model = CustomerSSOClient
|
||||
template_name = 'pretixcontrol/organizers/ssoclient_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'client'
|
||||
form_class = SSOClientForm
|
||||
|
||||
@@ -2926,7 +2929,7 @@ class SSOClientUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredM
|
||||
class SSOClientDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
model = CustomerSSOClient
|
||||
template_name = 'pretixcontrol/organizers/ssoclient_delete.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'client'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -2956,7 +2959,7 @@ class SSOClientDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredM
|
||||
class CustomerListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
model = Customer
|
||||
template_name = 'pretixcontrol/organizers/customers.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'customers'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -2977,7 +2980,7 @@ class CustomerListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
||||
|
||||
class CustomerDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
template_name = 'pretixcontrol/organizers/customer.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'orders'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -3092,7 +3095,7 @@ class CustomerDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
|
||||
class CustomerCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
template_name = 'pretixcontrol/organizers/customer_edit.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'customer'
|
||||
form_class = CustomerCreateForm
|
||||
|
||||
@@ -3122,7 +3125,7 @@ class CustomerCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
|
||||
class CustomerUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
template_name = 'pretixcontrol/organizers/customer_edit.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'customer'
|
||||
form_class = CustomerUpdateForm
|
||||
|
||||
@@ -3151,7 +3154,7 @@ class CustomerUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
|
||||
class MembershipUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
template_name = 'pretixcontrol/organizers/customer_membership.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'membership'
|
||||
form_class = MembershipUpdateForm
|
||||
|
||||
@@ -3191,7 +3194,7 @@ class MembershipUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequired
|
||||
|
||||
class MembershipDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
template_name = 'pretixcontrol/organizers/customer_membership_delete.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'membership'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -3229,7 +3232,7 @@ class MembershipDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequired
|
||||
|
||||
class MembershipCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
template_name = 'pretixcontrol/organizers/customer_membership.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'membership'
|
||||
form_class = MembershipUpdateForm
|
||||
|
||||
@@ -3268,7 +3271,7 @@ class MembershipCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequired
|
||||
|
||||
class CustomerAnonymizeView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
|
||||
template_name = 'pretixcontrol/organizers/customer_anonymize.html'
|
||||
permission = 'can_manage_customers'
|
||||
permission = 'organizer.customers:write'
|
||||
context_object_name = 'customer'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -3295,7 +3298,7 @@ class CustomerAnonymizeView(OrganizerDetailViewMixin, OrganizerPermissionRequire
|
||||
class ReusableMediaListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
model = ReusableMedium
|
||||
template_name = 'pretixcontrol/organizers/reusable_media.html'
|
||||
permission = 'can_manage_reusable_media'
|
||||
permission = 'organizer.reusablemedia:read'
|
||||
context_object_name = 'media'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -3319,7 +3322,7 @@ class ReusableMediaListView(OrganizerDetailViewMixin, OrganizerPermissionRequire
|
||||
|
||||
class ReusableMediumDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/organizers/reusable_medium.html'
|
||||
permission = 'can_manage_reusable_media'
|
||||
permission = 'organizer.reusablemedia:read'
|
||||
|
||||
@cached_property
|
||||
def medium(self):
|
||||
@@ -3336,7 +3339,7 @@ class ReusableMediumDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequ
|
||||
|
||||
class ReusableMediumCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
template_name = 'pretixcontrol/organizers/reusable_medium_edit.html'
|
||||
permission = 'can_manage_reusable_media'
|
||||
permission = 'organizer.reusablemedia:write'
|
||||
context_object_name = 'medium'
|
||||
form_class = ReusableMediumCreateForm
|
||||
|
||||
@@ -3365,7 +3368,7 @@ class ReusableMediumCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequ
|
||||
|
||||
class ReusableMediumUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
template_name = 'pretixcontrol/organizers/reusable_medium_edit.html'
|
||||
permission = 'can_manage_reusable_media'
|
||||
permission = 'organizer.reusablemedia:write'
|
||||
context_object_name = 'medium'
|
||||
form_class = ReusableMediumUpdateForm
|
||||
|
||||
@@ -3395,7 +3398,7 @@ class ReusableMediumUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequ
|
||||
class ChannelListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
model = SalesChannel
|
||||
template_name = 'pretixcontrol/organizers/channels.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'channels'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -3414,7 +3417,7 @@ class ChannelEditorMixin:
|
||||
|
||||
class ChannelCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ChannelEditorMixin, CreateView):
|
||||
model = SalesChannel
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
template_name = 'pretixcontrol/organizers/channel_add.html'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -3486,7 +3489,7 @@ class ChannelCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
|
||||
|
||||
class ChannelUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ChannelEditorMixin, UpdateView):
|
||||
model = SalesChannel
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'channel'
|
||||
template_name = 'pretixcontrol/organizers/channel_edit.html'
|
||||
|
||||
@@ -3531,7 +3534,7 @@ class ChannelUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
|
||||
class ChannelDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
|
||||
model = SalesChannel
|
||||
template_name = 'pretixcontrol/organizers/channel_delete.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
context_object_name = 'channel'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
@@ -3587,7 +3590,7 @@ def channel_move(request, channel, up=True):
|
||||
messages.success(request, _('The order of sales channels has been updated.'))
|
||||
|
||||
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@organizer_permission_required("organizer.settings.general:write")
|
||||
@require_http_methods(["POST"])
|
||||
def channel_move_up(request, organizer, channel):
|
||||
channel_move(request, channel, up=True)
|
||||
@@ -3595,7 +3598,7 @@ def channel_move_up(request, organizer, channel):
|
||||
organizer=request.organizer.slug)
|
||||
|
||||
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@organizer_permission_required("organizer.settings.general:write")
|
||||
@require_http_methods(["POST"])
|
||||
def channel_move_down(request, organizer, channel):
|
||||
channel_move(request, channel, up=False)
|
||||
@@ -3604,7 +3607,7 @@ def channel_move_down(request, organizer, channel):
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@organizer_permission_required("organizer.settings.general:write")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_channels(request, organizer):
|
||||
try:
|
||||
|
||||
@@ -58,7 +58,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/pdf/index.html'
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
accepted_formats = (
|
||||
'application/pdf',
|
||||
)
|
||||
|
||||
@@ -85,7 +85,7 @@ class OrderSearch(PaginationMixin, ListView):
|
||||
|
||||
if not self.request.user.has_active_staff_session(self.request.session.session_key):
|
||||
qs = qs.filter(
|
||||
Q(event_id__in=self.request.user.get_events_with_permission('can_view_orders').values_list('id', flat=True))
|
||||
Q(event_id__in=self.request.user.get_events_with_permission('event.orders:read').values_list('id', flat=True))
|
||||
)
|
||||
|
||||
if self.filter_form.is_valid():
|
||||
@@ -159,7 +159,7 @@ class PaymentSearch(PaginationMixin, ListView):
|
||||
|
||||
if not self.request.user.has_active_staff_session(self.request.session.session_key):
|
||||
qs = qs.filter(
|
||||
Q(order__event_id__in=self.request.user.get_events_with_permission('can_view_orders').values_list('id', flat=True))
|
||||
Q(order__event_id__in=self.request.user.get_events_with_permission('event.orders:read').values_list('id', flat=True))
|
||||
)
|
||||
|
||||
if self.filter_form.is_valid():
|
||||
|
||||
@@ -76,7 +76,7 @@ class ShredderMixin:
|
||||
|
||||
|
||||
class StartShredView(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, ShredderMixin, TemplateView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
template_name = 'pretixcontrol/shredder/index.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -87,7 +87,7 @@ class StartShredView(RecentAuthenticationRequiredMixin, EventPermissionRequiredM
|
||||
|
||||
|
||||
class ShredDownloadView(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, ShredderMixin, TemplateView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
template_name = 'pretixcontrol/shredder/download.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -119,7 +119,7 @@ class ShredDownloadView(RecentAuthenticationRequiredMixin, EventPermissionRequir
|
||||
|
||||
|
||||
class ShredExportView(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, ShredderMixin, AsyncAction, View):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
task = export
|
||||
known_errortypes = ['ShredError']
|
||||
|
||||
@@ -148,7 +148,7 @@ class ShredExportView(RecentAuthenticationRequiredMixin, EventPermissionRequired
|
||||
|
||||
|
||||
class ShredDoView(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, ShredderMixin, AsyncAction, View):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
task = shred
|
||||
known_errortypes = ['ShredError']
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class SubEventList(EventPermissionRequiredMixin, PaginationMixin, SubEventQueryM
|
||||
model = SubEvent
|
||||
context_object_name = 'subevents'
|
||||
template_name = 'pretixcontrol/subevents/index.html'
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset(True).prefetch_related(
|
||||
@@ -156,7 +156,7 @@ class SubEventList(EventPermissionRequiredMixin, PaginationMixin, SubEventQueryM
|
||||
class SubEventDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = SubEvent
|
||||
template_name = 'pretixcontrol/subevents/delete.html'
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'subevents'
|
||||
|
||||
def get_object(self, queryset=None) -> SubEvent:
|
||||
@@ -241,7 +241,7 @@ class SubEventEditorMixin(MetaDataEditorMixin):
|
||||
property=p,
|
||||
disabled=(
|
||||
p.protected and
|
||||
not self.request.user.has_organizer_permission(self.request.organizer, 'can_change_organizer_settings', request=self.request)
|
||||
not self.request.user.has_organizer_permission(self.request.organizer, 'organizer.settings.general:write', request=self.request)
|
||||
),
|
||||
default=self._default_meta.get(p.name, ''),
|
||||
instance=val_instances.get(p.pk, self.meta_model(property=p, subevent=self.object)),
|
||||
@@ -508,7 +508,7 @@ class SubEventEditorMixin(MetaDataEditorMixin):
|
||||
class SubEventUpdate(EventPermissionRequiredMixin, SubEventEditorMixin, UpdateView):
|
||||
model = SubEvent
|
||||
template_name = 'pretixcontrol/subevents/detail.html'
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'subevent'
|
||||
form_class = SubEventForm
|
||||
|
||||
@@ -575,7 +575,7 @@ class SubEventUpdate(EventPermissionRequiredMixin, SubEventEditorMixin, UpdateVi
|
||||
class SubEventCreate(SubEventEditorMixin, EventPermissionRequiredMixin, CreateView):
|
||||
model = SubEvent
|
||||
template_name = 'pretixcontrol/subevents/detail.html'
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'subevent'
|
||||
form_class = SubEventForm
|
||||
|
||||
@@ -669,7 +669,7 @@ class SubEventCreate(SubEventEditorMixin, EventPermissionRequiredMixin, CreateVi
|
||||
|
||||
|
||||
class SubEventBulkAction(SubEventQueryMixin, EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
@transaction.atomic
|
||||
def post(self, request, *args, **kwargs):
|
||||
@@ -740,7 +740,7 @@ class SubEventBulkAction(SubEventQueryMixin, EventPermissionRequiredMixin, View)
|
||||
class SubEventBulkCreate(SubEventEditorMixin, EventPermissionRequiredMixin, AsyncFormView):
|
||||
model = SubEvent
|
||||
template_name = 'pretixcontrol/subevents/bulk.html'
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'subevent'
|
||||
form_class = SubEventBulkForm
|
||||
itemformclass = BulkSubEventItemForm
|
||||
@@ -1065,7 +1065,7 @@ class SubEventBulkCreate(SubEventEditorMixin, EventPermissionRequiredMixin, Asyn
|
||||
|
||||
|
||||
class SubEventBulkEdit(SubEventQueryMixin, EventPermissionRequiredMixin, FormView):
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
form_class = SubEventBulkEditForm
|
||||
template_name = 'pretixcontrol/subevents/bulk_edit.html'
|
||||
context_object_name = 'subevent'
|
||||
|
||||
@@ -51,6 +51,7 @@ from pretix.base.models import (
|
||||
ItemVariation, ItemVariationMetaValue, Order, OrderPosition, Organizer,
|
||||
SubEventMetaValue, User, Voucher,
|
||||
)
|
||||
from pretix.base.models.organizer import TeamQuerySet
|
||||
from pretix.control.forms.event import EventWizardCopyForm
|
||||
from pretix.control.permissions import (
|
||||
event_permission_required, organizer_permission_required,
|
||||
@@ -172,7 +173,7 @@ def event_list(request):
|
||||
return JsonResponse(doc)
|
||||
|
||||
|
||||
@organizer_permission_required(("can_manage_gift_cards", "can_manage_reusable_media"))
|
||||
@organizer_permission_required(("organizer.giftcards:read", "organizer.reusablemedia:write"))
|
||||
def giftcard_select2(request, **kwargs):
|
||||
query = request.GET.get('query', '')
|
||||
try:
|
||||
@@ -180,7 +181,7 @@ def giftcard_select2(request, **kwargs):
|
||||
except ValueError:
|
||||
page = 1
|
||||
|
||||
if request.user.has_organizer_permission(request.organizer, 'can_manage_gift_cards', request):
|
||||
if request.user.has_organizer_permission(request.organizer, 'organizer.giftcards:write', request):
|
||||
qs = request.organizer.issued_gift_cards.filter(
|
||||
Q(secret__icontains=query)
|
||||
).order_by('secret')
|
||||
@@ -210,7 +211,7 @@ def giftcard_select2(request, **kwargs):
|
||||
return JsonResponse(doc)
|
||||
|
||||
|
||||
@organizer_permission_required(("can_manage_reusable_media", "can_manage_gift_cards"))
|
||||
@organizer_permission_required(("organizer.reusablemedia:write", "organizer.giftcards:write"))
|
||||
def ticket_select2(request, **kwargs):
|
||||
query = request.GET.get('query', '')
|
||||
try:
|
||||
@@ -240,8 +241,13 @@ def ticket_select2(request, **kwargs):
|
||||
qs_orders = qs_orders.filter(
|
||||
exact_match | (
|
||||
soft_match & (
|
||||
Q(order__event__organizer_id__in=request.user.teams.filter(all_events=True, can_view_orders=True).values_list('organizer', flat=True))
|
||||
| Q(order__event_id__in=request.user.teams.filter(can_view_orders=True).values_list('limit_events__id', flat=True))
|
||||
Q(order__event__organizer_id__in=request.user.teams.filter(
|
||||
TeamQuerySet.event_permission_q("event.orders:read"),
|
||||
all_events=True,
|
||||
).values_list('organizer', flat=True))
|
||||
| Q(order__event_id__in=request.user.teams.filter(
|
||||
TeamQuerySet.event_permission_q("event.orders:read")
|
||||
).values_list('limit_events__id', flat=True))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -270,7 +276,7 @@ def ticket_select2(request, **kwargs):
|
||||
return JsonResponse(doc)
|
||||
|
||||
|
||||
@organizer_permission_required("can_manage_customers")
|
||||
@organizer_permission_required("organizer.customers:write")
|
||||
def customer_select2(request, **kwargs):
|
||||
query = request.GET.get('query', '')
|
||||
try:
|
||||
@@ -337,9 +343,9 @@ def nav_context_list(request):
|
||||
if not request.user.has_active_staff_session(request.session.session_key):
|
||||
qs_orders = qs_orders.filter(
|
||||
Q(event__organizer_id__in=request.user.teams.filter(
|
||||
all_events=True, can_view_orders=True).values_list('organizer', flat=True))
|
||||
TeamQuerySet.event_permission_q("event.orders:read"), all_events=True).values_list('organizer', flat=True))
|
||||
| Q(event_id__in=request.user.teams.filter(
|
||||
can_view_orders=True).values_list('limit_events__id', flat=True))
|
||||
TeamQuerySet.event_permission_q("event.orders:read")).values_list('limit_events__id', flat=True))
|
||||
)
|
||||
|
||||
qs_vouchers = Voucher.objects.filter(
|
||||
@@ -348,9 +354,9 @@ def nav_context_list(request):
|
||||
if not request.user.has_active_staff_session(request.session.session_key):
|
||||
qs_vouchers = qs_vouchers.filter(
|
||||
Q(event__organizer_id__in=request.user.teams.filter(
|
||||
all_events=True, can_view_vouchers=True).values_list('organizer', flat=True))
|
||||
TeamQuerySet.event_permission_q("event.vouchers:read"), all_events=True).values_list('organizer', flat=True))
|
||||
| Q(event_id__in=request.user.teams.filter(
|
||||
can_view_vouchers=True).values_list('limit_events__id', flat=True))
|
||||
TeamQuerySet.event_permission_q("event.vouchers:read")).values_list('limit_events__id', flat=True))
|
||||
)
|
||||
else:
|
||||
qs_vouchers = Voucher.objects.none()
|
||||
@@ -813,7 +819,7 @@ def organizer_select2(request):
|
||||
qs = qs.filter(Q(name__icontains=term) | Q(slug__icontains=term))
|
||||
if not request.user.has_active_staff_session(request.session.session_key):
|
||||
if 'can_create' in request.GET:
|
||||
qs = qs.filter(pk__in=request.user.teams.filter(can_create_events=True).values_list('organizer', flat=True))
|
||||
qs = qs.filter(pk__in=request.user.teams.filter(TeamQuerySet.organizer_permission_q("organizer.events:create")).values_list('organizer', flat=True))
|
||||
else:
|
||||
qs = qs.filter(pk__in=request.user.teams.values_list('organizer', flat=True))
|
||||
|
||||
@@ -976,21 +982,21 @@ def item_meta_values(request, organizer, event):
|
||||
var_matches = var_matches.filter(variation__item__event__organizer_id=organizer.pk)
|
||||
all_access = (
|
||||
request.user.has_active_staff_session(request.session.session_key)
|
||||
or request.user.teams.filter(all_events=True, organizer=organizer, can_change_items=True).exists()
|
||||
or request.user.teams.filter(TeamQuerySet.event_permission_q("event.items:write"), all_events=True, organizer=organizer).exists()
|
||||
)
|
||||
if not all_access:
|
||||
defaults = defaults.filter(
|
||||
event__id__in=request.user.teams.filter(can_change_items=True).values_list(
|
||||
event__id__in=request.user.teams.filter(TeamQuerySet.event_permission_q("event.items:write")).values_list(
|
||||
'limit_events__id', flat=True
|
||||
)
|
||||
)
|
||||
matches = matches.filter(
|
||||
item__event__id__in=request.user.teams.filter(can_change_items=True).values_list(
|
||||
item__event__id__in=request.user.teams.filter(TeamQuerySet.event_permission_q("event.items:write")).values_list(
|
||||
'limit_events__id', flat=True
|
||||
)
|
||||
)
|
||||
var_matches = var_matches.filter(
|
||||
variation__item__event__id__in=request.user.teams.filter(can_change_items=True).values_list(
|
||||
variation__item__event__id__in=request.user.teams.filter(TeamQuerySet.event_permission_q("event.items:write")).values_list(
|
||||
'limit_events__id', flat=True
|
||||
)
|
||||
)
|
||||
@@ -1007,7 +1013,7 @@ def item_meta_values(request, organizer, event):
|
||||
})
|
||||
|
||||
|
||||
@organizer_permission_required(("can_view_orders", "can_change_organizer_settings"))
|
||||
@organizer_permission_required(("event.orders:read", "organizer.settings.general:write"))
|
||||
# This decorator is a bit of a hack since this is not technically an organizer permission, but it does the job here --
|
||||
# anyone who can see orders for any event can see the check-in log view where this is used as a filter
|
||||
def devices_select2(request, **kwargs):
|
||||
@@ -1045,7 +1051,7 @@ def devices_select2(request, **kwargs):
|
||||
return JsonResponse(doc)
|
||||
|
||||
|
||||
@organizer_permission_required(("can_view_orders", "can_change_event_settings", "can_change_organizer_settings"))
|
||||
@organizer_permission_required(("event.orders:read", "event.settings.general:write", "organizer.settings.general:write"))
|
||||
# This decorator is a bit of a hack since this is not technically an organizer permission, but it does the job here --
|
||||
# anyone who can see orders for any event can see the check-in log view where this is used as a filter
|
||||
def gate_select2(request, **kwargs):
|
||||
|
||||
@@ -83,7 +83,7 @@ class VoucherList(PaginationMixin, EventPermissionRequiredMixin, ListView):
|
||||
model = Voucher
|
||||
context_object_name = 'vouchers'
|
||||
template_name = 'pretixcontrol/vouchers/index.html'
|
||||
permission = 'can_view_vouchers'
|
||||
permission = 'event.vouchers:read'
|
||||
|
||||
@scopes_disabled() # we have an event check here, and we can save some performance on subqueries
|
||||
def get_queryset(self):
|
||||
@@ -155,7 +155,7 @@ class VoucherList(PaginationMixin, EventPermissionRequiredMixin, ListView):
|
||||
|
||||
class VoucherTags(EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/vouchers/tags.html'
|
||||
permission = 'can_view_vouchers'
|
||||
permission = 'event.vouchers:read'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.request.event.vouchers.order_by('tag').filter(
|
||||
@@ -196,7 +196,7 @@ class VoucherTags(EventPermissionRequiredMixin, TemplateView):
|
||||
class VoucherDeleteCarts(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Voucher
|
||||
template_name = 'pretixcontrol/vouchers/delete_carts.html'
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
context_object_name = 'voucher'
|
||||
|
||||
def get_object(self, queryset=None) -> Voucher:
|
||||
@@ -228,7 +228,7 @@ class VoucherDeleteCarts(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
class VoucherDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = Voucher
|
||||
template_name = 'pretixcontrol/vouchers/delete.html'
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
context_object_name = 'voucher'
|
||||
|
||||
def get_object(self, queryset=None) -> Voucher:
|
||||
@@ -270,7 +270,7 @@ class VoucherDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
class VoucherUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Voucher
|
||||
template_name = 'pretixcontrol/vouchers/detail.html'
|
||||
permission = ('can_change_vouchers', 'can_view_vouchers')
|
||||
permission = ('event.vouchers:write', 'event.vouchers:read')
|
||||
context_object_name = 'voucher'
|
||||
|
||||
def form_invalid(self, form):
|
||||
@@ -286,7 +286,7 @@ class VoucherUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'can_change_vouchers',
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'event.vouchers:write',
|
||||
request=self.request):
|
||||
for f in form.fields.values():
|
||||
f.disabled = True
|
||||
@@ -313,7 +313,7 @@ class VoucherUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
|
||||
@transaction.atomic
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_vouchers',
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.vouchers:write',
|
||||
request=request):
|
||||
raise PermissionDenied()
|
||||
return super().post(request, *args, **kwargs)
|
||||
@@ -344,7 +344,7 @@ class VoucherUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
class VoucherCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = Voucher
|
||||
template_name = 'pretixcontrol/vouchers/detail.html'
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
context_object_name = 'voucher'
|
||||
|
||||
def form_invalid(self, form):
|
||||
@@ -389,7 +389,7 @@ class VoucherCreate(EventPermissionRequiredMixin, CreateView):
|
||||
|
||||
|
||||
class VoucherGo(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_view_vouchers'
|
||||
permission = 'event.vouchers:read'
|
||||
|
||||
def get_voucher(self, code):
|
||||
return Voucher.objects.get(code__iexact=code, event=self.request.event)
|
||||
@@ -408,7 +408,7 @@ class VoucherGo(EventPermissionRequiredMixin, View):
|
||||
class VoucherBulkCreate(EventPermissionRequiredMixin, AsyncFormView):
|
||||
model = Voucher
|
||||
template_name = 'pretixcontrol/vouchers/bulk.html'
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
context_object_name = 'voucher'
|
||||
atomic_execute = True
|
||||
|
||||
@@ -540,7 +540,7 @@ class VoucherBulkCreate(EventPermissionRequiredMixin, AsyncFormView):
|
||||
|
||||
|
||||
class VoucherBulkMailPreview(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
|
||||
# return the origin text if key is missing in dict
|
||||
class SafeDict(dict):
|
||||
@@ -579,7 +579,7 @@ class VoucherBulkMailPreview(EventPermissionRequiredMixin, View):
|
||||
|
||||
|
||||
class VoucherRNG(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
try:
|
||||
@@ -603,7 +603,7 @@ class VoucherRNG(EventPermissionRequiredMixin, View):
|
||||
|
||||
|
||||
class VoucherBulkAction(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_vouchers'
|
||||
permission = 'event.vouchers:write'
|
||||
|
||||
@cached_property
|
||||
def objects(self):
|
||||
|
||||
@@ -64,7 +64,7 @@ from . import UpdateView
|
||||
class AutoAssign(EventPermissionRequiredMixin, AsyncAction, View):
|
||||
task = assign_automatically
|
||||
known_errortypes = ['WaitingListError']
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def get_success_message(self, value):
|
||||
return _('{num} vouchers have been created and sent out via email.').format(num=value)
|
||||
@@ -143,7 +143,7 @@ class WaitingListQuerySetMixin:
|
||||
|
||||
class WaitingListActionView(EventPermissionRequiredMixin, WaitingListQuerySetMixin, View):
|
||||
model = WaitingListEntry
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def _redirect_back(self):
|
||||
if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
|
||||
@@ -233,7 +233,7 @@ class WaitingListView(EventPermissionRequiredMixin, WaitingListQuerySetMixin, Pa
|
||||
model = WaitingListEntry
|
||||
context_object_name = 'entries'
|
||||
template_name = 'pretixcontrol/waitinglist/index.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
@@ -360,7 +360,7 @@ class WaitingListView(EventPermissionRequiredMixin, WaitingListQuerySetMixin, Pa
|
||||
class EntryDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = WaitingListEntry
|
||||
template_name = 'pretixcontrol/waitinglist/delete.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
context_object_name = 'entry'
|
||||
|
||||
def get_object(self, queryset=None) -> WaitingListEntry:
|
||||
@@ -393,7 +393,7 @@ class EntryDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
class EntryTransfer(EventPermissionRequiredMixin, UpdateView):
|
||||
model = WaitingListEntry
|
||||
template_name = 'pretixcontrol/waitinglist/transfer.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
form_class = WaitingListEntryTransferForm
|
||||
context_object_name = 'entry'
|
||||
|
||||
|
||||
96
src/pretix/helpers/permission_migration.py
Normal file
96
src/pretix/helpers/permission_migration.py
Normal file
@@ -0,0 +1,96 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-today pretix GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import warnings
|
||||
|
||||
# The first two mapping tables are used to migrate *configuration*, i.e. existing Team objects or Team objects
|
||||
# created through old-style API calls. These need to be "complete on both sides", i.e. all new permissions are assigned
|
||||
# to existing users in some scenario.
|
||||
OLD_TO_NEW_EVENT_MIGRATION = {
|
||||
"can_change_event_settings": [
|
||||
"event.settings.general:write",
|
||||
"event.settings.payment:write",
|
||||
"event.settings.plugins:write",
|
||||
"event.settings.email.sender:write",
|
||||
"event.settings.tax:write",
|
||||
"event.settings.invoicing:write",
|
||||
"event.subevents:write",
|
||||
],
|
||||
"can_change_items": ["event.items:write"],
|
||||
"can_view_orders": ["event.orders:read"],
|
||||
"can_change_orders": ["event.orders:write", "event:cancel"],
|
||||
"can_checkin_orders": ["event.orders:checkin"],
|
||||
"can_view_vouchers": ["event.vouchers:read"],
|
||||
"can_change_vouchers": ["event.vouchers:write"],
|
||||
}
|
||||
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"],
|
||||
"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"],
|
||||
"can_manage_reusable_media": ["organizer.reusablemedia:read", "organizer.reusablemedia:write"],
|
||||
}
|
||||
|
||||
# The second two mapping tables are used to migrate permission *checks*, i.e. they define which permissions a user needs
|
||||
# to have to fulfill the "old-style condition". These are shorter than the migration mappings, since it does not
|
||||
# make sense to check e.g. for event.settings.tax:write on every plugin that checks for can_change_event_settings
|
||||
OLD_TO_NEW_EVENT_COMPAT = {
|
||||
"can_change_event_settings": ["event.settings.general:write"],
|
||||
"can_change_items": ["event.items:write"],
|
||||
"can_view_orders": ["event.orders:read"],
|
||||
"can_change_orders": ["event.orders:write"],
|
||||
"can_checkin_orders": ["event.orders:checkin"],
|
||||
"can_view_vouchers": ["event.vouchers:read"],
|
||||
"can_change_vouchers": ["event.vouchers:write"],
|
||||
}
|
||||
OLD_TO_NEW_ORGANIZER_COMPAT = {
|
||||
"can_create_events": ["organizer.events:create"],
|
||||
"can_change_organizer_settings": ["organizer.settings.general:write"],
|
||||
"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"],
|
||||
"can_manage_reusable_media": ["organizer.reusablemedia:read", "organizer.reusablemedia:write"],
|
||||
}
|
||||
|
||||
|
||||
class LegacyPermissionProperty:
|
||||
name = None
|
||||
|
||||
def __set_name__(self, owner, name):
|
||||
self.name = name
|
||||
|
||||
def __get__(self, instance, owner=None):
|
||||
if instance is None:
|
||||
return self
|
||||
|
||||
warnings.warn("Legacy permission attribute used", DeprecationWarning, stacklevel=2)
|
||||
|
||||
if self.name in OLD_TO_NEW_EVENT_COMPAT:
|
||||
return instance.all_event_permissions or all(
|
||||
kk in instance.limit_event_permissions for kk in OLD_TO_NEW_EVENT_COMPAT[self.name]
|
||||
)
|
||||
if self.name in OLD_TO_NEW_ORGANIZER_COMPAT:
|
||||
return instance.all_organizer_permissions or all(
|
||||
kk in instance.limit_organizer_permissions for kk in OLD_TO_NEW_ORGANIZER_COMPAT[self.name]
|
||||
)
|
||||
raise AttributeError("Unknown legacy attribute")
|
||||
@@ -108,7 +108,7 @@ class RuleViewSet(viewsets.ModelViewSet):
|
||||
filter_backends = (DjangoFilterBackend, TotalOrderingFilter)
|
||||
ordering = ("id",)
|
||||
ordering_fields = ("id",)
|
||||
permission = "can_change_event_settings"
|
||||
permission = "event.settings.general:write"
|
||||
|
||||
def get_queryset(self):
|
||||
return AutoCheckinRule.objects.filter(event=self.request.event)
|
||||
|
||||
@@ -39,7 +39,7 @@ from pretix.plugins.autocheckin.models import AutoCheckinRule
|
||||
def nav_event_receiver(sender, request, **kwargs):
|
||||
url = request.resolver_match
|
||||
if not request.user.has_event_permission(
|
||||
request.organizer, request.event, "can_change_event_settings", request=request
|
||||
request.organizer, request.event, "event.settings.general:write", request=request
|
||||
):
|
||||
return []
|
||||
return [
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right flip">
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "plugins:autocheckin:edit" organizer=request.event.organizer.slug event=request.event.slug rule=r.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "plugins:autocheckin:add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ r.id }}"
|
||||
class="btn btn-default btn-sm" title="{% trans "Clone" %}" data-toggle="tooltip"><i class="fa fa-copy"></i></a>
|
||||
|
||||
@@ -35,7 +35,7 @@ from pretix.plugins.autocheckin.models import AutoCheckinRule
|
||||
|
||||
|
||||
class IndexView(EventPermissionRequiredMixin, ListView):
|
||||
permission = "can_change_event_settings"
|
||||
permission = "event.settings.general:write"
|
||||
template_name = "pretixplugins/autocheckin/index.html"
|
||||
paginate_by = 50
|
||||
context_object_name = "rules"
|
||||
@@ -70,7 +70,7 @@ class IndexView(EventPermissionRequiredMixin, ListView):
|
||||
|
||||
class RuleAddView(EventPermissionRequiredMixin, CreateView):
|
||||
template_name = "pretixplugins/autocheckin/add.html"
|
||||
permission = "can_change_event_settings"
|
||||
permission = "event.settings.general:write"
|
||||
form_class = AutoCheckinRuleForm
|
||||
model = AutoCheckinRule
|
||||
|
||||
@@ -140,7 +140,7 @@ class RuleEditView(EventPermissionRequiredMixin, UpdateView):
|
||||
model = AutoCheckinRule
|
||||
form_class = AutoCheckinRuleForm
|
||||
template_name = "pretixplugins/autocheckin/edit.html"
|
||||
permission = "can_change_event_settings"
|
||||
permission = "event.settings.general:write"
|
||||
|
||||
def get_object(self, queryset=None) -> AutoCheckinRule:
|
||||
return get_object_or_404(
|
||||
@@ -178,7 +178,7 @@ class RuleEditView(EventPermissionRequiredMixin, UpdateView):
|
||||
|
||||
class RuleDeleteView(EventPermissionRequiredMixin, DeleteView):
|
||||
model = AutoCheckinRule
|
||||
permission = "can_change_event_settings"
|
||||
permission = "event.settings.general:write"
|
||||
template_name = "pretixplugins/autocheckin/delete.html"
|
||||
context_object_name = "rule"
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ from pretix.plugins.badges.models import BadgeItem, BadgeLayout
|
||||
def control_nav_import(sender, request=None, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
p = (
|
||||
request.user.has_event_permission(request.organizer, request.event, 'can_change_settings', request)
|
||||
or request.user.has_event_permission(request.organizer, request.event, 'can_view_orders', request)
|
||||
request.user.has_event_permission(request.organizer, request.event, 'event.settings.general:write', request)
|
||||
or request.user.has_event_permission(request.organizer, request.event, 'event.orders:read', request)
|
||||
)
|
||||
if not p:
|
||||
return []
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "plugins:badges:add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-primary btn-lg"><i class="fa fa-plus"></i> {% trans "Create a new badge layout" %}
|
||||
</a>
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<p>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "plugins:badges:add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new badge layout" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
@@ -40,7 +40,7 @@
|
||||
{% for l in layouts %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<strong><a href="{% url "plugins:badges:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
|
||||
{{ l.name }}
|
||||
</a></strong>
|
||||
@@ -54,7 +54,7 @@
|
||||
<span class="fa fa-check"></span>
|
||||
{% trans "Default" %}
|
||||
</span>
|
||||
{% elif "can_change_event_settings" in request.eventpermset %}
|
||||
{% elif "event.settings.general:write" in request.eventpermset %}
|
||||
<form class="form-inline" method="post"
|
||||
action="{% url "plugins:badges:default" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}"
|
||||
>
|
||||
@@ -66,7 +66,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right flip">
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "plugins:badges:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "plugins:badges:add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ l.id }}"
|
||||
class="btn btn-default btn-sm" title="{% trans "Clone" %}" data-toggle="tooltip"><i class="fa fa-copy"></i></a>
|
||||
|
||||
@@ -59,7 +59,7 @@ from .templates import TEMPLATES
|
||||
|
||||
class LayoutListView(EventPermissionRequiredMixin, ListView):
|
||||
model = BadgeLayout
|
||||
permission = ('can_change_event_settings', 'can_view_orders')
|
||||
permission = ('event.settings.general:write', 'event.orders:read')
|
||||
template_name = 'pretixplugins/badges/index.html'
|
||||
context_object_name = 'layouts'
|
||||
|
||||
@@ -71,7 +71,7 @@ class LayoutCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = BadgeLayout
|
||||
form_class = BadgeLayoutForm
|
||||
template_name = 'pretixplugins/badges/edit.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'layout'
|
||||
success_url = '/ignored'
|
||||
|
||||
@@ -139,7 +139,7 @@ class LayoutCreate(EventPermissionRequiredMixin, CreateView):
|
||||
|
||||
class LayoutSetDefault(EventPermissionRequiredMixin, DetailView):
|
||||
model = BadgeLayout
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_object(self, queryset=None) -> BadgeLayout:
|
||||
try:
|
||||
@@ -171,7 +171,7 @@ class LayoutSetDefault(EventPermissionRequiredMixin, DetailView):
|
||||
class LayoutDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = BadgeLayout
|
||||
template_name = 'pretixplugins/badges/delete.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'layout'
|
||||
|
||||
def get_object(self, queryset=None) -> BadgeLayout:
|
||||
@@ -269,7 +269,7 @@ class LayoutEditorView(BaseEditorView):
|
||||
|
||||
class OrderPrintDo(EventPermissionRequiredMixin, AsyncAction, View):
|
||||
task = badges_create_pdf
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
known_errortypes = ['OrderError', 'ExportError']
|
||||
|
||||
def get_success_message(self, value):
|
||||
|
||||
@@ -97,7 +97,6 @@ class BankImportJobViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
queryset = BankImportJob.objects.none()
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = JobFilter
|
||||
permission = 'can_view_orders'
|
||||
|
||||
def get_queryset(self):
|
||||
return BankImportJob.objects.filter(organizer=self.request.organizer)
|
||||
@@ -105,9 +104,30 @@ class BankImportJobViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
def perform_create(self, serializer):
|
||||
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):
|
||||
perm_holder = (request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user)
|
||||
if not perm_holder.has_organizer_permission(request.organizer, 'can_change_orders'):
|
||||
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')
|
||||
|
||||
if BankImportJob.objects.filter(Q(organizer=request.organizer)).filter(
|
||||
|
||||
@@ -41,7 +41,7 @@ def register_payment_provider(sender, **kwargs):
|
||||
@receiver(nav_event, dispatch_uid="payment_banktransfer_nav")
|
||||
def control_nav_import(sender, request=None, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_orders', request=request):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.orders:write', request=request):
|
||||
return []
|
||||
return [
|
||||
{
|
||||
@@ -76,7 +76,10 @@ def control_nav_import(sender, request=None, **kwargs):
|
||||
@receiver(nav_organizer, dispatch_uid="payment_banktransfer_organav")
|
||||
def control_nav_orga_import(sender, request=None, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
if not request.user.has_organizer_permission(request.organizer, 'can_change_orders', 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 [
|
||||
{
|
||||
|
||||
@@ -44,6 +44,7 @@ from typing import Set
|
||||
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, Q, QuerySet
|
||||
from django.http import FileResponse, JsonResponse
|
||||
@@ -58,12 +59,11 @@ from localflavor.generic.forms import BICFormField, IBANFormField
|
||||
|
||||
from pretix.base.forms.widgets import DatePickerWidget
|
||||
from pretix.base.models import Event, Order, OrderPayment, OrderRefund, Quota
|
||||
from pretix.base.models.organizer import TeamQuerySet
|
||||
from pretix.base.services.mail import SendMailException
|
||||
from pretix.base.settings import SettingsSandbox
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
from pretix.control.permissions import (
|
||||
EventPermissionRequiredMixin, OrganizerPermissionRequiredMixin,
|
||||
)
|
||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||
from pretix.control.views.organizer import OrganizerDetailViewMixin
|
||||
from pretix.helpers.json import CustomJSONEncoder
|
||||
from pretix.plugins.banktransfer import camtimport, csvimport, mt940import
|
||||
@@ -80,7 +80,7 @@ logger = logging.getLogger('pretix.plugins.banktransfer')
|
||||
|
||||
|
||||
class ActionView(View):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def _discard(self, trans):
|
||||
trans.state = BankTransaction.STATE_DISCARDED
|
||||
@@ -285,7 +285,7 @@ class ActionView(View):
|
||||
|
||||
class JobDetailView(DetailView):
|
||||
template_name = 'pretixplugins/banktransfer/job_detail.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
context_objectname = 'job'
|
||||
|
||||
def redirect_form(self):
|
||||
@@ -374,7 +374,7 @@ class BankTransactionFilterForm(forms.Form):
|
||||
|
||||
class ImportView(ListView):
|
||||
template_name = 'pretixplugins/banktransfer/import_form.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
context_object_name = 'transactions_unhandled'
|
||||
paginate_by = 30
|
||||
|
||||
@@ -631,44 +631,54 @@ class ImportView(ListView):
|
||||
|
||||
class OrganizerBanktransferView:
|
||||
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)
|
||||
|
||||
|
||||
class EventImportView(EventPermissionRequiredMixin, ImportView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
|
||||
class OrganizerImportView(OrganizerBanktransferView, OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin,
|
||||
class OrganizerImportView(OrganizerBanktransferView, OrganizerDetailViewMixin,
|
||||
ImportView):
|
||||
permission = 'can_change_orders'
|
||||
pass
|
||||
|
||||
|
||||
class EventJobDetailView(EventPermissionRequiredMixin, JobDetailView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
|
||||
class OrganizerJobDetailView(OrganizerBanktransferView, OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin,
|
||||
class OrganizerJobDetailView(OrganizerBanktransferView, OrganizerDetailViewMixin,
|
||||
JobDetailView):
|
||||
permission = 'can_change_orders'
|
||||
pass
|
||||
|
||||
|
||||
class EventActionView(EventPermissionRequiredMixin, ActionView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
|
||||
class OrganizerActionView(OrganizerBanktransferView, OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin,
|
||||
class OrganizerActionView(OrganizerBanktransferView, OrganizerDetailViewMixin,
|
||||
ActionView):
|
||||
permission = 'can_change_orders'
|
||||
|
||||
def order_qs(self):
|
||||
all = self.request.user.teams.filter(organizer=self.request.organizer, can_change_orders=True,
|
||||
can_view_orders=True, all_events=True).exists()
|
||||
all = self.request.user.teams.filter(
|
||||
TeamQuerySet.event_permission_q("event.orders:read"),
|
||||
TeamQuerySet.event_permission_q("event.orders:write"),
|
||||
all_events=True,
|
||||
organizer=self.request.organizer,
|
||||
).exists()
|
||||
if self.request.user.has_active_staff_session(self.request.session.session_key) or all:
|
||||
return Order.objects.filter(event__organizer=self.request.organizer)
|
||||
else:
|
||||
return Order.objects.filter(
|
||||
event_id__in=self.request.user.teams.filter(
|
||||
organizer=self.request.organizer, can_change_orders=True, can_view_orders=True
|
||||
TeamQuerySet.event_permission_q("event.orders:read"),
|
||||
TeamQuerySet.event_permission_q("event.orders:write"),
|
||||
organizer=self.request.organizer,
|
||||
).values_list('limit_events__id', flat=True)
|
||||
)
|
||||
|
||||
@@ -761,7 +771,7 @@ class RefundExportListView(ListView):
|
||||
|
||||
|
||||
class EventRefundExportListView(EventPermissionRequiredMixin, RefundExportListView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('plugins:banktransfer:refunds.list', kwargs={
|
||||
@@ -783,8 +793,7 @@ class EventRefundExportListView(EventPermissionRequiredMixin, RefundExportListVi
|
||||
)
|
||||
|
||||
|
||||
class OrganizerRefundExportListView(OrganizerPermissionRequiredMixin, RefundExportListView):
|
||||
permission = 'can_change_orders'
|
||||
class OrganizerRefundExportListView(OrganizerBanktransferView, RefundExportListView):
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('plugins:banktransfer:refunds.list', kwargs={
|
||||
@@ -817,7 +826,7 @@ class DownloadRefundExportView(DetailView):
|
||||
|
||||
|
||||
class EventDownloadRefundExportView(EventPermissionRequiredMixin, DownloadRefundExportView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
return get_object_or_404(
|
||||
@@ -827,8 +836,7 @@ class EventDownloadRefundExportView(EventPermissionRequiredMixin, DownloadRefund
|
||||
)
|
||||
|
||||
|
||||
class OrganizerDownloadRefundExportView(OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, DownloadRefundExportView):
|
||||
permission = 'can_change_orders'
|
||||
class OrganizerDownloadRefundExportView(OrganizerBanktransferView, OrganizerDetailViewMixin, DownloadRefundExportView):
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
return get_object_or_404(
|
||||
@@ -856,9 +864,9 @@ class SepaXMLExportView(SingleObjectMixin, FormView):
|
||||
template_name = 'pretixplugins/banktransfer/sepa_export.html'
|
||||
context_object_name = "export"
|
||||
|
||||
def setup(self, request, *args, **kwargs):
|
||||
super().setup(request, *args, **kwargs)
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object: RefundExport = self.get_object()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
self.object.downloaded = True
|
||||
@@ -875,7 +883,7 @@ class SepaXMLExportView(SingleObjectMixin, FormView):
|
||||
|
||||
|
||||
class EventSepaXMLExportView(EventPermissionRequiredMixin, SepaXMLExportView):
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
return get_object_or_404(
|
||||
@@ -890,8 +898,7 @@ class EventSepaXMLExportView(EventPermissionRequiredMixin, SepaXMLExportView):
|
||||
return form
|
||||
|
||||
|
||||
class OrganizerSepaXMLExportView(OrganizerPermissionRequiredMixin, OrganizerDetailViewMixin, SepaXMLExportView):
|
||||
permission = 'can_change_orders'
|
||||
class OrganizerSepaXMLExportView(OrganizerBanktransferView, OrganizerDetailViewMixin, SepaXMLExportView):
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
return get_object_or_404(
|
||||
|
||||
@@ -246,7 +246,7 @@ def webhook(request, *args, **kwargs):
|
||||
return HttpResponse(status=200)
|
||||
|
||||
|
||||
@event_permission_required('can_change_event_settings')
|
||||
@event_permission_required('event.settings.general:write')
|
||||
@require_POST
|
||||
def oauth_disconnect(request, **kwargs):
|
||||
del request.event.settings.payment_paypal_connect_refresh_token
|
||||
|
||||
@@ -216,7 +216,7 @@ class PayView(PaypalOrderView, TemplateView):
|
||||
|
||||
|
||||
@scopes_disabled()
|
||||
@event_permission_required('can_change_event_settings')
|
||||
@event_permission_required('event.settings.general:write')
|
||||
def isu_return(request, *args, **kwargs):
|
||||
getparams = ['merchantId', 'merchantIdInPayPal', 'permissionsGranted', 'accountStatus', 'consentStatus', 'productIntentID', 'isEmailConfirmed']
|
||||
sessionparams = ['payment_paypal_isu_event', 'payment_paypal_isu_tracking_id']
|
||||
@@ -526,7 +526,7 @@ def webhook(request, *args, **kwargs):
|
||||
return HttpResponse(status=200)
|
||||
|
||||
|
||||
@event_permission_required('can_change_event_settings')
|
||||
@event_permission_required('event.settings.general:write')
|
||||
@require_POST
|
||||
def isu_disconnect(request, **kwargs):
|
||||
del request.event.settings.payment_paypal_connect_refresh_token
|
||||
|
||||
@@ -83,7 +83,7 @@ def check_against_prefix_list(u, allowlist):
|
||||
@receiver(nav_event_settings, dispatch_uid='returnurl_nav')
|
||||
def navbar_info(sender, request, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_event_settings',
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.settings.general:write',
|
||||
request=request):
|
||||
return []
|
||||
return [{
|
||||
|
||||
@@ -48,7 +48,7 @@ class ReturnSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
form_class = ReturnSettingsForm
|
||||
template_name = 'returnurl/settings.html'
|
||||
permission = 'can_change_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('plugins:returnurl:settings', kwargs={
|
||||
|
||||
@@ -113,7 +113,7 @@ class RuleViewSet(viewsets.ModelViewSet):
|
||||
filterset_class = RuleFilter
|
||||
ordering = ('id',)
|
||||
ordering_fields = ('id',)
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return Rule.objects.filter(event=self.request.event)
|
||||
|
||||
@@ -79,7 +79,7 @@ def scheduled_mail_create(sender, **kwargs):
|
||||
@receiver(nav_event, dispatch_uid="sendmail_nav")
|
||||
def control_nav_import(sender, request=None, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_orders', request=request):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.orders:write', request=request):
|
||||
return []
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@ logger = logging.getLogger('pretix.plugins.sendmail')
|
||||
|
||||
class IndexView(EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixplugins/sendmail/index.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
from .signals import sendmail_view_classes
|
||||
@@ -94,7 +94,7 @@ class IndexView(EventPermissionRequiredMixin, TemplateView):
|
||||
class BaseSenderView(EventPermissionRequiredMixin, FormView):
|
||||
# These parameters usually SHOULD NOT be overridden
|
||||
template_name = 'pretixplugins/sendmail/send_form.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
|
||||
# These parameters MUST be overridden by subclasses
|
||||
form_fragment_name = None
|
||||
@@ -523,7 +523,7 @@ class WaitinglistSendView(BaseSenderView):
|
||||
|
||||
class EmailHistoryView(EventPermissionRequiredMixin, ListView):
|
||||
template_name = 'pretixplugins/sendmail/history.html'
|
||||
permission = 'can_change_orders'
|
||||
permission = 'event.orders:write'
|
||||
model = LogEntry
|
||||
context_object_name = 'logs'
|
||||
paginate_by = 5
|
||||
@@ -571,7 +571,7 @@ class EmailHistoryView(EventPermissionRequiredMixin, ListView):
|
||||
|
||||
class CreateRule(EventPermissionRequiredMixin, CreateView):
|
||||
template_name = 'pretixplugins/sendmail/rule_create.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
form_class = forms.RuleForm
|
||||
|
||||
model = Rule
|
||||
@@ -621,7 +621,7 @@ class UpdateRule(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Rule
|
||||
form_class = forms.RuleForm
|
||||
template_name = 'pretixplugins/sendmail/rule_update.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_object(self, queryset=None) -> Rule:
|
||||
return get_object_or_404(
|
||||
@@ -701,7 +701,7 @@ class ListRules(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
|
||||
class DeleteRule(EventPermissionRequiredMixin, DeleteView):
|
||||
model = Rule
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
template_name = 'pretixplugins/sendmail/rule_delete.html'
|
||||
context_object_name = 'rule'
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ from pretix.control.signals import nav_event
|
||||
@receiver(nav_event, dispatch_uid="statistics_nav")
|
||||
def control_nav_import(sender, request=None, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_view_orders', request=request):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'event.orders:read', request=request):
|
||||
return []
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ from pretix.plugins.statistics.signals import clear_cache
|
||||
|
||||
class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView):
|
||||
template_name = 'pretixplugins/statistics/index.html'
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
@@ -473,7 +473,7 @@ def paymentintent_webhook(event, event_json, paymentintent_id, rso):
|
||||
return HttpResponse(status=200)
|
||||
|
||||
|
||||
@event_permission_required('can_change_event_settings')
|
||||
@event_permission_required('event.settings.general:write')
|
||||
def oauth_disconnect(request, **kwargs):
|
||||
if request.method != "POST":
|
||||
return render(request, 'pretixplugins/stripe/oauth_disconnect.html', {})
|
||||
@@ -671,7 +671,7 @@ class ScaReturnView(StripeOrderView, View):
|
||||
|
||||
class OrganizerSettingsFormView(DecoupleMixin, OrganizerDetailViewMixin, AdministratorPermissionRequiredMixin, FormView):
|
||||
model = Organizer
|
||||
permission = 'can_change_organizer_settings'
|
||||
permission = 'organizer.settings.general:write'
|
||||
form_class = OrganizerStripeSettingsForm
|
||||
template_name = 'pretixplugins/stripe/organizer_stripe.html'
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ class RenderJobSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class TicketRendererViewSet(viewsets.ViewSet):
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
|
||||
def get_serializer_kwargs(self):
|
||||
return {}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "plugins:ticketoutputpdf:add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-primary btn-lg"><i class="fa fa-plus"></i> {% trans "Create a new layout" %}
|
||||
</a>
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<p>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "plugins:ticketoutputpdf:add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new layout" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
@@ -38,7 +38,7 @@
|
||||
{% for l in layouts %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<strong><a href="{% url "plugins:ticketoutputpdf:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
|
||||
{{ l.name }}
|
||||
</a></strong>
|
||||
@@ -52,7 +52,7 @@
|
||||
<span class="fa fa-check"></span>
|
||||
{% trans "Default" %}
|
||||
</span>
|
||||
{% elif "can_change_event_settings" in request.eventpermset %}
|
||||
{% elif "event.settings.general:write" in request.eventpermset %}
|
||||
<form class="form-inline" method="post"
|
||||
action="{% url "plugins:ticketoutputpdf:default" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
|
||||
{% csrf_token %}
|
||||
@@ -63,7 +63,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right flip">
|
||||
{% if "can_change_event_settings" in request.eventpermset %}
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<a href="{% url "plugins:ticketoutputpdf:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "plugins:ticketoutputpdf:add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ l.id }}"
|
||||
class="btn btn-default btn-sm" title="{% trans "Clone" %}" data-toggle="tooltip"><i class="fa fa-copy"></i></a>
|
||||
|
||||
@@ -95,7 +95,7 @@ class EditorView(BaseEditorView):
|
||||
|
||||
class LayoutListView(EventPermissionRequiredMixin, ListView):
|
||||
model = TicketLayout
|
||||
permission = ('can_change_event_settings')
|
||||
permission = ('event.settings.general:write')
|
||||
template_name = 'pretixplugins/ticketoutputpdf/index.html'
|
||||
context_object_name = 'layouts'
|
||||
|
||||
@@ -107,7 +107,7 @@ class LayoutCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = TicketLayout
|
||||
form_class = TicketLayoutForm
|
||||
template_name = 'pretixplugins/ticketoutputpdf/edit.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'layout'
|
||||
success_url = '/ignored'
|
||||
|
||||
@@ -157,7 +157,7 @@ class LayoutCreate(EventPermissionRequiredMixin, CreateView):
|
||||
|
||||
class LayoutSetDefault(EventPermissionRequiredMixin, DetailView):
|
||||
model = TicketLayout
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get_object(self, queryset=None) -> TicketLayout:
|
||||
try:
|
||||
@@ -186,7 +186,7 @@ class LayoutSetDefault(EventPermissionRequiredMixin, DetailView):
|
||||
class LayoutDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
model = TicketLayout
|
||||
template_name = 'pretixplugins/ticketoutputpdf/delete.html'
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
context_object_name = 'layout'
|
||||
|
||||
def get_object(self, queryset=None) -> TicketLayout:
|
||||
@@ -218,7 +218,7 @@ class LayoutDelete(EventPermissionRequiredMixin, CompatDeleteView):
|
||||
|
||||
|
||||
class LayoutGetDefault(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
permission = 'event.settings.general:write'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
layout = self.request.event.ticket_layouts.get_or_create(
|
||||
@@ -304,7 +304,7 @@ class LayoutEditorView(BaseEditorView):
|
||||
|
||||
class OrderPrintDo(EventPermissionRequiredMixin, AsyncAction, View):
|
||||
task = tickets_create_pdf
|
||||
permission = 'can_view_orders'
|
||||
permission = 'event.orders:read'
|
||||
known_errortypes = ['OrderError', 'ExportError']
|
||||
|
||||
def get_success_message(self, value):
|
||||
|
||||
@@ -30,7 +30,7 @@ from pretix.control.signals import nav_event
|
||||
@receiver(nav_event, dispatch_uid='webcheckin_nav_event')
|
||||
def navbar_entry(sender, request, **kwargs):
|
||||
url = request.resolver_match
|
||||
if not request.user.has_event_permission(request.organizer, request.event, ('can_change_orders', 'can_checkin_orders'), request=request):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, ('event.orders:write', 'event.orders:checkin'), request=request):
|
||||
return []
|
||||
return [{
|
||||
'label': mark_safe(_('Web Check-in') + ' <span class="label label-success">beta</span>'),
|
||||
|
||||
@@ -26,7 +26,7 @@ from pretix.helpers.countries import CachedCountries
|
||||
|
||||
|
||||
class IndexView(EventPermissionRequiredMixin, TemplateView):
|
||||
permission = ('can_change_orders', 'can_checkin_orders')
|
||||
permission = ('event.orders:write', 'event.orders:checkin')
|
||||
template_name = 'pretixplugins/webcheckin/index.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
@@ -208,7 +208,7 @@ class TicketPageMixin:
|
||||
|
||||
ctx['download_buttons'] = self.download_buttons
|
||||
|
||||
ctx['backend_user'] = has_event_access_permission(self.request, 'can_view_orders')
|
||||
ctx['backend_user'] = has_event_access_permission(self.request, 'event.orders:read')
|
||||
|
||||
return ctx
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user