diff --git a/pylab/core/factories.py b/pylab/core/factories.py
index e106ff1..6f2ab7f 100644
--- a/pylab/core/factories.py
+++ b/pylab/core/factories.py
@@ -3,7 +3,7 @@
from django.contrib.auth.models import User
-from pylab.core.models import Event
+from pylab.core.models import Event, Project, VotingPoll
from pylab.core.helpers.factories import fake, future
@@ -41,3 +41,27 @@ class Meta:
description = factory.LazyAttribute(fake.sentence())
starts = factory.LazyAttribute(future(days=1, hour=18, minute=0, second=0))
ends = factory.LazyAttribute(future(days=1, hour=20, minute=0, second=0))
+
+
+class ProjectFactory(factory.django.DjangoModelFactory):
+
+ class Meta:
+ model = Project
+ django_get_or_create = ('slug',)
+
+ author = factory.SubFactory(UserFactory)
+ title = factory.LazyAttribute(fake.company())
+ slug = factory.LazyAttribute(fake.slug())
+ description = factory.LazyAttribute(fake.sentence())
+
+
+class VotingPollFactory(factory.django.DjangoModelFactory):
+
+ class Meta:
+ model = VotingPoll
+ django_get_or_create = ('slug',)
+
+ author = factory.SubFactory(UserFactory)
+ title = factory.LazyAttribute(fake.company())
+ slug = factory.LazyAttribute(fake.slug())
+ description = factory.LazyAttribute(fake.sentence())
diff --git a/pylab/core/migrations/0009_votingpoll_projects.py b/pylab/core/migrations/0009_votingpoll_projects.py
new file mode 100644
index 0000000..b7ab089
--- /dev/null
+++ b/pylab/core/migrations/0009_votingpoll_projects.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0008_auto_20150809_0654'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='votingpoll',
+ name='projects',
+ field=models.ManyToManyField(to='core.Project'),
+ ),
+ ]
diff --git a/pylab/core/models.py b/pylab/core/models.py
index 589a94b..7edda70 100644
--- a/pylab/core/models.py
+++ b/pylab/core/models.py
@@ -65,10 +65,17 @@ class VotingPoll(models.Model):
slug = AutoSlugField(populate_from='title')
title = models.CharField(_("Title"), max_length=255)
description = models.TextField(_("Description"), blank=True)
+ projects = models.ManyToManyField(Project)
def __str__(self):
return self.title
+ def get_absolute_url(self):
+ return reverse('voting-poll-details', args=[self.slug])
+
+ def get_voting_url(self):
+ return reverse('voting-page', args=[self.slug])
+
class Vote(models.Model):
created = CreationDateTimeField()
diff --git a/pylab/website/forms.py b/pylab/website/forms.py
index fb0b7f2..5fb4aa9 100644
--- a/pylab/website/forms.py
+++ b/pylab/website/forms.py
@@ -54,16 +54,34 @@ def clean(self):
self.check_existing_events(title, starts)
-class VotePointsForm(forms.ModelForm):
+class ProjectPointsForm(forms.ModelForm):
+ points = forms.IntegerField(
+ min_value=0,
+ widget=forms.NumberInput(attrs={'max': 99, 'min': 0, 'class': 'vote-points-input'}),
+ )
+
+ def __init__(self, user, voting_poll, *args, **kwargs):
+ self.user = user
+ self.voting_poll = voting_poll
+ super(ProjectPointsForm, self).__init__(*args, **kwargs)
+
+ try:
+ vote = Vote.objects.get(voter=self.user, project__id=self.initial['id'])
+ self.fields['points'].initial = vote.points
+ except Vote.DoesNotExist:
+ pass
+
class Meta:
- model = Vote
- fields = ('points',)
- widgets = {
- 'points': forms.NumberInput(attrs={'max': 99, 'class': 'vote-points-input'}),
- }
+ model = Project
+ fields = tuple()
- def save(self, commit=True, *args, **kwargs):
- vote = super(VotePointsForm, self).save(commit=False, *args, **kwargs)
+ def save(self, commit=True, *args, **kwargs): # pylint: disable=unused-argument
+ vote, created = Vote.objects.get_or_create( # pylint: disable=unused-variable
+ voter=self.user,
+ project=self.instance,
+ voting_poll=self.voting_poll
+ )
+ vote.points = self.cleaned_data['points']
vote.voted = datetime.datetime.now()
vote.save()
@@ -74,7 +92,7 @@ def clean(self, *args, **kwargs):
total_points = 0
for form in self.forms:
- if form.cleaned_data['points']:
+ if form.cleaned_data.get('points'):
total_points += form.cleaned_data['points']
if total_points < 0 or total_points > 15:
diff --git a/pylab/website/static/css/main.scss b/pylab/website/static/css/main.scss
index e920baa..c5d4c40 100644
--- a/pylab/website/static/css/main.scss
+++ b/pylab/website/static/css/main.scss
@@ -52,7 +52,7 @@
}
.vote-points-input {
- width: 38px;
+ width: 42px;
text-align: right;
font-weight: bold;
}
diff --git a/pylab/website/templates/website/voting_page.html b/pylab/website/templates/website/voting_page.html
index 2967c91..22246de 100644
--- a/pylab/website/templates/website/voting_page.html
+++ b/pylab/website/templates/website/voting_page.html
@@ -20,7 +20,6 @@
{{ voting_poll.title }}
{{ formset.management_form }}
{% for form in formset %}
- {{ form.errors }}
{% for hidden in form.hidden_fields %}
{{ hidden }}
@@ -28,7 +27,7 @@
{{ voting_poll.title }}
{% for field in form.visible_fields %}
{% endfor %}
diff --git a/pylab/website/tests/test_voting.py b/pylab/website/tests/test_voting.py
index 052f5f6..c656f14 100644
--- a/pylab/website/tests/test_voting.py
+++ b/pylab/website/tests/test_voting.py
@@ -2,25 +2,24 @@
from django_webtest import WebTest
-from django.contrib.auth.models import User
-
-from pylab.core.models import Project, VotingPoll, Vote
+from pylab.core.factories import UserFactory, VotingPollFactory, ProjectFactory
+from pylab.core.models import Vote
class VotingTests(WebTest):
- def test_voting_page(self):
- u1 = User.objects.create(username='u1')
-
- p1 = Project.objects.create(author=u1, title='Test title 1', description='Test description')
- p2 = Project.objects.create(author=u1, title='Test title 2', description='Test description')
+ def test_voting_and_voting_poll_details_page(self):
+ u1 = UserFactory()
+ u2 = UserFactory()
- vp = VotingPoll.objects.create(author=u1, title='Test voting poll', description='Test description')
+ p1 = ProjectFactory(author=u1)
+ p2 = ProjectFactory(author=u1)
- Vote.objects.create(voter=u1, voting_poll=vp, project=p1)
- Vote.objects.create(voter=u1, voting_poll=vp, project=p2)
+ vp = VotingPollFactory(author=u1)
+ vp.projects.add(p1)
+ vp.projects.add(p2)
- resp = self.app.get('/vote/test-voting-poll/', user='u1')
+ resp = self.app.get(vp.get_voting_url(), user=u1)
self.assertEqual(resp.status_int, 200)
time_before_vote = datetime.datetime.now()
@@ -32,38 +31,32 @@ def test_voting_page(self):
time_after_vote = datetime.datetime.now()
- self.assertEqual(list(Vote.objects.values_list('points', flat=True)), [3, 2])
+ self.assertEqual(list(Vote.objects.filter(voter=u1).values_list('points', flat=True)), [3, 2])
- for v in Vote.objects.all():
+ for v in Vote.objects.filter(voter=u1):
self.assertLess(time_before_vote, v.voted)
self.assertGreater(time_after_vote, v.voted)
- resp = self.app.get('/vote/test-voting-poll/', user='u1')
+ resp = self.app.get(vp.get_voting_url(), user=u2)
self.assertEqual(resp.status_int, 200)
time_before_vote = datetime.datetime.now()
- resp.form['form-0-points'].value = 30 # Vote points sum should be less or equal to 15
- resp.form['form-1-points'].value = 20
+ resp.form['form-0-points'].value = 6 # Vote points sum should be less or equal to 15
+ resp.form['form-1-points'].value = 5
resp = resp.form.submit()
- self.assertEqual(resp.status_int, 200)
-
- def test_voting_poll_details(self):
- u1 = User.objects.create(username='u1')
- u2 = User.objects.create(username='u2')
-
- p1 = Project.objects.create(author=u1, title='Test title 1', description='Test description')
- p2 = Project.objects.create(author=u1, title='Test title 2', description='Test description')
+ self.assertEqual(resp.status_int, 302)
- vp = VotingPoll.objects.create(author=u1, title='Test voting poll', description='Test description')
+ time_after_vote = datetime.datetime.now()
- Vote.objects.create(voter=u1, voting_poll=vp, project=p1, points=1)
- Vote.objects.create(voter=u1, voting_poll=vp, project=p2, points=2)
- Vote.objects.create(voter=u2, voting_poll=vp, project=p1, points=3)
- Vote.objects.create(voter=u2, voting_poll=vp, project=p2, points=4)
+ self.assertEqual(list(Vote.objects.filter(voter=u2).values_list('points', flat=True)), [6, 5])
- resp = self.app.get('/voting-poll/test-voting-poll/', user='u1')
+ for v in Vote.objects.filter(voter=u2):
+ self.assertLess(time_before_vote, v.voted)
+ self.assertGreater(time_after_vote, v.voted)
+ resp = self.app.get(vp.get_absolute_url(), user=u1)
self.assertEqual(resp.status_int, 200)
- self.assertTrue(b'4' in resp.content)
- self.assertTrue(b'6' in resp.content)
+
+ self.assertTrue(b'9' in resp.content)
+ self.assertTrue(b'7' in resp.content)
diff --git a/pylab/website/views.py b/pylab/website/views.py
index 50b1fff..b3718e7 100644
--- a/pylab/website/views.py
+++ b/pylab/website/views.py
@@ -1,3 +1,5 @@
+from django.utils.functional import curry
+
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.forms.models import modelformset_factory
@@ -7,7 +9,7 @@
from django.utils.translation import ugettext
from django.db.models import Sum
-from pylab.core.models import Project, Event, Vote, VotingPoll
+from pylab.core.models import Project, Event, VotingPoll
from pylab.website.helpers import formrenderer
from pylab.website.helpers.decorators import superuser_required
from pylab.website.services import weeklyevents
@@ -103,22 +105,25 @@ def create_weekly_event(request, year, month, day, slug):
def voting_page(request, voting_poll_slug):
voting_poll = get_object_or_404(VotingPoll, slug=voting_poll_slug)
total_points = 15
- VotePointsFormSet = modelformset_factory(
- Vote,
- form=website_forms.VotePointsForm,
+ ProjectPointsFormSet = modelformset_factory(
+ Project,
+ form=website_forms.ProjectPointsForm,
formset=website_forms.BaseTotalPointsFormset,
extra=0,
)
- vote_qs = Vote.objects.filter(voter=request.user, voting_poll__slug=voting_poll_slug)
+ ProjectPointsFormSet.form = staticmethod(curry(
+ website_forms.ProjectPointsForm,
+ user=request.user,
+ voting_poll=voting_poll))
if request.method == 'POST':
- formset = VotePointsFormSet(request.POST, queryset=vote_qs)
+ formset = ProjectPointsFormSet(request.POST, queryset=voting_poll.projects.all())
if formset.is_valid():
formset.save()
messages.success(request, ugettext("Vote for ā%sā voting poll was saved successfully." % voting_poll))
- return redirect('project-list')
+ return redirect(voting_poll)
else:
- formset = VotePointsFormSet(queryset=vote_qs)
+ formset = ProjectPointsFormSet(queryset=voting_poll.projects.all())
return render(request, 'website/voting_page.html', {
'voting_poll': voting_poll,