From cc970caad826ae1606d0f90c89917188c7dea456 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 28 Oct 2019 22:03:09 +0100 Subject: [PATCH] Allow to filter global event list using organizer parameters --- src/pretix/control/forms/filter.py | 77 ++++++++++++------- .../templates/pretixcontrol/events/index.html | 46 +++++++---- .../pretixcontrol/organizers/detail.html | 1 - src/pretix/control/views/main.py | 3 + .../static/pretixcontrol/scss/_forms.scss | 6 ++ 5 files changed, 87 insertions(+), 46 deletions(-) diff --git a/src/pretix/control/forms/filter.py b/src/pretix/control/forms/filter.py index 4e3651d0b..719a3e9bf 100644 --- a/src/pretix/control/forms/filter.py +++ b/src/pretix/control/forms/filter.py @@ -5,13 +5,15 @@ from django.apps import apps from django.db.models import Exists, F, OuterRef, Q from django.db.models.functions import Coalesce, ExtractWeekDay from django.urls import reverse, reverse_lazy +from django.utils.functional import cached_property from django.utils.timezone import get_current_timezone, make_aware, now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from pretix.base.forms.widgets import DatePickerWidget from pretix.base.models import ( - Checkin, Event, EventMetaValue, Invoice, Item, Order, OrderPayment, - OrderPosition, OrderRefund, Organizer, Question, QuestionAnswer, SubEvent, + Checkin, Event, EventMetaProperty, EventMetaValue, Invoice, Item, Order, + OrderPayment, OrderPosition, OrderRefund, Organizer, Question, + QuestionAnswer, SubEvent, ) from pretix.base.signals import register_payment_providers from pretix.control.forms.widgets import Select2 @@ -572,21 +574,25 @@ class EventFilterForm(FilterForm): ) def __init__(self, *args, **kwargs): - request = kwargs.pop('request') + self.request = kwargs.pop('request') self.organizer = kwargs.pop('organizer', None) super().__init__(*args, **kwargs) + seen = set() + for p in self.meta_properties.all(): + if p.name in seen: + continue + seen.add(p.name) + self.fields['meta_{}'.format(p.name)] = forms.CharField( + label=p.name, required=False + ) if self.organizer: del self.fields['organizer'] - for p in self.organizer.meta_properties.all(): - self.fields['meta_{}'.format(p.name)] = forms.CharField( - label=p.name, required=False - ) else: - if request.user.has_active_staff_session(request.session.session_key): + if self.request.user.has_active_staff_session(self.request.session.session_key): self.fields['organizer'].queryset = Organizer.objects.all() else: self.fields['organizer'].queryset = Organizer.objects.filter( - pk__in=request.user.teams.values_list('organizer', flat=True) + pk__in=self.request.user.teams.values_list('organizer', flat=True) ) def filter_qs(self, qs): @@ -636,31 +642,46 @@ class EventFilterForm(FilterForm): Q(name__icontains=i18ncomp(query)) | Q(slug__icontains=query) ) - if self.organizer: - for i, p in enumerate(self.organizer.meta_properties.all()): - d = fdata.get('meta_{}'.format(p.name)) - if d: - emv_with_value = EventMetaValue.objects.filter( - event=OuterRef('pk'), - property__name=p.name, - value=d - ) - emv_with_any_value = EventMetaValue.objects.filter( - event=OuterRef('pk'), - property__name=p.name, - ) - qs = qs.annotate(**{'attr_{}'.format(i): Exists(emv_with_value)}) - filters = Q(**{'attr_{}'.format(i): True}) - if p.default == d: - qs = qs.annotate(**{'attr_{}_any'.format(i): Exists(emv_with_any_value)}) - filters |= Q(**{'attr_{}_any'.format(i): False}) - qs = qs.filter(filters) + filters_by_property_name = {} + for i, p in enumerate(self.meta_properties): + d = fdata.get('meta_{}'.format(p.name)) + if d: + emv_with_value = EventMetaValue.objects.filter( + event=OuterRef('pk'), + property__pk=p.pk, + value=d + ) + emv_with_any_value = EventMetaValue.objects.filter( + event=OuterRef('pk'), + property__pk=p.pk, + ) + qs = qs.annotate(**{'attr_{}'.format(i): Exists(emv_with_value)}) + if p.name in filters_by_property_name: + filters_by_property_name[p.name] |= Q(**{'attr_{}'.format(i): True}) + else: + filters_by_property_name[p.name] = Q(**{'attr_{}'.format(i): True}) + if p.default == d: + qs = qs.annotate(**{'attr_{}_any'.format(i): Exists(emv_with_any_value)}) + filters_by_property_name[p.name] |= Q(**{'attr_{}_any'.format(i): False, 'organizer_id': p.organizer_id}) + for f in filters_by_property_name.values(): + qs = qs.filter(f) if fdata.get('ordering'): qs = qs.order_by(self.get_order_by()) return qs + @cached_property + def meta_properties(self): + if self.organizer: + return self.organizer.meta_properties.all() + else: + # We ignore superuser permissions here. This is intentional – we do not want to show super + # users a form with all meta properties ever assigned. + return EventMetaProperty.objects.filter( + organizer_id__in=self.request.user.teams.values_list('organizer', flat=True) + ) + class CheckInFilterForm(FilterForm): orders = { diff --git a/src/pretix/control/templates/pretixcontrol/events/index.html b/src/pretix/control/templates/pretixcontrol/events/index.html index d94d28228..eca4f42c8 100644 --- a/src/pretix/control/templates/pretixcontrol/events/index.html +++ b/src/pretix/control/templates/pretixcontrol/events/index.html @@ -20,25 +20,37 @@ {% else %} -
-
- {% bootstrap_field filter_form.query layout='inline' %} +
+
+

{% trans "Filter" %}

-
- {% bootstrap_field filter_form.status layout='inline' %} +
+ +
+
+ {% bootstrap_field filter_form.query layout='inline' %} +
+
+ {% bootstrap_field filter_form.status layout='inline' %} +
+
+ {% bootstrap_field filter_form.organizer layout='inline' %} +
+ {% for mf in meta_fields %} +
+ {% bootstrap_field mf layout='inline' %} +
+ {% endfor %} +
+
+ +
+
-
- {% bootstrap_field filter_form.organizer layout='inline' %} -
-
- -
- +

diff --git a/src/pretix/control/templates/pretixcontrol/organizers/detail.html b/src/pretix/control/templates/pretixcontrol/organizers/detail.html index 0846f87d4..fa8374291 100644 --- a/src/pretix/control/templates/pretixcontrol/organizers/detail.html +++ b/src/pretix/control/templates/pretixcontrol/organizers/detail.html @@ -37,7 +37,6 @@

{% endfor %}
-