fedora_elections/__init__.py | 8 + fedora_elections/default_config.py | 11 ++ fedora_elections/elections.py | 45 ++++++++++ fedora_elections/forms.py | 15 +++ fedora_elections/models.py | 2 tests/test_candidate.py | 22 +++++ tests/test_election.py | 32 ++++++- tests/test_flask.py | 10 +- tests/test_flask_irc.py | 157 +++++++++++++++++++++++++++++++++++++ tests/test_vote.py | 12 ++ 10 files changed, 303 insertions(+), 11 deletions(-)
New commits: commit 6ff26d188985174fedadcf76538c9d2e7a386cf1 Merge: b1396a3 398d7d3 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 17:10:55 2014 +0200
Merge pull request #35 from fedora-infra/permanent_session
Permanent session
commit 398d7d3f4f1449f84189472e3718e75b92c3155d Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 16:46:57 2014 +0200
Add header and a default time-out period for the session in the default configuration file
diff --git a/fedora_elections/default_config.py b/fedora_elections/default_config.py index 9a37e23..979dd9d 100644 --- a/fedora_elections/default_config.py +++ b/fedora_elections/default_config.py @@ -1,3 +1,14 @@ +# -*- coding: utf-8 -*- + +''' +Fedora elections default configuration. +''' + +from datetime import timedelta + +# Set the time after which the session expires +PERMANENT_SESSION_LIFETIME = timedelta(hours=1) + FEDORA_ELECTIONS_ADMIN_GROUP = 'elections'
# url to the database server:
commit 32788ff1f7219ec341ea0421e3672debe51d094e Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 16:46:35 2014 +0200
Activate the permanent session so that session time-out as specified in the configuration file
diff --git a/fedora_elections/__init__.py b/fedora_elections/__init__.py index 2fd1222..131f320 100644 --- a/fedora_elections/__init__.py +++ b/fedora_elections/__init__.py @@ -152,6 +152,7 @@ def inject_variables(): return dict(is_admin=is_admin(user), version=__version__)
+ @APP.template_filter('rjust') def rjust_filter(text, length): """ Run a rjust command on the text for the given length @@ -159,6 +160,13 @@ def rjust_filter(text, length): return str(text).rjust(length)
+# pylint: disable=W0613 +@APP.before_request +def set_session(): + """ Set the flask session as permanent. """ + flask.session.permanent = True + + # LIST VIEWS #############################################
@APP.route('/')
commit b1396a3567540aa03aaccabe8903fa97c805fa83 Merge: 1f21208 8a42ce6 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 16:34:51 2014 +0200
Merge pull request #34 from fedora-infra/for_abstain_against_vote
For abstain against vote
commit 8a42ce62abbefb172d0cf8c575b5f843d987b0e6 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 16:32:42 2014 +0200
One more forAbstainAgainst to change
diff --git a/tests/test_election.py b/tests/test_election.py index 583ce13..b33bf86 100644 --- a/tests/test_election.py +++ b/tests/test_election.py @@ -172,7 +172,7 @@ class Electiontests(Modeltests): self.session.add(obj) self.session.commit() self.assertNotEqual(obj, None) - # Election - forAbstainAgainst voting - Open + # Election - IRC voting - Open obj = models.Election( # id:7 shortdesc='test election 7 shortdesc', alias='test_election7',
commit 8ffd821696d0409ebd03413b380434e1e091babb Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 16:30:17 2014 +0200
Adjust test function names and docstrings for the change in the type
diff --git a/tests/test_flask_irc.py b/tests/test_flask_irc.py index 44d467d..9c45fa4 100644 --- a/tests/test_flask_irc.py +++ b/tests/test_flask_irc.py @@ -44,8 +44,8 @@ from tests import ModelFlasktests, Modeltests, TODAY, FakeUser, user_set class FlaskIrcElectionstests(ModelFlasktests): """ Flask application tests irc voting. """
- def test_vote_for_abstain_against(self): - """ Test the vote_for_abstain_against function - the preview part. """ + def test_vote_irc(self): + """ Test the vote_irc function - the preview part. """ output = self.app.get( '/vote/test_election', follow_redirects=True) self.assertEqual(output.status_code, 200) @@ -105,8 +105,8 @@ class FlaskIrcElectionstests(ModelFlasktests): '<li class="message">Please confirm your vote!</li>' in output.data)
- def test_vote_for_abstain_against_process(self): - """ Test the vote_for_abstain_against function - the voting part. """ + def test_vote_irc_process(self): + """ Test the vote_irc function - the voting part. """ output = self.app.get( '/vote/test_election', follow_redirects=True) self.assertEqual(output.status_code, 200)
commit 64c3628ffa812ad5e642e3fd28932d63a1e1bacc Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 16:27:59 2014 +0200
Change ``for_abstain_against`` voting to ``irc`` voting
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py index bfff1cd..2ad0e1e 100644 --- a/fedora_elections/elections.py +++ b/fedora_elections/elections.py @@ -117,8 +117,8 @@ def vote(election_alias): return vote_simple(election) elif election.voting_type == 'select': return vote_select(election) - elif election.voting_type == 'for_abstain_against': - return vote_for_abstain_against(election) + elif election.voting_type == 'irc': + return vote_irc(election) else: # pragma: no cover flask.flash( 'Unknown election voting type: %s' % election.voting_type) @@ -303,7 +303,7 @@ def vote_simple(election): nextaction=next_action)
-def vote_for_abstain_against(election): +def vote_irc(election): votes = models.Vote.of_user_on_election( SESSION, flask.g.fas_user.username, election.id, count=True)
@@ -314,7 +314,7 @@ def vote_for_abstain_against(election): num_candidates = election.candidates.count()
next_action = 'confirm' - form=forms.get_for_abstain_against_voting_form( + form=forms.get_irc_voting_form( candidates=election.candidates, fasusers=election.candidates_are_fasusers) if form.validate_on_submit(): diff --git a/fedora_elections/forms.py b/fedora_elections/forms.py index 50f676b..7150564 100644 --- a/fedora_elections/forms.py +++ b/fedora_elections/forms.py @@ -37,7 +37,7 @@ class ElectionForm(wtf.Form): ('range_3', 'Simplified Range Voting (max is set below)'), ('select', 'Select Voting (checkboxes for each candidate, ' 'maximum number of votes set below)'), - ('for_abstain_against', '+1/0/-1 voting'), + ('irc', '+1/0/-1 voting'), ], default='range')
@@ -160,8 +160,8 @@ def get_simple_voting_form(candidates, fasusers): return SimpleVoting()
-def get_for_abstain_against_voting_form(candidates, fasusers): - class ForAbstainAgainstVoting(wtf.Form): +def get_irc_voting_form(candidates, fasusers): + class IrcVoting(wtf.Form): action = wtforms.HiddenField()
for candidate in candidates: @@ -169,9 +169,9 @@ def get_for_abstain_against_voting_form(candidates, fasusers): candidate.name, choices=[('0',0),('1',1),('-1',-1)] ) - setattr(ForAbstainAgainstVoting, candidate.name, field) + setattr(IrcVoting, candidate.name, field)
- return ForAbstainAgainstVoting() + return IrcVoting()
def get_select_voting_form(candidates, max_selection): diff --git a/fedora_elections/models.py b/fedora_elections/models.py index 1ff263f..74af82d 100644 --- a/fedora_elections/models.py +++ b/fedora_elections/models.py @@ -420,7 +420,7 @@ class Vote(BASE): stats['max_vote'] = election.max_votes elif election.voting_type == 'simple': stats['max_vote'] = 1 - elif election.voting_type == 'for_abstain_against': + elif election.voting_type == 'irc': stats['max_vote'] = 1
return stats diff --git a/tests/test_election.py b/tests/test_election.py index fe1e17e..583ce13 100644 --- a/tests/test_election.py +++ b/tests/test_election.py @@ -182,7 +182,7 @@ class Electiontests(Modeltests): end_date=TODAY + timedelta(days=3), seats_elected=1, embargoed=1, - voting_type='for_abstain_against', + voting_type='irc', candidates_are_fasusers=0, max_votes=1, fas_user='nerdsville', diff --git a/tests/test_flask_for_abstain_against_voting.py b/tests/test_flask_for_abstain_against_voting.py deleted file mode 100644 index 243159d..0000000 --- a/tests/test_flask_for_abstain_against_voting.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" - (c) 2014 - Copyright Joshua Santos - Author: Joshua Santos nerdsville@nerdsville.net - -# This copyrighted material is made available to anyone wishing to use, modify, -# copy, or redistribute it subject to the terms and conditions of the GNU -# General Public License v.2, or (at your option) any later version. This -# program is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY expressed or implied, including the implied warranties of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. You should have received a copy of the GNU -# General Public License along with this program; if not, write to the Free -# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the source -# code or documentation are not subject to the GNU General Public License and -# may only be used or replicated with the express permission of Red Hat, Inc. - - fedora_elections.elections test script -""" -__requires__ = ['SQLAlchemy >= 0.7', 'jinja2 >= 2.4'] -import pkg_resources - -import logging -import unittest -import sys -import os - -from datetime import time -from datetime import timedelta - -import flask - -sys.path.insert(0, os.path.join(os.path.dirname( - os.path.abspath(__file__)), '..')) - -import fedora_elections -from tests import ModelFlasktests, Modeltests, TODAY, FakeUser, user_set - - -# pylint: disable=R0904 -class FlaskSimpleElectionstests(ModelFlasktests): - """ Flask application tests range voting. """ - - def test_vote_for_abstain_against(self): - """ Test the vote_for_abstain_against function - the preview part. """ - output = self.app.get( - '/vote/test_election', follow_redirects=True) - self.assertEqual(output.status_code, 200) - self.assertTrue( - '<title>OpenID transaction in progress</title>' in output.data - or 'discoveryfailure' in output.data) - - self.setup_db() - - user = FakeUser(['packager'], username='toshio') - with user_set(fedora_elections.APP, user): - output = self.app.get( - '/vote/test_election7', follow_redirects=True) - self.assertTrue( - 'class="message">You have already voted in the election!</' - in output.data) - - user = FakeUser(['packager'], username='nerdsville') - with user_set(fedora_elections.APP, user): - output = self.app.get( - '/vote/test_election7') - self.assertTrue( - '<h2>test election 7 shortdesc</h2>' in output.data) - self.assertTrue( - '<input type="hidden" name="action" value="preview" />' - in output.data) - - csrf_token = output.data.split( - 'name="csrf_token" type="hidden" value="')[1].split('">')[0] - - # Invalid vote: No candidate - data = { - 'action': 'preview', - } - - output = self.app.post('/vote/test_election7', data=data) - self.assertEqual(output.status_code, 200) - self.assertTrue( - '<h2>test election 7 shortdesc</h2>' in output.data) - - # Valid input - data = { - 'Kevin': -1, - 'Toshio': '0', - 'action': 'preview', - 'csrf_token': csrf_token, - } - - output = self.app.post('/vote/test_election7', data=data) - self.assertEqual(output.status_code, 200) - self.assertTrue( - '<h2>test election 7 shortdesc</h2>' in output.data) - self.assertTrue( - '<input type="hidden" name="action" value="submit" />' - in output.data) - self.assertTrue( - '<li class="message">Please confirm your vote!</li>' - in output.data) - - def test_vote_for_abstain_against_process(self): - """ Test the vote_for_abstain_against function - the voting part. """ - output = self.app.get( - '/vote/test_election', follow_redirects=True) - self.assertEqual(output.status_code, 200) - self.assertTrue( - '<title>OpenID transaction in progress</title>' in output.data - or 'discoveryfailure' in output.data) - - self.setup_db() - - user = FakeUser(['packager'], username='pingou') - with user_set(fedora_elections.APP, user): - # Invalid candidate id - no csrf - data = { - 'candidate': 1, - 'action': 'submit', - } - - output = self.app.post( - '/vote/test_election7', data=data, - follow_redirects=True) - self.assertEqual(output.status_code, 200) - - csrf_token = output.data.split( - 'name="csrf_token" type="hidden" value="')[1].split('">')[0] - - # Valid input - data = { - 'Toshio': '0', - 'Kevin': '1', - 'action': 'submit', - 'csrf_token': csrf_token, - } - - output = self.app.post( - '/vote/test_election7', data=data, - follow_redirects=True) - self.assertEqual(output.status_code, 200) - self.assertTrue( - 'class="message">Your vote has been recorded. Thank you!</' - in output.data) - self.assertTrue('<h3>Current elections</h3>' in output.data) - self.assertTrue('<h3>Next 1 elections</h3>' in output.data) - self.assertTrue('<h3>Last 2 elections</h3>' in output.data) - - -if __name__ == '__main__': - SUITE = unittest.TestLoader().loadTestsFromTestCase(FlaskSimpleElectionstests) - unittest.TextTestRunner(verbosity=2).run(SUITE) diff --git a/tests/test_flask_irc.py b/tests/test_flask_irc.py new file mode 100644 index 0000000..44d467d --- /dev/null +++ b/tests/test_flask_irc.py @@ -0,0 +1,157 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" + (c) 2014 - Copyright Joshua Santos + Author: Joshua Santos nerdsville@nerdsville.net + +# This copyrighted material is made available to anyone wishing to use, modify, +# copy, or redistribute it subject to the terms and conditions of the GNU +# General Public License v.2, or (at your option) any later version. This +# program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY expressed or implied, including the implied warranties of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the GNU +# General Public License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the source +# code or documentation are not subject to the GNU General Public License and +# may only be used or replicated with the express permission of Red Hat, Inc. + + fedora_elections.elections test script +""" +__requires__ = ['SQLAlchemy >= 0.7', 'jinja2 >= 2.4'] +import pkg_resources + +import logging +import unittest +import sys +import os + +from datetime import time +from datetime import timedelta + +import flask + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import fedora_elections +from tests import ModelFlasktests, Modeltests, TODAY, FakeUser, user_set + + +# pylint: disable=R0904 +class FlaskIrcElectionstests(ModelFlasktests): + """ Flask application tests irc voting. """ + + def test_vote_for_abstain_against(self): + """ Test the vote_for_abstain_against function - the preview part. """ + output = self.app.get( + '/vote/test_election', follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<title>OpenID transaction in progress</title>' in output.data + or 'discoveryfailure' in output.data) + + self.setup_db() + + user = FakeUser(['packager'], username='toshio') + with user_set(fedora_elections.APP, user): + output = self.app.get( + '/vote/test_election7', follow_redirects=True) + self.assertTrue( + 'class="message">You have already voted in the election!</' + in output.data) + + user = FakeUser(['packager'], username='nerdsville') + with user_set(fedora_elections.APP, user): + output = self.app.get( + '/vote/test_election7') + self.assertTrue( + '<h2>test election 7 shortdesc</h2>' in output.data) + self.assertTrue( + '<input type="hidden" name="action" value="preview" />' + in output.data) + + csrf_token = output.data.split( + 'name="csrf_token" type="hidden" value="')[1].split('">')[0] + + # Invalid vote: No candidate + data = { + 'action': 'preview', + } + + output = self.app.post('/vote/test_election7', data=data) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<h2>test election 7 shortdesc</h2>' in output.data) + + # Valid input + data = { + 'Kevin': -1, + 'Toshio': '0', + 'action': 'preview', + 'csrf_token': csrf_token, + } + + output = self.app.post('/vote/test_election7', data=data) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<h2>test election 7 shortdesc</h2>' in output.data) + self.assertTrue( + '<input type="hidden" name="action" value="submit" />' + in output.data) + self.assertTrue( + '<li class="message">Please confirm your vote!</li>' + in output.data) + + def test_vote_for_abstain_against_process(self): + """ Test the vote_for_abstain_against function - the voting part. """ + output = self.app.get( + '/vote/test_election', follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<title>OpenID transaction in progress</title>' in output.data + or 'discoveryfailure' in output.data) + + self.setup_db() + + user = FakeUser(['packager'], username='pingou') + with user_set(fedora_elections.APP, user): + # Invalid candidate id - no csrf + data = { + 'candidate': 1, + 'action': 'submit', + } + + output = self.app.post( + '/vote/test_election7', data=data, + follow_redirects=True) + self.assertEqual(output.status_code, 200) + + csrf_token = output.data.split( + 'name="csrf_token" type="hidden" value="')[1].split('">')[0] + + # Valid input + data = { + 'Toshio': '0', + 'Kevin': '1', + 'action': 'submit', + 'csrf_token': csrf_token, + } + + output = self.app.post( + '/vote/test_election7', data=data, + follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertTrue( + 'class="message">Your vote has been recorded. Thank you!</' + in output.data) + self.assertTrue('<h3>Current elections</h3>' in output.data) + self.assertTrue('<h3>Next 1 elections</h3>' in output.data) + self.assertTrue('<h3>Last 2 elections</h3>' in output.data) + + +if __name__ == '__main__': + SUITE = unittest.TestLoader().loadTestsFromTestCase(FlaskIrcElectionstests) + unittest.TextTestRunner(verbosity=2).run(SUITE)
commit 22e5cffc30c89dea14819fb4ac2201c3914f72b2 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 16:18:40 2014 +0200
Name the `for_abstain_against` election type `+1/0/-1 voting` in the UI
diff --git a/fedora_elections/forms.py b/fedora_elections/forms.py index dda16b3..50f676b 100644 --- a/fedora_elections/forms.py +++ b/fedora_elections/forms.py @@ -37,7 +37,7 @@ class ElectionForm(wtf.Form): ('range_3', 'Simplified Range Voting (max is set below)'), ('select', 'Select Voting (checkboxes for each candidate, ' 'maximum number of votes set below)'), - ('for_abstain_against', 'For - Abstain - Against (+1, neutral, -1)'), + ('for_abstain_against', '+1/0/-1 voting'), ], default='range')
commit d6ddf33bf2e83ca91386197ebf2adae9ed92f19c Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 15:00:57 2014 +0200
Adjust the unit-tests to handle the pro_abstain_against vote
diff --git a/tests/test_flask_for_abstain_against_voting.py b/tests/test_flask_for_abstain_against_voting.py index 2c5e99c..243159d 100644 --- a/tests/test_flask_for_abstain_against_voting.py +++ b/tests/test_flask_for_abstain_against_voting.py @@ -85,9 +85,11 @@ class FlaskSimpleElectionstests(ModelFlasktests): self.assertEqual(output.status_code, 200) self.assertTrue( '<h2>test election 7 shortdesc</h2>' in output.data) + # Valid input data = { 'Kevin': -1, + 'Toshio': '0', 'action': 'preview', 'csrf_token': csrf_token, } @@ -132,7 +134,8 @@ class FlaskSimpleElectionstests(ModelFlasktests):
# Valid input data = { - 'Toshio': True, + 'Toshio': '0', + 'Kevin': '1', 'action': 'submit', 'csrf_token': csrf_token, }
commit a58e7ea1c654edd9f74b04eb2532dc32f69e94c9 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 14:58:52 2014 +0200
Adjust again the form logic for vote_for_abstain_against
The name of the field will be the name of the candidate and adjust the logic to handle it as such
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py index 7ba405d..bfff1cd 100644 --- a/fedora_elections/elections.py +++ b/fedora_elections/elections.py @@ -307,6 +307,10 @@ def vote_for_abstain_against(election): votes = models.Vote.of_user_on_election( SESSION, flask.g.fas_user.username, election.id, count=True)
+ cand_name = {} + for candidate in election.candidates: + cand_name[candidate.name] = candidate.id + num_candidates = election.candidates.count()
next_action = 'confirm' @@ -318,12 +322,11 @@ def vote_for_abstain_against(election): for candidate in form: if candidate.short_name in ['csrf_token', 'action']: continue - cand_id = candidate.short_name.replace('candidate_', '') new_vote = models.Vote( election_id=election.id, voter=flask.g.fas_user.username, timestamp=datetime.now(), - candidate_id=cand_id, + candidate_id=cand_name[candidate.short_name], value=candidate.data, ) SESSION.add(new_vote) diff --git a/fedora_elections/forms.py b/fedora_elections/forms.py index fc82721..dda16b3 100644 --- a/fedora_elections/forms.py +++ b/fedora_elections/forms.py @@ -164,15 +164,12 @@ def get_for_abstain_against_voting_form(candidates, fasusers): class ForAbstainAgainstVoting(wtf.Form): action = wtforms.HiddenField()
- fields = [] for candidate in candidates: - fields.append(wtforms.SelectField( + field = wtforms.SelectField( candidate.name, choices=[('0',0),('1',1),('-1',-1)] - )) - - for i,field in enumerate(fields): - setattr(ForAbstainAgainstVoting,'candidate_'+str(i),field) + ) + setattr(ForAbstainAgainstVoting, candidate.name, field)
return ForAbstainAgainstVoting()
commit bfa0f558f1f30fdb4daf43bc20ea346109ffc1d9 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 14:46:38 2014 +0200
Add some candidates to the election #7
diff --git a/tests/test_candidate.py b/tests/test_candidate.py index aa87e95..90bdc08 100644 --- a/tests/test_candidate.py +++ b/tests/test_candidate.py @@ -187,6 +187,28 @@ class Candidatetests(Modeltests): self.session.commit() self.assertNotEqual(obj, None)
+ # + # Election #7 + # + + obj = models.Candidate( # id:14 + election_id=7, + name='Toshio', + url='https://fedoraproject.org/wiki/User:Toshio', + ) + self.session.add(obj) + self.session.commit() + self.assertNotEqual(obj, None) + + obj = models.Candidate( # id:15 + election_id=7, + name='Kevin', + url='https://fedoraproject.org/wiki/User:Kevin', + ) + self.session.add(obj) + self.session.commit() + self.assertNotEqual(obj, None) + def test_to_json(self): """ Test the Candidate.to_json function. """ self.test_init_candidate()
commit 7c282c7622c248b1e2df0ed63c7e1b20a44a2a45 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 14:38:46 2014 +0200
Fix get_election_stats for the `for_abstain_against` elections
diff --git a/fedora_elections/models.py b/fedora_elections/models.py index 1cc51f4..1ff263f 100644 --- a/fedora_elections/models.py +++ b/fedora_elections/models.py @@ -420,6 +420,8 @@ class Vote(BASE): stats['max_vote'] = election.max_votes elif election.voting_type == 'simple': stats['max_vote'] = 1 + elif election.voting_type == 'for_abstain_against': + stats['max_vote'] = 1
return stats
commit df53ac4639dddfb6d149de0664c1fb70e3827536 Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 14:38:20 2014 +0200
Simplify retrieving the candidate id submitted via the form
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py index b50951a..7ba405d 100644 --- a/fedora_elections/elections.py +++ b/fedora_elections/elections.py @@ -315,18 +315,17 @@ def vote_for_abstain_against(election): fasusers=election.candidates_are_fasusers) if form.validate_on_submit(): if form.action.data == 'submit': - i=0 for candidate in form: if candidate.short_name in ['csrf_token', 'action']: continue + cand_id = candidate.short_name.replace('candidate_', '') new_vote = models.Vote( election_id=election.id, voter=flask.g.fas_user.username, timestamp=datetime.now(), - candidate_id=form.candidate_ids[i-1], + candidate_id=cand_id, value=candidate.data, ) - i += 1 SESSION.add(new_vote) SESSION.commit() flask.flash("Your vote has been recorded. Thank you!")
commit 27037ebd30c58d5e8d380b840f569bbb68ace74d Author: Pierre-Yves Chibon pingou@pingoured.fr Date: Tue Aug 26 14:38:01 2014 +0200
Simplify the form for get_for_abstain_against_voting_form
diff --git a/fedora_elections/forms.py b/fedora_elections/forms.py index 68cbed3..fc82721 100644 --- a/fedora_elections/forms.py +++ b/fedora_elections/forms.py @@ -163,32 +163,17 @@ def get_simple_voting_form(candidates, fasusers): def get_for_abstain_against_voting_form(candidates, fasusers): class ForAbstainAgainstVoting(wtf.Form): action = wtforms.HiddenField() - titles = [] - candidate_ids = [] + fields = [] for candidate in candidates: - title = candidate.name - if fasusers: # pragma: no cover - # We can't cover FAS integration - try: - title = \ - FAS2.person_by_username(candidate.name)['human_name'] - except (KeyError, AuthError), err: - APP.logger.debug(err) - if candidate.url: - title = '%s <a href="%s">[Info]</a>' % (title, candidate.url) - ForAbstainAgainstVoting.titles.append((str(candidate.id), title)) - ForAbstainAgainstVoting.candidate_ids.append(str(candidate.id)) fields.append(wtforms.SelectField( candidate.name, choices=[('0',0),('1',1),('-1',-1)] )) - def validate_field(form, field): - if field.data != '1' and field.data != '-1' and field.data != '0': - raise wtforms.ValidationError( - 'Not a valid integer value for vote.') + for i,field in enumerate(fields): - setattr(ForAbstainAgainstVoting,'candidate'+str(i),field) + setattr(ForAbstainAgainstVoting,'candidate_'+str(i),field) + return ForAbstainAgainstVoting()
commit 59097d23b275b43240419ba927d96a2effd89257 Author: Joshua Santos nerdsville@nerdsville.net Date: Mon Aug 25 07:54:08 2014 -0700
Adding unit tests
diff --git a/tests/test_election.py b/tests/test_election.py index 2370716..fe1e17e 100644 --- a/tests/test_election.py +++ b/tests/test_election.py @@ -172,6 +172,24 @@ class Electiontests(Modeltests): self.session.add(obj) self.session.commit() self.assertNotEqual(obj, None) + # Election - forAbstainAgainst voting - Open + obj = models.Election( # id:7 + shortdesc='test election 7 shortdesc', + alias='test_election7', + description='test election 7 description', + url='https://fedoraproject.org', + start_date=TODAY - timedelta(days=1), + end_date=TODAY + timedelta(days=3), + seats_elected=1, + embargoed=1, + voting_type='for_abstain_against', + candidates_are_fasusers=0, + max_votes=1, + fas_user='nerdsville', + ) + self.session.add(obj) + self.session.commit() + self.assertNotEqual(obj, None)
def test_get_election(self): """ Test the Election.get function. """ @@ -246,13 +264,14 @@ class Electiontests(Modeltests): obj = models.Election.search(self.session) self.assertNotEqual(obj, None) self.assertNotEqual(obj, []) - self.assertEqual(len(obj), 6) + self.assertEqual(len(obj), 7) self.assertEqual(obj[0].description, 'test election 4 description') self.assertEqual(obj[1].description, 'test election 5 description') self.assertEqual(obj[2].description, 'test election 6 description') - self.assertEqual(obj[3].description, 'test election 3 description') - self.assertEqual(obj[4].description, 'test election 2 description') - self.assertEqual(obj[5].description, 'test election description') + self.assertEqual(obj[3].description, 'test election 7 description') + self.assertEqual(obj[4].description, 'test election 3 description') + self.assertEqual(obj[5].description, 'test election 2 description') + self.assertEqual(obj[6].description, 'test election description')
def test_get_older_election(self): """ Test the Election.get_older_election function. """ @@ -270,10 +289,11 @@ class Electiontests(Modeltests): obj = models.Election.get_open_election(self.session, limit=TODAY) self.assertNotEqual(obj, None) self.assertNotEqual(obj, []) - self.assertEqual(len(obj), 3) + self.assertEqual(len(obj), 4) self.assertEqual(obj[0].shortdesc, 'test election 5 shortdesc') self.assertEqual(obj[1].shortdesc, 'test election 6 shortdesc') - self.assertEqual(obj[2].shortdesc, 'test election 3 shortdesc') + self.assertEqual(obj[2].shortdesc, 'test election 7 shortdesc') + self.assertEqual(obj[3].shortdesc, 'test election 3 shortdesc')
def test_get_next_election(self): """ Test the Election.get_next_election function. """ diff --git a/tests/test_flask.py b/tests/test_flask.py index b9da2cd..9e7efbe 100644 --- a/tests/test_flask.py +++ b/tests/test_flask.py @@ -99,7 +99,7 @@ class Flasktests(ModelFlasktests): self.assertTrue('<a href="/vote/' in output.data) self.assertTrue( '<span class="text">logged in as </span>' in output.data) - self.assertEqual(output.data.count('Vote now!'), 3) + self.assertEqual(output.data.count('Vote now!'), 4)
user = FakeUser([], username='toshio') with user_set(fedora_elections.APP, user): @@ -296,7 +296,7 @@ class Flasktests(ModelFlasktests): output = self.app.get('/open') self.assertEqual(output.status_code, 200) self.assertTrue('<title>Fedora elections</title>' in output.data) - self.assertTrue('<h3>Next 3 elections</h3>' in output.data) + self.assertTrue('<h3>Next 4 elections</h3>' in output.data) self.assertTrue('<td>test election 3 shortdesc</td>' in output.data) self.assertTrue('<a href="/vote/' in output.data) self.assertTrue('<a href="/login">login</a>' in output.data) @@ -306,18 +306,18 @@ class Flasktests(ModelFlasktests): output = self.app.get('/open') self.assertEqual(output.status_code, 200) self.assertTrue('<title>Fedora elections</title>' in output.data) - self.assertTrue('<h3>Next 3 elections</h3>' in output.data) + self.assertTrue('<h3>Next 4 elections</h3>' in output.data) self.assertTrue('<a href="/vote/' in output.data) self.assertTrue( '<span class="text">logged in as </span>' in output.data) - self.assertEqual(output.data.count('Vote now!'), 3) + self.assertEqual(output.data.count('Vote now!'), 4)
user = FakeUser([], username='toshio') with user_set(fedora_elections.APP, user): output = self.app.get('/open') self.assertEqual(output.status_code, 200) self.assertTrue('<title>Fedora elections</title>' in output.data) - self.assertTrue('<h3>Next 3 elections</h3>' in output.data) + self.assertTrue('<h3>Next 4 elections</h3>' in output.data) self.assertTrue( '<span class="text">logged in as </span>' in output.data) self.assertEqual(output.data.count('Vote now!'), 0) diff --git a/tests/test_flask_for_abstain_against_voting.py b/tests/test_flask_for_abstain_against_voting.py new file mode 100644 index 0000000..2c5e99c --- /dev/null +++ b/tests/test_flask_for_abstain_against_voting.py @@ -0,0 +1,154 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" + (c) 2014 - Copyright Joshua Santos + Author: Joshua Santos nerdsville@nerdsville.net + +# This copyrighted material is made available to anyone wishing to use, modify, +# copy, or redistribute it subject to the terms and conditions of the GNU +# General Public License v.2, or (at your option) any later version. This +# program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY expressed or implied, including the implied warranties of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the GNU +# General Public License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the source +# code or documentation are not subject to the GNU General Public License and +# may only be used or replicated with the express permission of Red Hat, Inc. + + fedora_elections.elections test script +""" +__requires__ = ['SQLAlchemy >= 0.7', 'jinja2 >= 2.4'] +import pkg_resources + +import logging +import unittest +import sys +import os + +from datetime import time +from datetime import timedelta + +import flask + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import fedora_elections +from tests import ModelFlasktests, Modeltests, TODAY, FakeUser, user_set + + +# pylint: disable=R0904 +class FlaskSimpleElectionstests(ModelFlasktests): + """ Flask application tests range voting. """ + + def test_vote_for_abstain_against(self): + """ Test the vote_for_abstain_against function - the preview part. """ + output = self.app.get( + '/vote/test_election', follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<title>OpenID transaction in progress</title>' in output.data + or 'discoveryfailure' in output.data) + + self.setup_db() + + user = FakeUser(['packager'], username='toshio') + with user_set(fedora_elections.APP, user): + output = self.app.get( + '/vote/test_election7', follow_redirects=True) + self.assertTrue( + 'class="message">You have already voted in the election!</' + in output.data) + + user = FakeUser(['packager'], username='nerdsville') + with user_set(fedora_elections.APP, user): + output = self.app.get( + '/vote/test_election7') + self.assertTrue( + '<h2>test election 7 shortdesc</h2>' in output.data) + self.assertTrue( + '<input type="hidden" name="action" value="preview" />' + in output.data) + + csrf_token = output.data.split( + 'name="csrf_token" type="hidden" value="')[1].split('">')[0] + + # Invalid vote: No candidate + data = { + 'action': 'preview', + } + + output = self.app.post('/vote/test_election7', data=data) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<h2>test election 7 shortdesc</h2>' in output.data) + # Valid input + data = { + 'Kevin': -1, + 'action': 'preview', + 'csrf_token': csrf_token, + } + + output = self.app.post('/vote/test_election7', data=data) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<h2>test election 7 shortdesc</h2>' in output.data) + self.assertTrue( + '<input type="hidden" name="action" value="submit" />' + in output.data) + self.assertTrue( + '<li class="message">Please confirm your vote!</li>' + in output.data) + + def test_vote_for_abstain_against_process(self): + """ Test the vote_for_abstain_against function - the voting part. """ + output = self.app.get( + '/vote/test_election', follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertTrue( + '<title>OpenID transaction in progress</title>' in output.data + or 'discoveryfailure' in output.data) + + self.setup_db() + + user = FakeUser(['packager'], username='pingou') + with user_set(fedora_elections.APP, user): + # Invalid candidate id - no csrf + data = { + 'candidate': 1, + 'action': 'submit', + } + + output = self.app.post( + '/vote/test_election7', data=data, + follow_redirects=True) + self.assertEqual(output.status_code, 200) + + csrf_token = output.data.split( + 'name="csrf_token" type="hidden" value="')[1].split('">')[0] + + # Valid input + data = { + 'Toshio': True, + 'action': 'submit', + 'csrf_token': csrf_token, + } + + output = self.app.post( + '/vote/test_election7', data=data, + follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertTrue( + 'class="message">Your vote has been recorded. Thank you!</' + in output.data) + self.assertTrue('<h3>Current elections</h3>' in output.data) + self.assertTrue('<h3>Next 1 elections</h3>' in output.data) + self.assertTrue('<h3>Last 2 elections</h3>' in output.data) + + +if __name__ == '__main__': + SUITE = unittest.TestLoader().loadTestsFromTestCase(FlaskSimpleElectionstests) + unittest.TextTestRunner(verbosity=2).run(SUITE) diff --git a/tests/test_vote.py b/tests/test_vote.py index c3d81e5..8d15279 100644 --- a/tests/test_vote.py +++ b/tests/test_vote.py @@ -176,6 +176,18 @@ class Votetests(Modeltests): self.session.commit() self.assertNotEqual(obj, None)
+ # Election 7 + + obj = models.Vote( #id:1 + election_id=7, + voter='toshio', + candidate_id=12, + value='1', + ) + self.session.add(obj) + self.session.commit() + self.assertNotEqual(obj, None) + def test_vote_count_with_votes(self): """ Test the Candidate.vote_count function with votes in. """ self.test_init_vote()
commit 96c803a6ddf46e31f140e0b194e21929dafb1abd Author: Joshua Santos nerdsville@nerdsville.net Date: Mon Aug 4 16:53:41 2014 -0700
Adding for abstain against feature
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py index 4abfbdc..b50951a 100644 --- a/fedora_elections/elections.py +++ b/fedora_elections/elections.py @@ -117,6 +117,8 @@ def vote(election_alias): return vote_simple(election) elif election.voting_type == 'select': return vote_select(election) + elif election.voting_type == 'for_abstain_against': + return vote_for_abstain_against(election) else: # pragma: no cover flask.flash( 'Unknown election voting type: %s' % election.voting_type) @@ -301,6 +303,47 @@ def vote_simple(election): nextaction=next_action)
+def vote_for_abstain_against(election): + votes = models.Vote.of_user_on_election( + SESSION, flask.g.fas_user.username, election.id, count=True) + + num_candidates = election.candidates.count() + + next_action = 'confirm' + form=forms.get_for_abstain_against_voting_form( + candidates=election.candidates, + fasusers=election.candidates_are_fasusers) + if form.validate_on_submit(): + if form.action.data == 'submit': + i=0 + for candidate in form: + if candidate.short_name in ['csrf_token', 'action']: + continue + new_vote = models.Vote( + election_id=election.id, + voter=flask.g.fas_user.username, + timestamp=datetime.now(), + candidate_id=form.candidate_ids[i-1], + value=candidate.data, + ) + i += 1 + SESSION.add(new_vote) + SESSION.commit() + flask.flash("Your vote has been recorded. Thank you!") + return safe_redirect_back() + + if form.action.data == 'preview': + flask.flash("Please confirm your vote!") + next_action = 'vote' + + return flask.render_template( + 'vote_simple.html', + election=election, + form=form, + num_candidates=num_candidates, + nextaction=next_action) + + @APP.route('/results/<election_alias>') def election_results(election_alias): election = get_valid_election(election_alias, ended=True) diff --git a/fedora_elections/forms.py b/fedora_elections/forms.py index 46c14ee..68cbed3 100644 --- a/fedora_elections/forms.py +++ b/fedora_elections/forms.py @@ -37,6 +37,7 @@ class ElectionForm(wtf.Form): ('range_3', 'Simplified Range Voting (max is set below)'), ('select', 'Select Voting (checkboxes for each candidate, ' 'maximum number of votes set below)'), + ('for_abstain_against', 'For - Abstain - Against (+1, neutral, -1)'), ], default='range')
@@ -159,6 +160,38 @@ def get_simple_voting_form(candidates, fasusers): return SimpleVoting()
+def get_for_abstain_against_voting_form(candidates, fasusers): + class ForAbstainAgainstVoting(wtf.Form): + action = wtforms.HiddenField() + titles = [] + candidate_ids = [] + fields = [] + for candidate in candidates: + title = candidate.name + if fasusers: # pragma: no cover + # We can't cover FAS integration + try: + title = \ + FAS2.person_by_username(candidate.name)['human_name'] + except (KeyError, AuthError), err: + APP.logger.debug(err) + if candidate.url: + title = '%s <a href="%s">[Info]</a>' % (title, candidate.url) + ForAbstainAgainstVoting.titles.append((str(candidate.id), title)) + ForAbstainAgainstVoting.candidate_ids.append(str(candidate.id)) + fields.append(wtforms.SelectField( + candidate.name, + choices=[('0',0),('1',1),('-1',-1)] + )) + def validate_field(form, field): + if field.data != '1' and field.data != '-1' and field.data != '0': + raise wtforms.ValidationError( + 'Not a valid integer value for vote.') + for i,field in enumerate(fields): + setattr(ForAbstainAgainstVoting,'candidate'+str(i),field) + return ForAbstainAgainstVoting() + + def get_select_voting_form(candidates, max_selection): class SelectVoting(wtf.Form): action = wtforms.HiddenField()
elections-devel@lists.stg.fedorahosted.org