Compare commits

...

5 Commits

Author SHA1 Message Date
Mira Weller
a4a599a6de fix out-of-the-box experience 2026-03-19 13:54:07 +01:00
Kara Engelhardt
e63bc09216 Use correct first page number in control pagination
This worked accidentally because page_obj.num_pages does not exists (page_obj.paginator.num_pages does) which made url_replace remove the page parameter
2026-03-19 13:19:10 +01:00
Kara Engelhardt
f8bbb3d3bb Fix crash in CheckinList export (PRETIXEU-D59) 2026-03-19 11:08:11 +01:00
Raphael Michel
58840a5fd6 Hotfix for exporters via API (#6007)
* Hotfix for exporters via API

* Apply suggestion from @raphaelm
2026-03-18 15:50:05 +01:00
Raphael Michel
e1b8e16a34 Permissions: Fix staff session handling for organizer exports (#6005) 2026-03-18 13:23:26 +01:00
10 changed files with 23 additions and 11 deletions

View File

@@ -75,7 +75,8 @@ class JobRunSerializer(serializers.Serializer):
def to_representation(self, instance):
# Translate between events as a list of slugs (API) and list of ints (database)
if self.ex.is_multievent and not isinstance(self.ex, OrganizerLevelExportMixin) and "events" in instance and isinstance(instance["events"], list):
instance["events"] = [e.slug for e in self.ex.events.filter(pk__in=instance["events"]).only("slug")]
instance["events"] = [e for e in self.ex.events.filter(pk__in=instance["events"])]
instance = super().to_representation(instance)
return instance
def to_internal_value(self, data):

View File

@@ -65,8 +65,9 @@ def form_field_to_serializer_field(field):
if isinstance(field, m_from):
return m_to(
required=field.required,
allow_null=not field.required,
allow_null=not field.required and not isinstance(field, forms.BooleanField),
validators=field.validators,
initial=field.initial,
**{kwarg: getattr(field, kwarg, None) for kwarg in m_kwargs}
)

View File

@@ -257,7 +257,7 @@ def init_organizer_exporters(
if permission_name not in _event_list_cache:
if staff_session:
events = event_qs.all()
events = event_qs.all() if event_qs else organizer.events.all()
elif event_qs is not None:
events = event_qs.filter(
pk__in=perm_holder.get_events_with_permission(
@@ -292,7 +292,7 @@ def init_organizer_exporters(
elif device:
_has_permission_on_any_team_cache[permission_name] = device.has_event_permission(permission_name)
if not _has_permission_on_any_team_cache[permission_name]:
if not _has_permission_on_any_team_cache[permission_name] and not staff_session:
continue
exporter: BaseExporter = response(event=_event_list_cache[permission_name], organizer=organizer, **kwargs)

View File

@@ -363,7 +363,7 @@ def get_global_navigation(request):
'icon': 'dashboard',
},
]
if request.user.is_in_any_teams:
if request.user.is_in_any_teams or request.user.is_staff:
nav += [
{
'label': _('Events'),

View File

@@ -8,7 +8,7 @@
{% if page_obj.has_previous %}
{% if page_obj.previous_page_number > 1 %}
<li>
<a href="?{% url_replace request 'page' page_obj.num_pages %}" title="{% trans "Go to page 1" %}">
<a href="?{% url_replace request 'page' 1 %}" title="{% trans "Go to page 1" %}">
<span class="fa fa-angle-double-left"></span>
</a>
</li>

View File

@@ -641,7 +641,7 @@ def user_index(request):
ctx = {
'widgets': rearrange(widgets),
'can_create_event': request.user.teams.with_organizer_permission("organizer.events:create").exists(),
'can_create_event': request.user.teams.with_organizer_permission("organizer.events:create").exists() or request.user.is_staff,
'upcoming': widgets_for_event_qs(
request,
annotated_event_query(request, lazy=True).filter(

View File

@@ -2649,7 +2649,10 @@ class OrderGo(EventPermissionRequiredMixin, View):
class ExportMixin:
@cached_property
def exporters(self):
raw_exporters = list(init_event_exporters(self.request.event, user=self.request.user, request=self.request))
raw_exporters = list(init_event_exporters(
self.request.event, user=self.request.user, request=self.request,
staff_session=self.request.user.has_active_staff_session(self.request.session.session_key),
))
return sorted(
raw_exporters,
key=lambda ex: (0 if ex.category else 1, ex.category or "", 0 if ex.featured else 1, str(ex.verbose_name).lower())

View File

@@ -2025,7 +2025,10 @@ class ExportMixin:
@cached_property
def exporters(self):
raw_exporters = list(init_organizer_exporters(self.request.organizer, user=self.request.user, request=self.request))
raw_exporters = list(init_organizer_exporters(
self.request.organizer, user=self.request.user, request=self.request,
staff_session=self.request.user.has_active_staff_session(self.request.session.session_key),
))
return sorted(
raw_exporters,
key=lambda ex: (

View File

@@ -503,7 +503,7 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
if cl.include_pending:
headers.append(_('Paid'))
if form_data['secrets']:
if form_data.get('secrets', False):
headers.append(_('Secret'))
headers.append(_('Email'))
@@ -603,7 +603,7 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
]
if cl.include_pending:
row.append(_('Yes') if op.order.status == Order.STATUS_PAID else _('No'))
if form_data['secrets']:
if form_data.get('secrets', False):
row.append(op.secret)
row.append(op.attendee_email or (op.addon_to.attendee_email if op.addon_to else '') or op.order.email or '')
row.append(str(op.order.phone) if op.order.phone else '')

View File

@@ -493,6 +493,7 @@ def org_scheduled_export(organizer, user):
@pytest.mark.django_db
def test_org_scheduled_export_list_token(token_client, organizer, user, team, org_scheduled_export):
res = dict(TEST_SCHEDULED_EXPORT_RES)
res["export_form_data"]["event_date_range"] = None
res["id"] = org_scheduled_export.pk
res["schedule_next_run"] = org_scheduled_export.schedule_next_run.astimezone(zoneinfo.ZoneInfo("UTC")). \
isoformat().replace("+00:00", "Z")
@@ -518,6 +519,7 @@ def test_org_scheduled_export_list_user(user_client, organizer, user, team, org_
team.members.add(user2)
res = dict(TEST_SCHEDULED_EXPORT_RES)
res["export_form_data"]["event_date_range"] = None
res["id"] = org_scheduled_export.pk
res["schedule_next_run"] = org_scheduled_export.schedule_next_run.astimezone(zoneinfo.ZoneInfo("UTC")). \
isoformat().replace("+00:00", "Z")
@@ -545,6 +547,7 @@ def test_org_scheduled_export_list_user(user_client, organizer, user, team, org_
@pytest.mark.django_db
def test_org_scheduled_export_detail(token_client, organizer, user, org_scheduled_export):
res = dict(TEST_SCHEDULED_EXPORT_RES)
res["export_form_data"]["event_date_range"] = None
res["id"] = org_scheduled_export.pk
res["schedule_next_run"] = org_scheduled_export.schedule_next_run.astimezone(zoneinfo.ZoneInfo("UTC")). \
isoformat().replace("+00:00", "Z")
@@ -959,6 +962,7 @@ def test_organizer_edit_restrictions(client, event, organizer, user, team):
organizer=organizer,
owner=user2,
export_identifier="giftcardlist",
export_form_data={"_format": "xlsx"},
mail_subject="Test",
mail_template="Test",
locale="en",