talk list, with filtering capabilities

This commit is contained in:
Élie Bouttier 2016-09-18 02:00:46 +02:00
parent 1d8d03b2f5
commit 9bc2ed1c92
9 changed files with 159 additions and 45 deletions

View File

@ -0,0 +1,3 @@
tr.clickable-row {
cursor: pointer;
}

View File

@ -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)

View File

@ -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)

View File

@ -13,7 +13,7 @@
{% if talk.topics.exists %}
<i>{% trans "in" %}</i>
{% for topic in talk.topics.all %}
<a href="{% url 'list-talks-by-topic' topic.slug %}">{{ topic }}</a>
<a href="{{ topic.get_full_url }}">{{ topic }}</a>
{% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
{% endfor %}
{% endif %}

View File

@ -38,7 +38,7 @@
{% for topic in talk.topics.all %}
{% if forloop.first %}<ul>{% endif %}
<li><a href="{% url 'list-talks-by-topic' topic.slug %}">{{ topic }}</a></li>
<li><a href="{{ topic.get_full_url }}">{{ topic }}</a></li>
{% if forloop.last %}</ul>{% endif %}
{% empty %}
<i>{% trans "No topics." %}</i>

View File

@ -1,11 +1,101 @@
{% extends 'base.html' %}
{% load bootstrap3 i18n %}
{% block talktab %} class="active"{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<h1>{% trans "Talks" %}</h1>
{% include "proposals/_talk_list.html" %}
<a class="btn btn-primary" role="button" data-toggle="collapse" href="#filter" aria-expanded="{{ show_filters|yesno:"true,false" }}" aria-controls="filter">Show filtering options…</a>
<br /><br />
<div class="collapse{{ show_filters|yesno:" in," }}" id="filter">
<div class="well">
<form class="form-horizontal" method="get">
<div class="row">
<div class="col-md-4 col-xs-6">
{% bootstrap_field filter_form.kind layout="horizontal" %}
</div>
<div class="col-md-4 col-xs-6">
{% bootstrap_field filter_form.status layout="horizontal" %}
</div>
<div class="col-md-4 col-xs-6">
{% bootstrap_field filter_form.topic layout="horizontal" %}
</div>
</div>
<input type="submit" class="btn btn-success" value="Filter">
</form>
</div>
</div>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th class="text-center">{% trans "Title" %} <a href="#"><span class="glyphicon glyphicon-sort pull-right"></span></a></th>
<th class="text-center">{% trans "Intervention kind" %} <a href="#"><span class="glyphicon glyphicon-sort pull-right"></span></a></th>
<th class="text-center">{% trans "Speakers" %} <a href="#"><span class="glyphicon glyphicon-sort pull-right"></span></a></th>
<th class="text-center">{% trans "Topics" %} <a href="#"><span class="glyphicon glyphicon-sort pull-right"></span></a></th>
<th class="text-center">{% trans "Status" %} <a href="#"><span class="glyphicon glyphicon-sort pull-right"></span></a></th>
</tr>
</thead>
{% for talk in talk_list %}
{% if forloop.first %}
<tbody>
{% endif %}
<tr class="clickable-row" data-href="{% url 'show-talk' talk.slug %}">
<td class="{{ talk.accepted|yesno:"success,danger,warning" }}">{{ talk.title }}</td>
<td class="{{ talk.accepted|yesno:"success,danger,warning" }}">{{ talk.event }}</td>
<td class="{{ talk.accepted|yesno:"success,danger,warning" }}">
{% for speaker in talk.speakers.all %}
{{ speaker }}
{% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
{% empty %}
{% endfor %}
</td>
<td class="{{ talk.accepted|yesno:"success,danger,warning" }}">
{% for topic in talk.topics.all %}
{{ topic }}
{% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
{% empty %}
{% endfor %}
</td>
<td class="{{ talk.accepted|yesno:"success,danger,warning" }}">
{% if talk.accepted == True %}
{% trans "Accepted" %}
{% elif talk.accepted == False %}
{% trans "Declined" %}
{% else %}
{% blocktrans with score=talk.score %}Pending, score: {{ score }}{% endblocktrans %}
{% endif %}
</td>
</tr>
{% if forloop.last%}
</tbody>
{% endif %}
{% endfor %}
<tfoot>
<tr>
<th colspan="5">{% trans "Total:" %} {{ talk_list|length }} {% trans "talk" %}{{ talk_list|length|pluralize }}</th>
</tr>
</tfoot>
</table>
{% endblock %}
{% block js_end %}
<script type="text/javascript">
jQuery(document).ready(function($) {
$(".clickable-row").click(function() {
window.location = $(this).data("href");
});
var anchor = window.location.hash.replace("#", "");
if (anchor == "filter") {
$("#filter").collapse('show');
}
});
</script>
{% endblock %}

View File

@ -1,23 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block talktab %} class="active"{% endblock %}
{% block content %}
<h1>{% trans "Talks" %}</h1>
<a class="btn btn-success" href="{% url 'add-talk' %}">{% trans "Propose a talk" %}</a>
{% if my_talks %}
<h2>{% trans "My participing talks" %}</h2>
{% include "proposals/_talk_list.html" with talk_list=my_talks %}
{% endif %}
{% if other_talks %}
<h2>{% trans "Others talks" %}</h2>
{% include "proposals/_talk_list.html" with talk_list=other_talks %}
{% endif %}
{% endblock %}

View File

@ -12,7 +12,7 @@ urlpatterns = [
url(r'^talk/edit/(?P<talk>[-\w]+)$', views.talk_edit, name='edit-talk'),
url(r'^talk/vote/(?P<talk>[-\w]+)/(?P<score>[-0-2]+)$', views.vote, name='vote'),
url(r'^talk/details/(?P<slug>[-\w]+)$', views.TalkDetail.as_view(), name='show-talk'),
url(r'^talk/by-topic/(?P<topic>[-\w]+)$', views.talk_list_by_topic, name='list-talks-by-topic'),
#url(r'^talk/by-topic/(?P<topic>[-\w]+)$', views.talk_list_by_topic, name='list-talks-by-topic'),
url(r'^talk/accept/(?P<talk>[-\w]+)/$', views.talk_decide, {'accepted': True}, name='accept-talk'),
url(r'^talk/decline/(?P<talk>[-\w]+)/$', views.talk_decide, {'accepted': False}, name='decline-talk'),
url(r'^topic/$', views.TopicList.as_view(), name='list-topics'),

View File

@ -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: