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…" %}
-{% endcomment %}
{% trans "Total:" %} {{ participant_list|length }} {% trans "speaker" %}{{ participant_list|length|pluralize }}
@@ -51,13 +36,11 @@
{% comment %} | {% endcomment %}
- {% comment %}
{% trans "Contact:" %} {% trans "link" %} |
- {% endcomment %}
{% for participant in participant_list %}
{% if forloop.first %}
@@ -84,16 +67,3 @@
{% 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,
})