Skip to content

Commit 7be3f75

Browse files
authored
Merge pull request #503 from ChillarAnand/voting
Second Phase Voting
2 parents 9170378 + 08ac3f0 commit 7be3f75

16 files changed

+370
-99
lines changed

junction/base/constants.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,15 @@ class ConferenceSettingConstants:
9898
ALLOW_PLUS_ZERO_REVIEWER_VOTE = {"name": "allow_plus_zero_reviewer_vote",
9999
"value": True,
100100
"description": "Allow +0 vote in reviewer votes"}
101+
102+
103+
@choices
104+
class PSRVotePhase:
105+
_PRIMARY = [0, 'Initial voting']
106+
_SECONDARY = [1, 'Second phase voting']
107+
108+
109+
@choices
110+
class ProposalCommentType:
111+
_GENERAL = [0, 'All general comments']
112+
_SECONDARY_VOTING = [1, 'Second phase voting']

junction/profiles/admin.py

Lines changed: 0 additions & 3 deletions
This file was deleted.

junction/proposals/dashboard.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from junction.base.constants import (
2020
ProposalReviewVote,
2121
ProposalStatus,
22+
ProposalReviewStatus,
2223
)
2324
from junction.conferences.models import Conference, ConferenceProposalReviewer
2425

@@ -233,6 +234,54 @@ def reviewer_votes_dashboard(request, conference_slug):
233234
'form': form})
234235

235236

