forked from CGM_Public/pretix_original
Pluggable permissions (#5728)
* Data model draft * Refactor query and assignment usages of old permissions * Backend UI * API serializer * Big string replace * Docs, tests and fixes for teams api * Update docs for device auth * Eliminate old names * Make tests pass * Use new permissions, remove inconsistencies * Add test for translations * Show plugin permissions * Add permission for seating plans * Fix plugin activation * Fix failing test * Refactor to permission groups * Update doc/api/resources/devices.rst Co-authored-by: luelista <weller@rami.io> * Update doc/api/resources/events.rst Co-authored-by: luelista <weller@rami.io> * Update src/pretix/api/serializers/organizer.py Co-authored-by: luelista <weller@rami.io> * Fix typo * Fix python version compat * Replacement after rebase * Add proper permission handling for exports * Docs for exporters * Runtime linting of permission names * Fix typos * Show export page even without orders permission * More legacy compat * Do not strongly validate before plugins are loaded * Rebase migration * Add permission for outgoing mails * Review notes * Update doc/api/resources/teams.rst Co-authored-by: Richard Schreiber <schreiber@pretix.eu> * Clean up logic around exporters * Review and failures * Fix migration leading to forbidden combination * Handle permissions on event copying * Remove print-statements * Make test clearer * Review feedback * Add AnyPermissionOf * migration safety --------- Co-authored-by: luelista <weller@rami.io> Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
This commit is contained in:
@@ -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,11 +59,10 @@ 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.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
|
||||
@@ -79,7 +79,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
|
||||
@@ -279,7 +279,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):
|
||||
@@ -368,7 +368,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
|
||||
|
||||
@@ -625,44 +625,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)
|
||||
)
|
||||
|
||||
@@ -755,7 +765,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={
|
||||
@@ -777,8 +787,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={
|
||||
@@ -811,7 +820,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(
|
||||
@@ -821,8 +830,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(
|
||||
@@ -850,9 +858,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
|
||||
@@ -869,7 +877,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(
|
||||
@@ -884,8 +892,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(
|
||||
|
||||
Reference in New Issue
Block a user