diff --git a/ponyconf/static/css/ponyconf.css b/ponyconf/static/css/ponyconf.css
index e69de29..af37051 100644
--- a/ponyconf/static/css/ponyconf.css
+++ b/ponyconf/static/css/ponyconf.css
@@ -0,0 +1,3 @@
+tr.clickable-row {
+ cursor: pointer;
+}
diff --git a/proposals/forms.py b/proposals/forms.py
index 0c2ad92..4017471 100644
--- a/proposals/forms.py
+++ b/proposals/forms.py
@@ -1,4 +1,4 @@
-from django.forms import CheckboxSelectMultiple, ModelForm
+from django import forms
from django.forms.models import modelform_factory
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
@@ -8,7 +8,19 @@ from django_select2.forms import Select2TagWidget
from proposals.models import Talk, Topic, Event, Conference
-class TalkForm(ModelForm):
+STATUS_CHOICES = [
+ ('pending', 'Pending decision'),
+ ('accepted', 'Accepted'),
+ ('declined', 'Declined'),
+]
+STATUS_VALUES = [
+ ('pending', None),
+ ('accepted', True),
+ ('declined', False),
+]
+
+
+class TalkForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
site = kwargs.pop('site')
super(TalkForm, self).__init__(*args, **kwargs)
@@ -18,14 +30,39 @@ class TalkForm(ModelForm):
class Meta:
model = Talk
fields = ['title', 'abstract', 'description', 'topics', 'notes', 'event', 'speakers']
- widgets = {'topics': CheckboxSelectMultiple(), 'speakers': Select2TagWidget()}
+ widgets = {'topics': forms.CheckboxSelectMultiple(), 'speakers': Select2TagWidget()}
help_texts = {
'abstract': _('Should be less than 255 characters'),
'notes': _('If you want to add some precisions for the organizers.'),
}
-class TopicCreateForm(ModelForm):
+class FilterForm(forms.Form):
+ kind = forms.MultipleChoiceField(
+ required=False,
+ widget=forms.CheckboxSelectMultiple,
+ choices=[],
+ )
+ status = forms.MultipleChoiceField(
+ required=False,
+ widget=forms.CheckboxSelectMultiple,
+ choices=STATUS_CHOICES,
+ )
+ topic = forms.MultipleChoiceField(
+ required=False,
+ widget=forms.CheckboxSelectMultiple,
+ choices=[],
+ )
+ def __init__(self, *args, **kwargs):
+ site = kwargs.pop('site')
+ super().__init__(*args, **kwargs)
+ events = Event.objects.filter(site=site)
+ self.fields['kind'].choices = events.values_list('pk', 'name')
+ topics = Topic.objects.filter(site=site)
+ self.fields['topic'].choices = topics.values_list('slug', 'name')
+
+
+class TopicCreateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.site_id = kwargs.pop('site_id')
super(TopicCreateForm, self).__init__(*args, **kwargs)
diff --git a/proposals/models.py b/proposals/models.py
index 9460103..7af4ab8 100644
--- a/proposals/models.py
+++ b/proposals/models.py
@@ -42,7 +42,7 @@ class Topic(PonyConfModel):
return self.name
def get_absolute_url(self):
- return reverse('list-talks-by-topic', kwargs={'topic': self.slug})
+ return reverse('list-talks') + '?filter=topic:%s' % self.slug
class Event(models.Model):
@@ -52,6 +52,7 @@ class Event(models.Model):
class Meta:
unique_together = ('site', 'name')
+ ordering = ('pk',)
def __str__(self):
return ugettext(self.name)
diff --git a/proposals/templates/proposals/_talk_list.html b/proposals/templates/proposals/_talk_list.html
index 8520ca7..1f2d51c 100644
--- a/proposals/templates/proposals/_talk_list.html
+++ b/proposals/templates/proposals/_talk_list.html
@@ -13,7 +13,7 @@
{% if talk.topics.exists %}
{% trans "in" %}
{% for topic in talk.topics.all %}
- {{ topic }}
+ {{ topic }}
{% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
{% endfor %}
{% endif %}
diff --git a/proposals/templates/proposals/talk_detail.html b/proposals/templates/proposals/talk_detail.html
index 3601aa8..75643ae 100644
--- a/proposals/templates/proposals/talk_detail.html
+++ b/proposals/templates/proposals/talk_detail.html
@@ -38,7 +38,7 @@
{% for topic in talk.topics.all %}
{% if forloop.first %}
{% endif %}
{% empty %}
{% trans "No topics." %}
diff --git a/proposals/templates/proposals/talk_list.html b/proposals/templates/proposals/talk_list.html
index e00cd0c..9b3d21e 100644
--- a/proposals/templates/proposals/talk_list.html
+++ b/proposals/templates/proposals/talk_list.html
@@ -1,11 +1,101 @@
{% extends 'base.html' %}
+{% load bootstrap3 i18n %}
+
{% block talktab %} class="active"{% endblock %}
{% block content %}
-{{ title }}
+{% trans "Talks" %}
-{% include "proposals/_talk_list.html" %}
+Show filtering options…
+
+
+
+
+
+
+
+
+ {% trans "Title" %} |
+ {% trans "Intervention kind" %} |
+ {% trans "Speakers" %} |
+ {% trans "Topics" %} |
+ {% trans "Status" %} |
+
+
+ {% for talk in talk_list %}
+ {% if forloop.first %}
+
+ {% endif %}
+
+ {{ talk.title }} |
+ {{ talk.event }} |
+
+ {% for speaker in talk.speakers.all %}
+ {{ speaker }}
+ {% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
+ {% empty %}–
+ {% endfor %}
+ |
+
+ {% for topic in talk.topics.all %}
+ {{ topic }}
+ {% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
+ {% empty %}–
+ {% endfor %}
+ |
+
+ {% if talk.accepted == True %}
+ {% trans "Accepted" %}
+ {% elif talk.accepted == False %}
+ {% trans "Declined" %}
+ {% else %}
+ {% blocktrans with score=talk.score %}Pending, score: {{ score }}{% endblocktrans %}
+ {% endif %}
+ |
+
+ {% if forloop.last%}
+
+ {% endif %}
+ {% endfor %}
+
+
+ {% trans "Total:" %} {{ talk_list|length }} {% trans "talk" %}{{ talk_list|length|pluralize }} |
+
+
+
{% endblock %}
+
+{% block js_end %}
+
+{% endblock %}
diff --git a/proposals/templates/proposals/talks.html b/proposals/templates/proposals/talks.html
deleted file mode 100644
index dcc1355..0000000
--- a/proposals/templates/proposals/talks.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{% extends 'base.html' %}
-
-{% load i18n %}
-
-{% block talktab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% trans "Talks" %}
-
-{% trans "Propose a talk" %}
-
-{% if my_talks %}
- {% trans "My participing talks" %}
- {% include "proposals/_talk_list.html" with talk_list=my_talks %}
-{% endif %}
-
-{% if other_talks %}
- {% trans "Others talks" %}
- {% include "proposals/_talk_list.html" with talk_list=other_talks %}
-{% endif %}
-
-{% endblock %}
diff --git a/proposals/urls.py b/proposals/urls.py
index 85c2bfa..13f082d 100644
--- a/proposals/urls.py
+++ b/proposals/urls.py
@@ -12,7 +12,7 @@ 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/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'),
diff --git a/proposals/views.py b/proposals/views.py
index 29be02e..5fc41da 100644
--- a/proposals/views.py
+++ b/proposals/views.py
@@ -1,3 +1,5 @@
+from functools import reduce
+
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
@@ -18,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
+from .forms import TalkForm, TopicCreateForm, TopicUpdateForm, ConferenceForm, FilterForm, STATUS_VALUES
from .models import Talk, Topic, Vote, Conference
from .signals import talk_added, talk_edited
from .utils import allowed_talks, markdown_to_html
@@ -50,7 +52,7 @@ def conference(request):
@login_required
def participate(request):
- talks = Talk.objects.filter(site=get_current_site(request))#.filter(Q(speakers=request.user) | Q(proposer=request.user)).distinct()
+ talks = Talk.objects.filter(site=get_current_site(request))
my_talks = talks.filter(speakers=request.user)
proposed_talks = talks.exclude(speakers=request.user).filter(proposer=request.user)
return render(request, 'proposals/participate.html', {
@@ -60,20 +62,24 @@ def participate(request):
@staff_required
def talk_list(request):
- talks = allowed_talks(Talk.objects.filter(site=get_current_site(request)), 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))
+ if filter_form.is_valid():
+ data = filter_form.cleaned_data
+ if len(data['kind']):
+ talks = talks.filter(reduce(lambda x, y: x | y, [Q(event__pk=pk) for pk in data['kind']]))
+ if len(data['status']):
+ talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
+ if len(data['topic']):
+ talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug=topic) for topic in data['topic']]))
+ show_filters = True
return render(request, 'proposals/talk_list.html', {
- 'title': _('Talks') + ' (%d)' % len(talks),
+ 'show_filters': show_filters,
'talk_list': talks,
+ 'filter_form': filter_form,
})
-
-@login_required
-def talk_list_by_topic(request, topic):
- topic = get_object_or_404(Topic, slug=topic)
- talks = allowed_talks(Talk.objects.filter(site=topic.site, topics=topic), request)
- return render(request, 'proposals/talk_list.html', {'title': _('Talks related to %s:') % topic, 'talk_list': talks})
-
-
@login_required
def talk_edit(request, talk=None):
if talk: