vote views, urls, tests, templates, etc.

This commit is contained in:
Guilhem Saurel 2016-07-02 01:03:07 +02:00
parent 58256e0d3b
commit 8e936ccf46
6 changed files with 70 additions and 14 deletions

View File

@ -13,6 +13,8 @@ from sortedm2m.fields import SortedManyToManyField
from accounts.models import Participation
from ponyconf.utils import PonyConfModel, enum_to_choices
from .utils import query_sum
__all__ = ['Topic', 'Talk']
@ -65,6 +67,9 @@ class Talk(PonyConfModel):
def is_editable_by(self, user):
return user == self.proposer or user in self.speakers.all() or self.is_moderable_by(user)
def score(self):
return query_sum(self.vote_set, 'vote')
class Vote(PonyConfModel):
@ -74,3 +79,9 @@ class Vote(PonyConfModel):
class Meta:
unique_together = ('talk', 'user')
def __str__(self):
return "%+i by %s for %s" % (self.vote, self.user, self.talk)
def get_absolute_url(self):
return self.talk.get_absolute_url()

View File

@ -12,11 +12,11 @@
<p>{{ talk.get_event_display }}</p>
<b>Description:</b>
<h3>Description:</h3>
<p>{{ talk.description }}</p>
<b>Speakers:</b>
<h3>Speakers:</h3>
<ul>
{% for speaker in talk.speakers.all %}
@ -26,7 +26,7 @@
{% endfor %}
</ul>
<b>Topics:</b>
<h3>Topics:</h3>
<ul>
{% for topic in talk.topics.all %}
@ -37,7 +37,18 @@
{% if moderate_perm %}
<h2>Moderation</h2>
<b>Messages:</b>
<h3>Vote:</h3>
<div class="btn-group" role="group" aria-label="vote">
<a class="btn {% if vote.vote == -2 %} active {% endif %}btn-danger" href="{% url 'vote' talk=talk.slug score='-2' %}">-2</a>
<a class="btn {% if vote.vote == -1 %} active {% endif %}btn-warning" href="{% url 'vote' talk=talk.slug score='-1' %}">-1</a>
<a class="btn {% if vote.vote == 0 %} active {% endif %}btn-default" href="{% url 'vote' talk=talk.slug score='0' %}"> 0</a>
<a class="btn {% if vote.vote == 1 %} active {% endif %}btn-info" href="{% url 'vote' talk=talk.slug score='1' %}">+1</a>
<a class="btn {% if vote.vote == 2 %} active {% endif %}btn-success" href="{% url 'vote' talk=talk.slug score='2' %}">+2</a>
</div>
Sum: {{ talk.score }}
<h3>Messages:</h3>
{% for message in talk.conversation.messages.all %}
{% include 'conversations/_message_detail.html' %}
{% endfor %}

View File

@ -5,7 +5,7 @@ from django.test import TestCase
from accounts.models import Participation
from .models import Talk, Topic
from .models import Talk, Topic, Vote
class ProposalsTests(TestCase):
@ -43,17 +43,26 @@ class ProposalsTests(TestCase):
{'title': 'mega talk', 'description': 'mega', 'event': 1}).status_code, 403)
self.assertEqual(self.client.get(reverse('list-talks')).status_code, 200)
# Vote
self.assertEqual(talk.score(), 0)
self.assertEqual(self.client.get(reverse('vote', kwargs={'talk': talk.slug, 'score': 2})).status_code, 403)
self.client.login(username='c', password='c')
self.assertEqual(self.client.get(reverse('vote', kwargs={'talk': talk.slug, 'score': 2})).status_code, 302)
self.assertEqual(talk.score(), 2)
# Models str & get_asbolute_url
for model in [Talk, Topic]:
for model in [Talk, Topic, Vote]:
item = model.objects.first()
self.assertEqual(self.client.get(item.get_absolute_url()).status_code, 200)
self.assertTrue(str(item))
# Talk.is_editable_by
# Talk.is_{editable,moderable}_by
a, b, c = User.objects.all()
self.assertTrue(talk.is_editable_by(c))
self.assertTrue(talk.is_moderable_by(c))
self.assertFalse(talk.is_editable_by(b))
self.assertFalse(talk.is_moderable_by(b))
self.client.login(username='a', password='a')
self.client.post(reverse('edit-talk', kwargs={'talk': 'super-talk'}),
{'title': 'mega talk', 'description': 'mega', 'event': 1, 'speakers': "2,1"})
self.assertTrue(talk.is_editable_by(b))
self.assertFalse(talk.is_moderable_by(b))

View File

@ -7,6 +7,7 @@ urlpatterns = [
url(r'^talk/$', views.talk_list, name='list-talks'),
url(r'^talk/add/$', views.talk_edit, name='add-talk'),
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-speaker/(?P<speaker>[\w.@+-]+)$', views.talk_list_by_speaker, name='list-talks-by-speaker'),

6
proposals/utils.py Normal file
View File

@ -0,0 +1,6 @@
from django.db.models import Sum
from django.db.models.functions import Coalesce
def query_sum(queryset, field):
return queryset.aggregate(s=Coalesce(Sum(field), 0))['s']

View File

@ -12,7 +12,7 @@ from accounts.mixins import StaffRequiredMixin
from accounts.models import Participation
from .forms import TalkForm
from .models import Talk, Topic
from .models import Talk, Topic, Vote
from .signals import new_talk
@ -81,11 +81,15 @@ def talk_edit(request, talk=None):
class TalkDetail(LoginRequiredMixin, DetailView):
queryset = Talk.on_site.all()
def get_context_data(self, **kwargs):
kwargs['edit_perm'] = self.object.is_editable_by(self.request.user)
kwargs['moderate_perm'] = self.object.is_moderable_by(self.request.user)
kwargs['form_url'] = reverse('talk-conversation', kwargs={'talk': self.object.slug})
return super().get_context_data(**kwargs)
def get_context_data(self, **ctx):
user = self.request.user
if self.object.is_moderable_by(user):
vote = Vote.objects.filter(talk=self.object, user=Participation.on_site.get(user=user)).first()
ctx.update(edit_perm=True, moderate_perm=True, vote=vote,
form_url=reverse('talk-conversation', kwargs={'talk': self.object.slug}))
else:
ctx['edit_perm'] = self.object.is_editable_by(user)
return super().get_context_data(**ctx)
class TopicList(LoginRequiredMixin, ListView):
@ -102,6 +106,20 @@ class SpeakerList(StaffRequiredMixin, ListView):
template_name = 'proposals/speaker_list.html'
@login_required
def vote(request, talk, score):
site = get_current_site(request)
talk = get_object_or_404(Talk, site=site, slug=talk)
user = Participation.on_site.get(user=request.user)
if not talk.is_moderable_by(request.user):
raise PermissionDenied()
vote, created = Vote.objects.get_or_create(talk=talk, user=user)
vote.vote = int(score)
vote.save()
messages.success(request, "Vote successfully %s" % ('created' if created else 'updated'))
return redirect(talk.get_absolute_url())
@login_required
def user_details(request, username):
return render(request, 'proposals/user_details.html', {