Backend UI

This commit is contained in:
Raphael Michel
2025-12-17 16:20:38 +01:00
committed by Raphael Michel
parent 96ac8ef103
commit bd3ade711e
4 changed files with 83 additions and 24 deletions

View File

@@ -403,13 +403,13 @@ class Team(LoggedModel):
)
result = set()
for permission in get_all_event_permissions():
if self.all_event_permissions or self.limit_event_permissions.get(permission.name):
result.add(permission.name)
for permission in get_all_event_permissions().keys():
if self.all_event_permissions or self.limit_event_permissions.get(permission):
result.add(permission)
for permission in get_all_organizer_permissions():
if self.all_organizer_permissions or self.limit_organizer_permissions.get(permission.name):
result.add(permission.name)
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
@@ -447,6 +447,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")

View File

@@ -75,7 +75,8 @@ def get_all_organizer_permissions():
@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, None),
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),
@@ -86,9 +87,9 @@ def register_default_event_permissions(sender, **kwargs):
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:cancel", pgettext_lazy("subevent", "Cancel the entire event or date"), 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),
]
@@ -96,7 +97,8 @@ def register_default_event_permissions(sender, **kwargs):
def register_default_organizer_permissions(sender, **kwargs):
return [
Permission("organizer.events:create", _("Create events"), None, None),
Permission("organizer.settings.general:write", _("Change settings"), 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),
@@ -107,5 +109,5 @@ def register_default_organizer_permissions(sender, **kwargs):
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 inclues the ability to give access to events and date oneself does not have access to.")),
_("This includes the ability to give access to events and data oneself does not have access to.")),
]

View File

@@ -76,6 +76,9 @@ from pretix.base.models import (
)
from pretix.base.models.customers import CustomerSSOClient, CustomerSSOProvider
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,6 +320,44 @@ 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
@@ -323,7 +376,7 @@ 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 not data.get('limit_organizer_permissions', {}).get('organizer.teams:write'):
if not self.instance.organizer.teams.exclude(pk=self.instance.pk).filter(
TeamQuerySet.organizer_permission_q("organizer.teams:write"),
members__isnull=False

View File

@@ -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">