diff --git a/accounts/admin.py b/accounts/admin.py
index 063969b..11bd7e9 100644
--- a/accounts/admin.py
+++ b/accounts/admin.py
@@ -2,6 +2,7 @@ from django.contrib import admin
from accounts.models import Participation, Profile, Transport, Connector
+
admin.site.register(Profile) # FIXME extend user admin
admin.site.register(Participation)
admin.site.register(Transport)
diff --git a/proposals/admin.py b/proposals/admin.py
index c120197..88883a2 100644
--- a/proposals/admin.py
+++ b/proposals/admin.py
@@ -8,7 +8,7 @@ class TalkAdmin(admin.ModelAdmin):
# (it is easy to obtain incoherent data due to site framework)
def has_add_permission(self, request):
return False
- # Filter for 'on site' tocpis and event
+ # Filter for 'on site' topics and event
def get_form(self, request, obj=None, **kwargs):
form = super(TalkAdmin, self).get_form(request, obj, **kwargs)
# in fact, obj should never be none as 'add' button is disabled
diff --git a/proposals/forms.py b/proposals/forms.py
index 4017471..0d90a0e 100644
--- a/proposals/forms.py
+++ b/proposals/forms.py
@@ -7,6 +7,8 @@ from django_select2.forms import Select2TagWidget
from proposals.models import Talk, Topic, Event, Conference
+from accounts.models import Transport
+
STATUS_CHOICES = [
('pending', 'Pending decision'),
@@ -37,7 +39,7 @@ class TalkForm(forms.ModelForm):
}
-class FilterForm(forms.Form):
+class TalkFilterForm(forms.Form):
kind = forms.MultipleChoiceField(
required=False,
widget=forms.CheckboxSelectMultiple,
@@ -62,6 +64,25 @@ class FilterForm(forms.Form):
self.fields['topic'].choices = topics.values_list('slug', 'name')
+class SpeakerFilterForm(forms.Form):
+ transport = forms.MultipleChoiceField(
+ required=False,
+ widget=forms.CheckboxSelectMultiple,
+ choices=Transport.objects.values_list('pk', 'name'),
+ )
+ hosting = forms.MultipleChoiceField(
+ required=False,
+ widget=forms.CheckboxSelectMultiple,
+ choices=[
+ ('hotel', 'Hotel'),
+ ('homestay', 'Homestay'),
+ ],
+ )
+ sound = forms.NullBooleanField()
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+
class TopicCreateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.site_id = kwargs.pop('site_id')
diff --git a/proposals/templates/proposals/speaker_list.html b/proposals/templates/proposals/speaker_list.html
index 958eef2..91172ee 100644
--- a/proposals/templates/proposals/speaker_list.html
+++ b/proposals/templates/proposals/speaker_list.html
@@ -1,22 +1,111 @@
{% extends 'base.html' %}
-{% load i18n %}
+{% load bootstrap3 i18n %}
{% block speakertab %} class="active"{% endblock %}
{% block content %}
-
{% trans "Speakers" %} ({{ user_list|length }})
+{% trans "Speakers" %}
-
-{% for speaker in user_list %}
- -
- {{ speaker.profile }}
- ({{ speaker.talk_set.count }} {% trans "talk" %}{{ speaker.talk_set.count|pluralize }})
+{% trans "Show filtering options…" %}
+
+
+
+
+
+
+
+
+ {% trans "Username" %} |
+ {% trans "Fullname" %} |
+ {% trans "Talk count" %} |
+ {% blocktrans context "table column title" %}Need transport?{% endblocktrans %} |
+ {% blocktrans context "table column title" %}Need hosting?{% endblocktrans %} |
+ {% trans "Need sound?" %} |
+ |
+
+
+ {% for speaker in speaker_list %}
+ {% if forloop.first %}
+
+ {% endif %}
+
+ {{ speaker.user.username }} |
+ {{ speaker.user.get_full_name }} |
+ {{ speaker.talk_set.count }} |
+ {% if speaker.need_transport %}
+
+ {% for transport in speaker.transport.all %}
+ {% if not forloop.first %}, {% endif %}
+ {{ transport }}
+ {% endfor %}
+ |
+ {% else %}
+ — |
+ {% endif %}
+ {% if speaker.need_hosting %}
+
+ {% if speaker.homestay %}
+ Logement chez habitant
+ {% else %}
+ Hotel
+ {% endif %}
+ |
+ {% else %}
+ — |
+ {% endif %}
+ {% if speaker.sound %}
+ Yes |
+ {% else %}
+ No |
+ {% endif %}
+
+ {% trans "Contact" %}
+ |
+
-{% empty %}
- - {% trans "No speakers." %}
-{% endfor %}
-
+ {% if forloop.last %}
+
+ {% endif %}
+ {% endfor %}
+
+
+ {% trans "Total:" %} {{ speaker_list|length }} {% trans "speaker" %}{{ speaker_list|length|pluralize }} |
+
+
+
{% endblock %}
+
+{% block js_end %}
+
+{% endblock %}
diff --git a/proposals/templates/proposals/talk_list.html b/proposals/templates/proposals/talk_list.html
index 8b48892..87c9fca 100644
--- a/proposals/templates/proposals/talk_list.html
+++ b/proposals/templates/proposals/talk_list.html
@@ -8,7 +8,7 @@
{% trans "Talks" %}
-Show filtering options…
+{% trans "Show filtering options…" %}
@@ -26,7 +26,7 @@
{% bootstrap_field filter_form.topic layout="horizontal" %}
-
+
diff --git a/proposals/urls.py b/proposals/urls.py
index 13f082d..a5361ad 100644
--- a/proposals/urls.py
+++ b/proposals/urls.py
@@ -12,12 +12,11 @@ urlpatterns = [
url(r'^talk/edit/(?P[-\w]+)$', views.talk_edit, name='edit-talk'),
url(r'^talk/vote/(?P[-\w]+)/(?P[-0-2]+)$', views.vote, name='vote'),
url(r'^talk/details/(?P[-\w]+)$', views.TalkDetail.as_view(), name='show-talk'),
- #url(r'^talk/by-topic/(?P[-\w]+)$', views.talk_list_by_topic, name='list-talks-by-topic'),
url(r'^talk/accept/(?P[-\w]+)/$', views.talk_decide, {'accepted': True}, name='accept-talk'),
url(r'^talk/decline/(?P[-\w]+)/$', views.talk_decide, {'accepted': False}, name='decline-talk'),
url(r'^topic/$', views.TopicList.as_view(), name='list-topics'),
url(r'^topic/add/$', views.TopicCreate.as_view(), name='add-topic'),
url(r'^topic/(?P[-\w]+)/edit/$', views.TopicUpdate.as_view(), name='edit-topic'),
- url(r'^speakers/$', views.SpeakerList.as_view(), name='list-speakers'),
+ url(r'^speakers/$', views.speaker_list, name='list-speakers'),
url(r'^speaker/(?P[\w.@+-]+)$', views.user_details, name='show-speaker'),
]
diff --git a/proposals/views.py b/proposals/views.py
index fed32de..94a5e6c 100644
--- a/proposals/views.py
+++ b/proposals/views.py
@@ -20,7 +20,7 @@ from accounts.decorators import orga_required, staff_required
from conversations.models import ConversationWithParticipant, ConversationAboutTalk, Message
-from .forms import TalkForm, TopicCreateForm, TopicUpdateForm, ConferenceForm, FilterForm, STATUS_VALUES
+from .forms import TalkForm, TopicCreateForm, TopicUpdateForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm
from .models import Talk, Topic, Vote, Conference
from .signals import talk_added, talk_edited
from .utils import allowed_talks, markdown_to_html
@@ -64,7 +64,7 @@ def participate(request):
def talk_list(request):
show_filters = False
talks = Talk.objects.filter(site=get_current_site(request))
- filter_form = FilterForm(request.GET or None, site=get_current_site(request))
+ filter_form = TalkFilterForm(request.GET or None, site=get_current_site(request))
# Filtering
if filter_form.is_valid():
data = filter_form.cleaned_data
@@ -192,14 +192,6 @@ class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
return TopicCreateForm if self.request.user.is_superuser else TopicUpdateForm
-class SpeakerList(StaffRequiredMixin, ListView):
- template_name = 'proposals/speaker_list.html'
-
- def get_queryset(self):
- site = get_current_site(self.request)
- return User.objects.filter(talk__in=Talk.objects.filter(site=site)).all().distinct()
-
-
@login_required
def vote(request, talk, score):
talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
@@ -242,6 +234,36 @@ def talk_decide(request, talk, accepted):
})
+@staff_required
+def speaker_list(request):
+ show_filters = False
+ site = get_current_site(request)
+ speakers = Participation.objects.filter(user__talk__in=Talk.objects.filter(site=site)).all().distinct()
+ filter_form = SpeakerFilterForm(request.GET or None)
+ # Filtering
+ if filter_form.is_valid():
+ data = filter_form.cleaned_data
+ if len(data['transport']):
+ show_filters = True
+ speakers = speakers.filter(reduce(lambda x, y: x | y, [Q(transport__pk=pk) for pk in data['transport']]))
+ if len(data['hosting']):
+ show_filters = True
+ queries = []
+ if 'hotel' in data['hosting']:
+ queries += [ Q(need_hosting=True, homestay=False) ]
+ if 'homestay' in data['hosting']:
+ queries += [ Q(need_hosting=True, homestay=True) ]
+ speakers = speakers.filter(reduce(lambda x, y: x | y, queries))
+ if data['sound'] != None:
+ show_filters = True
+ speakers = speakers.filter(sound=data['sound'])
+ return render(request, 'proposals/speaker_list.html', {
+ 'speaker_list': speakers,
+ 'filter_form': filter_form,
+ 'show_filters': show_filters,
+ })
+
+
@login_required
def user_details(request, username):
user = get_object_or_404(User, username=username)