237+
@require_http_methods(['GET', 'POST'])
238+
def second_phase_voting(request, conference_slug):
239+
conference = get_object_or_404(Conference, slug=conference_slug)
240+
user = request.user
241+
242+
if not is_conference_moderator(user=request.user, conference=conference):
243+
raise PermissionDenied
244+
245+
proposal_sections = conference.proposal_sections.all()
246+
proposals_qs = Proposal.objects.select_related(
247+
'proposal_type', 'proposal_section', 'conference', 'author',
248+
).filter(
249+
conference=conference,
250+
review_status=ProposalReviewStatus.SELECTED
251+
)
252+
253+
proposals = []
254+
s_items = collections.namedtuple('section_items', 'section proposals')
255+
form = ProposalVotesFilterForm(conference=conference)
256+
257+
if request.method == 'GET':
258+
for section in proposal_sections:
259+
section_proposals = [
260+
p for p in proposals_qs if p.proposal_section == section]
261+
proposals.append(s_items(section, section_proposals))
262+
263+
return render(request, 'proposals/second_phase_voting.html',
264+
{'conference': conference,
265+
'proposals': proposals,
266+
'form': form})
267+
268+
form = ProposalVotesFilterForm(conference=conference, data=request.POST)
269+
270+
if not form.is_valid():
271+
return render(request, 'proposals/votes-dashboard.html',
272+
{'form': form,
273+
'conference': conference,
274+
'errors': form.errors})
275+
276+
# Valid form
277+
proposals = _sort_proposals_for_dashboard(conference, proposals_qs, user, form)
278+
279+
return render(request, 'proposals/second_phase_voting.html',
280+
{'conference': conference,
281+
'proposals': proposals,
282+
'form': form})
283+
284+
236285
@require_http_methods(['GET', 'POST'])
237286
def export_reviewer_votes(request, conference_slug):
238287
"""

junction/proposals/forms.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ class ProposalReviewForm(forms.Form):
152152

153153

154154
class ProposalReviewerVoteForm(forms.Form):
155-
156155
"""
157156
Used by ProposalSectionReviewers to vote on proposals.
158157
"""
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import models, migrations
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('proposals', '0016_auto_20160221_0240'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='proposalcomment',
16+
name='type',
17+
field=models.PositiveSmallIntegerField(default=0, choices=[(0, 'Unclassified'), (1, 'Second phase voting')]),
18+
preserve_default=True,
19+
),
20+
]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import models, migrations
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('proposals', '0017_proposalcomment_type'),
11+
]
12+
13+
operations = [
14+
migrations.RemoveField(
15+
model_name='proposalcomment',
16+
name='type',
17+
),
18+
migrations.AddField(
19+
model_name='historicalproposalsectionreviewervote',
20+
name='phase',
21+
field=models.PositiveSmallIntegerField(default=0, choices=[(0, 'Initial voting'), (1, 'Second phase voting')]),
22+
preserve_default=True,
23+
),
24+
migrations.AddField(
25+
model_name='proposalsectionreviewervote',
26+
name='phase',
27+
field=models.PositiveSmallIntegerField(default=0, choices=[(0, 'Initial voting'), (1, 'Second phase voting')]),
28+
preserve_default=True,
29+
),
30+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import models, migrations
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('proposals', '0018_auto_20160806_1727'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='proposalcomment',
16+
name='comment_type',
17+
field=models.PositiveSmallIntegerField(default=0, choices=[(0, 'All general comments'), (1, 'Second phase voting')]),
18+
preserve_default=True,
19+
),
20+
]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import models, migrations
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('proposals', '0019_proposalcomment_comment_type'),
11+
]
12+
13+
operations = [
14+
migrations.AlterUniqueTogether(
15+
name='proposalsectionreviewervote',
16+
unique_together=set([]),
17+
),
18+
]

junction/proposals/models.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import, unicode_literals
33

4-
# Standard Library
54
from datetime import datetime
65

7-
# Third Party Stuff
86
from django.contrib.auth.models import User
97
from django.core.urlresolvers import reverse
108
from django.db import models
@@ -14,9 +12,9 @@
1412
from hashids import Hashids
1513
from simple_history.models import HistoricalRecords
1614

17-
# Junction Stuff
18-
from junction.base.constants import ProposalReviewStatus, ProposalStatus, ProposalTargetAudience, \
19-
ProposalUserVoteRole, ProposalReviewVote
15+
from junction.base.constants import PSRVotePhase, ProposalCommentType, \
16+
ProposalReviewStatus, ProposalReviewVote, ProposalStatus, \
17+
ProposalTargetAudience, ProposalUserVoteRole
2018
from junction.base.models import AuditModel, TimeAuditModel
2119
from junction.conferences.models import Conference, ConferenceProposalReviewer
2220

@@ -122,6 +120,10 @@ def get_vote_url(self):
122120
return reverse('proposal-reviewer-vote',
123121
args=[self.conference.slug, self.slug])
124122

123+
def get_secondary_vote_url(self):
124+
return reverse('proposal-reviewer-secondary-vote',
125+
args=[self.conference.slug, self.slug])
126+
125127
def get_delete_url(self):
126128
return reverse('proposal-delete',
127129
args=[self.conference.slug, self.slug])
@@ -263,16 +265,18 @@ class ProposalSectionReviewerVote(TimeAuditModel):
263265
role = models.PositiveSmallIntegerField(
264266
choices=ProposalUserVoteRole.CHOICES, default=ProposalUserVoteRole.REVIEWER)
265267
vote_value = models.ForeignKey(ProposalSectionReviewerVoteValue)
268+
phase = models.PositiveSmallIntegerField(choices=PSRVotePhase.CHOICES, default=PSRVotePhase.PRIMARY)
269+
266270
history = HistoricalRecords()
267271

268272
def __str__(self):
269273
return "[{}] {}".format(self.vote_value, self.proposal)
270274

271275
class Meta:
272-
unique_together = ("proposal", "voter")
273276
verbose_name = 'ProposalSectionReviewerVote'
274277

275278

279+
# FIXME: Need to move private, reviewer, vote to type
276280
@python_2_unicode_compatible
277281
class ProposalComment(TimeAuditModel):
278282

@@ -284,7 +288,8 @@ class ProposalComment(TimeAuditModel):
284288
vote = models.BooleanField(default=False, verbose_name="What is the reason?")
285289
comment = models.TextField()
286290
deleted = models.BooleanField(default=False, verbose_name="Is Deleted?")
287-
291+
comment_type = models.PositiveSmallIntegerField(
292+
choices=ProposalCommentType.CHOICES, default=ProposalCommentType.GENERAL)
288293
objects = ProposalCommentQuerySet.as_manager()
289294

290295
def __str__(self):

junction/proposals/templatetags/proposal_filters.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import, unicode_literals
33

4-
# Standard Library
54
import collections
65
import re
76

8-
# Third Party Stuff
97
from django import template
8+
from junction.base.constants import PSRVotePhase
9+
from junction.proposals.models import ProposalComment, ProposalSectionReviewer, \
10+
ProposalSectionReviewerVote
1011

11-
# Junction Stuff
12-
from junction.proposals.models import ProposalComment, ProposalSectionReviewer, ProposalSectionReviewerVote
1312

1413
register = template.Library()
1514

@@ -20,14 +19,17 @@ def reviewer_comments(proposal, user):
2019

2120

2221
@register.filter(name='is_reviewer_voted')
23-
def is_reviewer_voted(proposal, user):
22+
def is_reviewer_voted(proposal, user, phase=None):
23+
if not phase:
24+
phase = PSRVotePhase.PRIMARY
2425
try:
2526
vote = ProposalSectionReviewerVote.objects.get(
2627
proposal=proposal,
2728
voter=ProposalSectionReviewer.objects.get(
2829
conference_reviewer__reviewer=user,
2930
conference_reviewer__conference=proposal.conference,
3031
proposal_section=proposal.proposal_section),
32+
phase=phase,
3133
)
3234
except ProposalSectionReviewerVote.DoesNotExist:
3335
vote = None

0 commit comments

Comments
 (0)