Use new permissions, remove inconsistencies

This commit is contained in:
Raphael Michel
2026-01-12 18:30:39 +01:00
parent 2c8b545ed1
commit 18d3df4736
61 changed files with 1214 additions and 781 deletions

View File

@@ -295,7 +295,7 @@ class CheckInListBulkActionView(CheckInListQueryMixin, EventPermissionRequiredMi
class CheckinListList(EventPermissionRequiredMixin, PaginationMixin, ListView):
model = CheckinList
context_object_name = 'checkinlists'
permission = 'event.orders:read'
permission = ('event.orders:read', 'event.settings.general:write')
template_name = 'pretixcontrol/checkin/lists.html'
ordering = ('subevent__date_from', 'name', 'pk')
@@ -317,9 +317,9 @@ class CheckinListList(EventPermissionRequiredMixin, PaginationMixin, ListView):
cl.subevent.event = self.request.event # re-use same event object to make sure settings are cached
ctx['checkinlists'] = clists
ctx['can_change_organizer_settings'] = self.request.user.has_organizer_permission(
ctx['link_device_settings'] = self.request.user.has_organizer_permission(
self.request.organizer,
'organizer.settings.general:write',
'organizer.devices:read',
self.request
)
ctx['filter_form'] = self.filter_form
@@ -578,6 +578,12 @@ class CheckInResetView(CheckInListQueryMixin, EventPermissionRequiredMixin, Asyn
permission = "event.orders:write"
template_name = "pretixcontrol/checkin/reset.html"
def dispatch(self, request, *args, **kwargs):
# Special case, we want two permissions to be set
if not request.user.has_event_permission(request.organizer, request.event, "event.settings.general:write", request=request):
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
def get_error_url(self, *args):
return reverse(
"control:event.orders.checkinlists",

View File

@@ -502,7 +502,7 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
class PaymentProviderSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
model = Event
context_object_name = 'event'
permission = 'event.settings.general:write'
permission = 'event.settings.payment:write'
template_name = 'pretixcontrol/event/payment_provider.html'
def get_success_url(self) -> str:
@@ -618,10 +618,28 @@ class EventSettingsFormView(EventPermissionRequiredMixin, DecoupleMixin, FormVie
return self.render_to_response(self.get_context_data(form=form))
class PaymentSettings(EventSettingsViewMixin, EventSettingsFormView):
class WritePermissionMixin:
def post(self, request, *args, **kwargs):
# Special case, we want to allow different access for read and write
if not request.user.has_event_permission(request.organizer, request.event, self.write_permission,
request=request):
raise PermissionDenied()
return super().post(request, *args, **kwargs)
def get_form(self, *args, **kwargs):
form = super().get_form(*args, **kwargs)
if not self.request.user.has_event_permission(
self.request.organizer, self.request.event, self.write_permission, request=self.request):
for f in form.fields.values():
f.disabled = True
return form
class PaymentSettings(WritePermissionMixin, EventSettingsViewMixin, EventSettingsFormView):
template_name = 'pretixcontrol/event/payment.html'
form_class = PaymentSettingsForm
permission = 'event.settings.general:write'
permission = ('event.settings.payment:write', 'event.settings.general:write')
write_permission = 'event.settings.payment:write'
def get_success_url(self) -> str:
return reverse('control:event.settings.payment', kwargs={
@@ -647,10 +665,11 @@ class PaymentSettings(EventSettingsViewMixin, EventSettingsFormView):
return context
class TaxSettings(EventSettingsViewMixin, EventSettingsFormView):
class TaxSettings(WritePermissionMixin, EventSettingsViewMixin, EventSettingsFormView):
template_name = 'pretixcontrol/event/tax.html'
form_class = TaxSettingsForm
permission = 'event.settings.general:write'
permission = ('event.settings.tax:write', 'event.settings.general:write')
write_permission = 'event.settings.tax:write'
def get_success_url(self) -> str:
return reverse('control:event.settings.tax', kwargs={
@@ -666,11 +685,12 @@ class TaxSettings(EventSettingsViewMixin, EventSettingsFormView):
return context
class InvoiceSettings(EventSettingsViewMixin, EventSettingsFormView):
class InvoiceSettings(WritePermissionMixin, EventSettingsViewMixin, EventSettingsFormView):
model = Event
form_class = InvoiceSettingsForm
template_name = 'pretixcontrol/event/invoicing.html'
permission = 'event.settings.general:write'
permission = ('event.settings.invoicing:write', 'event.settings.general:write')
write_permission = 'event.settings.invoicing:write'
def get_context_data(self, **kwargs):
types = get_transmission_types()
@@ -738,7 +758,7 @@ class CancelSettings(EventSettingsViewMixin, EventSettingsFormView):
class InvoicePreview(EventPermissionRequiredMixin, View):
permission = 'event.settings.general:write'
permission = 'event.settings.invoicing:write'
def get(self, request, *args, **kwargs):
fname, ftype, fcontent = build_preview_invoice_pdf(request.event)
@@ -1293,7 +1313,7 @@ class TaxCreate(EventSettingsViewMixin, EventPermissionRequiredMixin, CreateView
model = TaxRule
form_class = TaxRuleForm
template_name = 'pretixcontrol/event/tax_edit.html'
permission = 'event.settings.general:write'
permission = 'event.settings.tax:write'
context_object_name = 'taxrule'
def get_success_url(self) -> str:
@@ -1354,7 +1374,7 @@ class TaxUpdate(EventSettingsViewMixin, EventPermissionRequiredMixin, UpdateView
model = TaxRule
form_class = TaxRuleForm
template_name = 'pretixcontrol/event/tax_edit.html'
permission = 'event.settings.general:write'
permission = 'event.settings.tax:write'
context_object_name = 'rule'
def get_object(self, queryset=None) -> TaxRule:
@@ -1418,7 +1438,7 @@ class TaxUpdate(EventSettingsViewMixin, EventPermissionRequiredMixin, UpdateView
class TaxDefault(EventSettingsViewMixin, EventPermissionRequiredMixin, DetailView):
model = TaxRule
permission = 'event.settings.general:write'
permission = 'event.settings.tax:write'
def get_object(self, queryset=None) -> TaxRule:
try:
@@ -1463,7 +1483,7 @@ class TaxDefault(EventSettingsViewMixin, EventPermissionRequiredMixin, DetailVie
class TaxDelete(EventSettingsViewMixin, EventPermissionRequiredMixin, CompatDeleteView):
model = TaxRule
template_name = 'pretixcontrol/event/tax_delete.html'
permission = 'event.settings.general:write'
permission = 'event.settings.tax:write'
context_object_name = 'taxrule'
def get_object(self, queryset=None) -> TaxRule:

View File

@@ -664,7 +664,7 @@ class QuestionMixin:
class QuestionView(EventPermissionRequiredMixin, ChartContainingView, DetailView):
model = Question
template_name = 'pretixcontrol/items/question.html'
permission = 'event.items:write'
permission = None
template_name_field = 'question'
@cached_property

View File

@@ -2980,7 +2980,7 @@ class RefundList(EventPermissionRequiredMixin, PaginationMixin, ListView):
class EventCancel(EventPermissionRequiredMixin, AsyncAction, FormView):
template_name = 'pretixcontrol/orders/cancel.html'
permission = 'event.orders:write'
permission = 'event:cancel'
form_class = EventCancelForm
task = cancel_event
known_errortypes = ['OrderError']

View File

@@ -1234,7 +1234,7 @@ class DeviceQueryMixin:
class DeviceListView(DeviceQueryMixin, OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
model = Device
template_name = 'pretixcontrol/organizers/devices.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:read'
context_object_name = 'devices'
paginate_by = 100
@@ -1247,7 +1247,7 @@ class DeviceListView(DeviceQueryMixin, OrganizerDetailViewMixin, OrganizerPermis
class DeviceCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
model = Device
template_name = 'pretixcontrol/organizers/device_edit.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
form_class = DeviceForm
def get_form_kwargs(self):
@@ -1278,7 +1278,7 @@ class DeviceCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
class DeviceLogView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
template_name = 'pretixcontrol/organizers/device_logs.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:read'
model = LogEntry
context_object_name = 'logs'
paginate_by = 20
@@ -1306,7 +1306,7 @@ class DeviceLogView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
class DeviceUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
model = Device
template_name = 'pretixcontrol/organizers/device_edit.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
context_object_name = 'device'
form_class = DeviceForm
@@ -1349,7 +1349,7 @@ class DeviceUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
class DeviceBulkUpdateView(DeviceQueryMixin, OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, FormView):
template_name = 'pretixcontrol/organizers/device_bulk_edit.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
context_object_name = 'device'
form_class = DeviceBulkEditForm
@@ -1463,7 +1463,7 @@ class DeviceBulkUpdateView(DeviceQueryMixin, OrganizerDetailViewMixin, Organizer
class DeviceConnectView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
model = Device
template_name = 'pretixcontrol/organizers/device_connect.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
context_object_name = 'device'
def get_object(self, queryset=None):
@@ -1495,7 +1495,7 @@ class DeviceConnectView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
class DeviceRevokeView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
model = Device
template_name = 'pretixcontrol/organizers/device_revoke.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
context_object_name = 'device'
def get_object(self, queryset=None):
@@ -2283,7 +2283,7 @@ class RunScheduledExportView(OrganizerPermissionRequiredMixin, ExportMixin, View
class GateListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
model = Gate
template_name = 'pretixcontrol/organizers/gates.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:read'
context_object_name = 'gates'
def get_queryset(self):
@@ -2293,7 +2293,7 @@ class GateListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, L
class GateCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
model = Gate
template_name = 'pretixcontrol/organizers/gate_edit.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
form_class = GateForm
def get_form_kwargs(self):
@@ -2327,7 +2327,7 @@ class GateCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
class GateUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
model = Gate
template_name = 'pretixcontrol/organizers/gate_edit.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
context_object_name = 'gate'
form_class = GateForm
@@ -2362,7 +2362,7 @@ class GateUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
class GateDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CompatDeleteView):
model = Gate
template_name = 'pretixcontrol/organizers/gate_delete.html'
permission = 'organizer.settings.general:write'
permission = 'organizer.devices:write'
context_object_name = 'gate'
def get_object(self, queryset=None):
@@ -2972,7 +2972,7 @@ class SSOClientDeleteView(OrganizerDetailViewMixin, OrganizerPermissionRequiredM
class CustomerListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
model = Customer
template_name = 'pretixcontrol/organizers/customers.html'
permission = 'organizer.customers:write'
permission = 'organizer.customers:read'
context_object_name = 'customers'
def get_queryset(self):
@@ -2993,7 +2993,7 @@ class CustomerListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
class CustomerDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
template_name = 'pretixcontrol/organizers/customer.html'
permission = 'organizer.customers:write'
permission = 'organizer.customers:read'
context_object_name = 'orders'
def get_queryset(self):

View File

@@ -117,7 +117,7 @@ class SubEventList(EventPermissionRequiredMixin, PaginationMixin, SubEventQueryM
model = SubEvent
context_object_name = 'subevents'
template_name = 'pretixcontrol/subevents/index.html'
permission = 'event.settings.general:write'
permission = None
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 = 'event.settings.general:write'
permission = 'event.subevents:write'
context_object_name = 'subevents'
def get_object(self, queryset=None) -> SubEvent:
@@ -508,7 +508,7 @@ class SubEventEditorMixin(MetaDataEditorMixin):
class SubEventUpdate(EventPermissionRequiredMixin, SubEventEditorMixin, UpdateView):
model = SubEvent
template_name = 'pretixcontrol/subevents/detail.html'
permission = 'event.settings.general:write'
permission = 'event.subevents: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 = 'event.settings.general:write'
permission = 'event.subevents:write'
context_object_name = 'subevent'
form_class = SubEventForm
@@ -669,7 +669,7 @@ class SubEventCreate(SubEventEditorMixin, EventPermissionRequiredMixin, CreateVi
class SubEventBulkAction(SubEventQueryMixin, EventPermissionRequiredMixin, View):
permission = 'event.settings.general:write'
permission = 'event.subevents: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 = 'event.settings.general:write'
permission = 'event.subevents: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 = 'event.settings.general:write'
permission = 'event.subevents:write'
form_class = SubEventBulkEditForm
template_name = 'pretixcontrol/subevents/bulk_edit.html'
context_object_name = 'subevent'
@@ -1170,7 +1170,10 @@ class SubEventBulkEdit(SubEventQueryMixin, EventPermissionRequiredMixin, FormVie
kwargs = {}
if self.sampled_quotas is not None:
kwargs['instance'] = self.get_queryset()[0]
try:
kwargs['instance'] = self.get_queryset()[0]
except IndexError:
raise Http404("No matching dates")
formsetclass = inlineformset_factory(
SubEvent, Quota,

View File

@@ -1013,10 +1013,16 @@ def item_meta_values(request, organizer, event):
})
@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):
allowed = (
# This check 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
request.user.has_organizer_permission(request.organizer, "organizer.devices:read", request=request) or
request.user.get_events_with_permission("event.orders:read").filter(organizer=request.organizer).exists()
)
if not allowed:
raise PermissionDenied()
query = request.GET.get('query', '')
try:
page = int(request.GET.get('page', '1'))
@@ -1051,10 +1057,16 @@ def devices_select2(request, **kwargs):
return JsonResponse(doc)
@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):
allowed = (
# This check 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
request.user.has_organizer_permission(request.organizer, "organizer.devices:read", request=request) or
request.user.get_events_with_permission("event.orders:read").filter(organizer=request.organizer).exists()
)
if not allowed:
raise PermissionDenied()
query = request.GET.get('query', '')
try:
page = int(request.GET.get('page', '1'))