Skip to content

Commit 6eede3a

Browse files
merging upstream
2 parents 5951407 + 9d244ed commit 6eede3a

24 files changed

+499
-152
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ sudo: false
33
python:
44
- '2.7'
55
- '3.4'
6+
- '3.5'
67
addons:
78
postgresql: "9.3"
89

@@ -11,7 +12,8 @@ cache:
1112
- $HOME/.pip-cache/
1213

1314
install:
14-
- pip install -r requirements-dev.txt --allow-all-external --download-cache $HOME/.pip-cache
15+
- pip install pip==8.1.2
16+
- pip install -r requirements-dev.txt --allow-all-external
1517
- pip install coveralls
1618

1719
env:

junction/base/constants.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ class ProposalReviewerComment:
8080
class ProposalVotesFilter:
8181
_NO_VOTES = [0, "No votes"]
8282
_MIN_ONE_VOTE = [1, "Minimum 1 vote"]
83-
_SORT = [2, "Sort by vote value"]
83+
_SORT_BY_SUM = [2, "Sort by total votes"]
84+
_SORT_BY_REVIEWER = [3, "Sort by your votes"]
85+
_SORT_BY_SELECTION = [4, "Sort by selection"]
8486

8587

8688
class ConferenceSettingConstants:
@@ -96,3 +98,15 @@ class ConferenceSettingConstants:
9698
ALLOW_PLUS_ZERO_REVIEWER_VOTE = {"name": "allow_plus_zero_reviewer_vote",
9799
"value": True,
98100
"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/feedback/service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def get_choice_feedback_questions(conference_id):
5656
schedule item type.
5757
"""
5858
qs = ChoiceFeedbackQuestion.objects.filter(
59-
conference_id=conference_id).select_related('allowed_values')
59+
conference_id=conference_id).prefetch_related('allowed_values')
6060
return _get_question_oragnized_by_type(qs)
6161

6262

junction/profiles/admin.py

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

junction/proposals/dashboard.py

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,22 @@
1919
from junction.base.constants import (
2020
ProposalReviewVote,
2121
ProposalStatus,
22-
ProposalVotesFilter
22+
ProposalReviewStatus,
2323
)
2424
from junction.conferences.models import Conference, ConferenceProposalReviewer
2525

2626
from .forms import ProposalVotesFilterForm
2727
from .permissions import is_conference_moderator
28-
28+
from .utils import _sort_proposals_for_dashboard
2929
from .models import (
3030
Proposal,
3131
ProposalComment,
32-
ProposalSection,
3332
ProposalSectionReviewer,
3433
ProposalSectionReviewerVoteValue
3534
)
3635

3736
from . import services
37+
from . import permissions
3838

3939

4040
@login_required
@@ -193,7 +193,7 @@ def reviewer_comments_dashboard(request, conference_slug):
193193
@require_http_methods(['GET', 'POST'])
194194
def reviewer_votes_dashboard(request, conference_slug):
195195
conference = get_object_or_404(Conference, slug=conference_slug)
196-
196+
user = request.user
197197
if not is_conference_moderator(user=request.user, conference=conference):
198198
raise PermissionDenied
199199

@@ -226,43 +226,63 @@ def reviewer_votes_dashboard(request, conference_slug):
226226
'errors': form.errors})
227227

228228
# Valid form
229-
cps = form.cleaned_data['proposal_section']
230-
cpt = form.cleaned_data['proposal_type']
231-
votes = form.cleaned_data['votes']
232-
review_status = form.cleaned_data['review_status']
233-
proposal_sections = conference.proposal_sections.all()
234229

235-
if cps != 'all':
236-
proposal_sections = ProposalSection.objects.filter(pk=cps)
237-
if cpt != 'all':
238-
proposals_qs = proposals_qs.filter(proposal_type__id__in=cpt)
239-
if votes != 'all':
240-
votes = int(votes)
241-
if review_status != 'all':
242-
proposals_qs = proposals_qs.filter(review_status=review_status)
243-
244-
if votes == ProposalVotesFilter.NO_VOTES:
245-
proposals_qs = [
246-
p for p in proposals_qs if p.get_reviewer_votes_count() == votes]
247-
elif votes == ProposalVotesFilter.MIN_ONE_VOTE:
248-
proposals_qs = [
249-
p for p in proposals_qs if p.get_reviewer_votes_count() >= votes]
250-
elif votes == ProposalVotesFilter.SORT:
251-
proposals_qs = sorted(
252-
proposals_qs, key=lambda x: x.get_reviewer_votes_sum(),
253-
reverse=True)
254-
255-
for section in proposal_sections:
256-
section_proposals = [
257-
p for p in proposals_qs if p.proposal_section == section]
258-
proposals.append(s_items(section, section_proposals))
230+
proposals = _sort_proposals_for_dashboard(conference, proposals_qs, user, form)
259231

260232
return render(request, 'proposals/votes-dashboard.html',
261233
{'conference': conference,
262234
'proposals': proposals,
263235
'form': form})
264236

265237

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

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+
]

0 commit comments

Comments
 (0)