vote views, urls, tests, templates, etc.
This commit is contained in:
parent
58256e0d3b
commit
8e936ccf46
|
@ -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()
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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']
|
|
@ -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', {
|
||||
|
|
Loading…
Reference in New Issue