diff --git a/cfp/forms.py b/cfp/forms.py index 1579aab..c91a5a3 100644 --- a/cfp/forms.py +++ b/cfp/forms.py @@ -125,6 +125,35 @@ class ParticipantStaffForm(ParticipantForm): } +class ParticipantFilterForm(forms.Form): + category = forms.MultipleChoiceField( + label=_('Category'), + required=False, + widget=forms.CheckboxSelectMultiple, + choices=[], + ) + status = forms.MultipleChoiceField( + label=_('Status'), + required=False, + widget=forms.CheckboxSelectMultiple, + choices=STATUS_CHOICES, + ) + track = forms.MultipleChoiceField( + label=_('Track'), + required=False, + widget=forms.CheckboxSelectMultiple, + choices=[], + ) + + def __init__(self, *args, **kwargs): + site = kwargs.pop('site') + super().__init__(*args, **kwargs) + categories = TalkCategory.objects.filter(site=site) + self.fields['category'].choices = categories.values_list('pk', 'name') + tracks = Track.objects.filter(site=site) + self.fields['track'].choices = [('none', _('Not assigned'))] + list(tracks.values_list('slug', 'name')) + + class UsersWidget(ModelSelect2MultipleWidget): model = User search_fields = [ '%s__icontains' % field for field in UserAdmin.search_fields ] diff --git a/cfp/models.py b/cfp/models.py index cd72dc9..9333e2c 100644 --- a/cfp/models.py +++ b/cfp/models.py @@ -4,7 +4,7 @@ from django.core.urlresolvers import reverse from django.core.validators import MaxValueValidator, MinValueValidator from django.core.exceptions import ValidationError from django.db import models -from django.db.models import Q, Sum, Avg, Case, When +from django.db.models import Q, Count, Avg, Case, When from django.db.models.functions import Coalesce from django.utils import timezone from django.utils.translation import ugettext, ugettext_lazy as _ @@ -69,9 +69,9 @@ class ParticipantManager(models.Manager): def get_queryset(self): qs = super().get_queryset() qs = qs.annotate( - accepted_talk_count=Sum(Case(When(talk__accepted=True, then=1), default=0, output_field=models.IntegerField())), - pending_talk_count=Sum(Case(When(talk__accepted=None, then=1), default=0, output_field=models.IntegerField())), - refused_talk_count=Sum(Case(When(talk__accepted=False, then=1), default=0, output_field=models.IntegerField())), + accepted_talk_count=Count(Case(When(talk__accepted=True, then='talk__pk'), output_field=models.IntegerField()), distinct=True), + pending_talk_count=Count(Case(When(talk__accepted=None, then='talk__pk'), output_field=models.IntegerField()), distinct=True), + refused_talk_count=Count(Case(When(talk__accepted=False, then='talk__pk'), output_field=models.IntegerField()), distinct=True), ) return qs diff --git a/cfp/templates/cfp/staff/participant_list.html b/cfp/templates/cfp/staff/participant_list.html index ea90495..d2afe24 100644 --- a/cfp/templates/cfp/staff/participant_list.html +++ b/cfp/templates/cfp/staff/participant_list.html @@ -7,30 +7,16 @@

{% trans "Speakers" %}

-{% comment %} -{% trans "Show filtering options…" %} - -

+

{% trans "Show filtering options…" %}

- {% bootstrap_field filter_form.transport layout="horizontal" %} - {% bootstrap_field filter_form.transport_booked layout="horizontal" %} - {% bootstrap_field filter_form.sound layout="horizontal" %} -
-
- {% bootstrap_field filter_form.accommodation layout="horizontal" %} - {% bootstrap_field filter_form.accommodation_booked layout="horizontal" %} + {% bootstrap_field filter_form.category layout="horizontal" %} {% bootstrap_field filter_form.status layout="horizontal" %}
-
-
-
- {% bootstrap_field filter_form.topic layout="horizontal" %} -
{% bootstrap_field filter_form.track layout="horizontal" %}
@@ -39,7 +25,6 @@
-{% endcomment %} {% endcomment %} - {% comment %} - {% endcomment %} {% for participant in participant_list %} {% if forloop.first %} @@ -84,16 +67,3 @@
{% trans "Total:" %} {{ participant_list|length }} {% trans "speaker" %}{{ participant_list|length|pluralize }} @@ -51,13 +36,11 @@ {% comment %}
{% trans "Contact:" %} {% trans "link" %}
{% endblock %} - -{% comment %} -{% block js_end %} - -{% endblock %} -{% endcomment %} diff --git a/cfp/templates/cfp/staff/talk_list.html b/cfp/templates/cfp/staff/talk_list.html index 36025d1..a861c2a 100644 --- a/cfp/templates/cfp/staff/talk_list.html +++ b/cfp/templates/cfp/staff/talk_list.html @@ -7,9 +7,7 @@

{% trans "Talks" %}

-{% trans "Show filtering options…" %} - -

+

{% trans "Show filtering options…" %}

diff --git a/cfp/views.py b/cfp/views.py index b27638b..329bc56 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -18,8 +18,9 @@ from .decorators import staff_required from .mixins import StaffRequiredMixin, OnSiteMixin from .utils import is_staff from .models import Participant, Talk, TalkCategory, Vote, Track, Room -from .forms import TalkForm, TalkStaffForm, TalkFilterForm, TalkActionForm, ParticipantForm, \ - ParticipantStaffForm, ConferenceForm, CreateUserForm, STATUS_VALUES, TrackForm, RoomForm +from .forms import TalkForm, TalkStaffForm, TalkFilterForm, TalkActionForm, \ + ParticipantForm, ParticipantStaffForm, ParticipantFilterForm, \ + ConferenceForm, CreateUserForm, STATUS_VALUES, TrackForm, RoomForm def home(request): @@ -137,10 +138,10 @@ def staff(request): @staff_required def talk_list(request): - show_filters = False talks = Talk.objects.filter(site=request.conference.site) - filter_form = TalkFilterForm(request.GET or None, site=request.conference.site) # Filtering + show_filters = False + filter_form = TalkFilterForm(request.GET or None, site=request.conference.site) if filter_form.is_valid(): data = filter_form.cleaned_data if len(data['category']): @@ -290,8 +291,34 @@ def participant_list(request): participants = Participant.objects.filter(site=request.conference.site) \ .extra(select={'lower_name': 'lower(name)'}) \ .order_by('lower_name') + # Filtering + show_filters = False + filter_form = ParticipantFilterForm(request.GET or None, site=request.conference.site) + if filter_form.is_valid(): + data = filter_form.cleaned_data + talks = Talk.objects.filter(site=request.conference.site) + if len(data['category']): + show_filters = True + talks = talks.filter(reduce(lambda x, y: x | y, [Q(category__pk=pk) for pk in data['category']])) + if len(data['status']): + show_filters = True + talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']])) + if len(data['track']): + show_filters = True + q = Q() + if 'none' in data['track']: + data['track'].remove('none') + q |= Q(track__isnull=True) + if len(data['track']): + q |= Q(track__slug__in=data['track']) + talks = talks.filter(q) + participants = participants.filter(talk__in=talks) + contact_link = 'mailto:' + ','.join([participant.email for participant in participants.all()]) return render(request, 'cfp/staff/participant_list.html', { + 'filter_form': filter_form, 'participant_list': participants, + 'show_filters': show_filters, + 'contact_link': contact_link, })