fedora_elections/__init__.py | 6 +
fedora_elections/elections.py | 65 ++++++++++----
fedora_elections/models.py | 7 +
fedora_elections/templates/results.html | 4
fedora_elections/templates/results_text.html | 60 +++++++++++++
tests/test_flask_elections.py | 123 +++++++++++++++++++++++++++
6 files changed, 247 insertions(+), 18 deletions(-)
New commits:
commit 1f21208e5cf2d4680c4fdcdaca21ca2701efaab7
Merge: 7954b66 9dbe3fe
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Aug 1 11:52:03 2014 +0200
Merge pull request #33 from fedora-infra/text_results
Text results
commit 9dbe3fe02383e20ddc619c7ed10940424057a088
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Aug 1 11:45:03 2014 +0200
Add unit-test checking the text output with some vote/result
diff --git a/tests/test_flask_elections.py b/tests/test_flask_elections.py
index 65268c9..2d7c5d0 100644
--- a/tests/test_flask_elections.py
+++ b/tests/test_flask_elections.py
@@ -272,6 +272,47 @@ class FlaskElectionstests(ModelFlasktests):
username='toshio')
with user_set(fedora_elections.APP, user):
output = self.app.get(
+ '/results/test_election/text', follow_redirects=True)
+ self.assertEqual(output.status_code, 200)
+ exp = """<!DOCTYPE html>
+
+<html
xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
+ <title>Fedora elections</title>
+ <link rel="shortcut icon" type="image/vnd.microsoft.icon"
+
href="//fedoraproject.org/static/images/favicon.ico"/>
+ </head>
+ <body>
+<pre>
+Greetings, all!
+
+The elections for test election shortdesc have concluded, and the results
+are shown below.
+
+XXX is electing 1 seats this time.
+A total of 2 ballots were cast, meaning a candidate
+could accumulate up to 6 votes (2 * 3).
+
+The results for the elections are as follows:
+
+ # votes | name
+- --------+----------------------
+ 8 | Kevin
+- --------+----------------------
+ 7 | Ralph
+ 6 | Toshio
+
+
+Congratulations to the winning candidates, and thank you all
+candidates for running this elections!
+</pre>
+
+</body>
+</html>"""
+ self.assertEqual(output.data, exp)
+
+ output = self.app.get(
'/results/test_election2/text', follow_redirects=True)
self.assertEqual(output.status_code, 200)
exp = """<!DOCTYPE html>
commit 53316711f81df4730140087e3ec3c7e0010141d2
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Aug 1 11:26:47 2014 +0200
Fix typo in comment
Thanks @puiterwijk
diff --git a/fedora_elections/templates/results.html
b/fedora_elections/templates/results.html
index 9183faf..435073b 100644
--- a/fedora_elections/templates/results.html
+++ b/fedora_elections/templates/results.html
@@ -23,7 +23,7 @@
available), check if the number of votes for this candidate is lower than
the number of votes for the last candidate and if the Flag is False
So this takes care of the case where there are 10 seats elected and the 11th
- candidate as the same score as the 10th one.
+ candidate has the same score as the 10th one.
In this case we would end up with one more person that the number of seats
available and we'll need to either find a way to select one over the other
or deal with having one more candidate accepted #}
diff --git a/fedora_elections/templates/results_text.html
b/fedora_elections/templates/results_text.html
index f3947ec..9c99734 100644
--- a/fedora_elections/templates/results_text.html
+++ b/fedora_elections/templates/results_text.html
@@ -34,7 +34,7 @@ for candidate in
election.candidates|sort(attribute='vote_count', reverse=True)
than the number of votes for the last candidate and if the Flag is
False.
So this takes care of the case where there are 10 seats elected and
- the 11th candidate as the same score as the 10th one.
+ the 11th candidate has the same score as the 10th one.
In this case we would end up with one more person that the number of
seats available and we'll need to either find a way to select one
over the other or deal with having one more candidate accepted -#}
commit 8f1aec4281996acff1794c5835a1ffa803dbf96c
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Aug 1 11:24:27 2014 +0200
Fix check for showing the election announce template
You may be either an election admin or a plain all-mighty admin
Thanks @puiterwijk
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index 70ea77f..4abfbdc 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -357,8 +357,8 @@ def election_results_text(election_alias):
if not isinstance(election, models.Election): # pragma: no cover
return election
- if not (is_authenticated() and is_admin(flask.g.fas_user)
- and is_election_admin(flask.g.fas_user, election.id)):
+ if not (is_authenticated() and (is_admin(flask.g.fas_user)
+ or is_election_admin(flask.g.fas_user, election.id))):
flask.flash(
"The text results are only available to the admins",
"error")
return safe_redirect_back()
commit 7fce149fbb8f2b324e3c779dd9cc97b1ba5acebd
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Aug 1 11:07:11 2014 +0200
Simplify checking if the user is allowed to view the result page when the election is
under embargo
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index 355eabb..70ea77f 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -309,26 +309,19 @@ def election_results(election_alias):
return election
elif election.embargoed:
- if not is_authenticated():
+ if is_authenticated() and (
+ is_admin(flask.g.fas_user)
+ or is_election_admin(flask.g.fas_user, election.id)):
+ flask.flash("You are only seeing this page because you are "
+ "an admin.", "warning")
+ flask.flash("The results for this election are currently "
+ "embargoed pending formal announcement.",
+ "warning")
+ else:
flask.flash("We are sorry. The results for this election "
"cannot be viewed because they are currently "
"embargoed pending formal announcement.")
return safe_redirect_back()
- else:
- if is_admin(flask.g.fas_user) \
- or is_election_admin(flask.g.fas_user, election.id):
- flask.flash("You are only seeing this page because you are "
- "an admin.", "warning")
- flask.flash("The results for this election are currently "
- "embargoed pending formal announcement.",
- "warning")
- pass
- else:
- flask.flash(
- "We are sorry. The results for this election "
- "cannot be viewed because they are currently "
- "embargoed pending formal announcement.")
- return safe_redirect_back()
if is_authenticated() and (is_admin(flask.g.fas_user) \
or is_election_admin(flask.g.fas_user, election.id)):
commit 88b340563c8ee5bf5bbbfc6a397dccc2f07d5bf1
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Sat Jul 26 12:43:31 2014 +0200
Adjust calculating the maximum number of votes to use `max_vote`
diff --git a/fedora_elections/templates/results.html
b/fedora_elections/templates/results.html
index c4581b1..9183faf 100644
--- a/fedora_elections/templates/results.html
+++ b/fedora_elections/templates/results.html
@@ -68,7 +68,7 @@
</tr>
<tr>
<th title="Maximum number of votes possible">Maximum of
votes</th>
- <td>{{ stats['n_voters'] * stats['n_candidates']
}}</td>
+ <td>{{ stats['n_voters'] * stats['max_vote']
}}</td>
</tr>
{% if stats['candidate_voters'] %}
<tr>
diff --git a/fedora_elections/templates/results_text.html
b/fedora_elections/templates/results_text.html
index 59fbba0..f3947ec 100644
--- a/fedora_elections/templates/results_text.html
+++ b/fedora_elections/templates/results_text.html
@@ -16,7 +16,7 @@ are shown below.
XXX is electing {{ election.seats_elected }} seats this time.
A total of {{stats['n_voters'] }} ballots were cast, meaning a candidate
-could accumulate up to {{ stats['n_voters'] * stats['n_candidates'] }}
votes ({{stats['n_voters'] }} * {{ stats['n_candidates'] }}).
+could accumulate up to {{ stats['n_voters'] * stats['max_vote'] }} votes
({{stats['n_voters'] }} * {{ stats['max_vote'] }}).
The results for the elections are as follows:
commit 9e82fe2336d0f4790f30b06a65968a688516f232
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Sat Jul 26 12:43:02 2014 +0200
Add a `max_vote` entry in the stats table used for the result page
diff --git a/fedora_elections/models.py b/fedora_elections/models.py
index d35096f..1cc51f4 100644
--- a/fedora_elections/models.py
+++ b/fedora_elections/models.py
@@ -414,6 +414,13 @@ class Vote(BASE):
stats['candidate_voters'] = candidate_voters
stats['n_candidates'] = cnt
+ if election.voting_type in ['range', 'select']:
+ stats['max_vote'] = cnt
+ if election.max_votes:
+ stats['max_vote'] = election.max_votes
+ elif election.voting_type == 'simple':
+ stats['max_vote'] = 1
+
return stats
commit 4359ef64463bbf915f48404e3912f9a958aaf46b
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:52:51 2014 +0200
Add unit-tests for the text output of the results
diff --git a/tests/test_flask_elections.py b/tests/test_flask_elections.py
index 397db4a..65268c9 100644
--- a/tests/test_flask_elections.py
+++ b/tests/test_flask_elections.py
@@ -238,6 +238,88 @@ class FlaskElectionstests(ModelFlasktests):
' and you may not see its results yet.</li>' in
output.data)
self.assertTrue('<h3>Current elections</h3>' in
output.data)
+ def test_election_results_text(self):
+ """ Test the election_results_text function - the preview part.
"""
+ output = self.app.get(
+ '/results/test_election/text', follow_redirects=True)
+ self.assertEqual(output.status_code, 200)
+ self.assertTrue(
+ 'class="message">The election, test_election, does not
exist.</'
+ in output.data)
+
+ self.setup_db()
+
+ output = self.app.get(
+ '/results/test_election/text', follow_redirects=True)
+ self.assertEqual(output.status_code, 200)
+ self.assertTrue(
+ 'class="error">The text results are only available to the
'
+ 'admins</li>' in output.data)
+ self.assertTrue('<h2>Elections</h2>' in output.data)
+
+ user = FakeUser(['packager'], username='toshio')
+ with user_set(fedora_elections.APP, user):
+ output = self.app.get(
+ '/results/test_election2/text', follow_redirects=True)
+ self.assertEqual(output.status_code, 200)
+ self.assertTrue(
+ 'class="error">The text results are only available to
the '
+ 'admins</li>' in output.data)
+ self.assertTrue('<h2>Elections</h2>' in output.data)
+
+ user = FakeUser(
+ fedora_elections.APP.config['FEDORA_ELECTIONS_ADMIN_GROUP'],
+ username='toshio')
+ with user_set(fedora_elections.APP, user):
+ output = self.app.get(
+ '/results/test_election2/text', follow_redirects=True)
+ self.assertEqual(output.status_code, 200)
+ exp = """<!DOCTYPE html>
+
+<html
xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
+ <title>Fedora elections</title>
+ <link rel="shortcut icon" type="image/vnd.microsoft.icon"
+
href="//fedoraproject.org/static/images/favicon.ico"/>
+ </head>
+ <body>
+<pre>
+Greetings, all!
+
+The elections for test election 2 shortdesc have concluded, and the results
+are shown below.
+
+XXX is electing 1 seats this time.
+A total of 0 ballots were cast, meaning a candidate
+could accumulate up to 0 votes (0 * 0).
+
+The results for the elections are as follows:
+
+ # votes | name
+- --------+----------------------
+
+
+Congratulations to the winning candidates, and thank you all
+candidates for running this elections!
+</pre>
+
+</body>
+</html>"""
+
+ self.assertEqual(output.data, exp)
+
+ user = FakeUser(['gitr2spec'], username='kevin')
+ with user_set(fedora_elections.APP, user):
+ output = self.app.get(
+ '/results/test_election3/text', follow_redirects=True)
+ self.assertEqual(output.status_code, 200)
+ self.assertTrue(
+ '<li class="message">Sorry but this election is in
progress,'
+ ' and you may not see its results yet.</li>' in
output.data)
+ self.assertTrue('<h3>Current elections</h3>' in
output.data)
+
+
if __name__ == '__main__':
SUITE = unittest.TestLoader().loadTestsFromTestCase(FlaskElectionstests)
commit 86578361f7e9dbb40fabbe4f08bfdc78d13202ea
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:45:04 2014 +0200
Rely on the is_authenticated() where it makes sense
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index 5227ddb..355eabb 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -309,7 +309,7 @@ def election_results(election_alias):
return election
elif election.embargoed:
- if not hasattr(flask.g, 'fas_user') or not flask.g.fas_user:
+ if not is_authenticated():
flask.flash("We are sorry. The results for this election "
"cannot be viewed because they are currently "
"embargoed pending formal announcement.")
commit 950db261e90a6244f667dcc6b5bc00836b3f8354
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:44:14 2014 +0200
Optimization: by using `and` instead of `or` will stop the condition at the first
False
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index e7b9893..5227ddb 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -364,8 +364,8 @@ def election_results_text(election_alias):
if not isinstance(election, models.Election): # pragma: no cover
return election
- if not is_authenticated() or not is_admin(flask.g.fas_user) \
- or not is_election_admin(flask.g.fas_user, election.id):
+ if not (is_authenticated() and is_admin(flask.g.fas_user)
+ and is_election_admin(flask.g.fas_user, election.id)):
flask.flash(
"The text results are only available to the admins",
"error")
return safe_redirect_back()
commit 0d63467564d94d5497ac2da10002ba3d1438bc6d
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:43:43 2014 +0200
Check is the user is authenticated before checking if he/she is an admin
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index a4ca812..e7b9893 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -330,8 +330,8 @@ def election_results(election_alias):
"embargoed pending formal announcement.")
return safe_redirect_back()
- if is_admin(flask.g.fas_user) \
- or is_election_admin(flask.g.fas_user, election.id):
+ if is_authenticated() and (is_admin(flask.g.fas_user) \
+ or is_election_admin(flask.g.fas_user, election.id)):
flask.flash(
"Check out the <a href='%s'>Text version</a> "
"to send the annoucement" % flask.url_for(
commit cbad3d6573394df0b9c85e619956e6ab464db6b7
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:36:36 2014 +0200
Let's make it simple: only admins can see the text version of the results page
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index 30a7c8f..a4ca812 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -364,12 +364,10 @@ def election_results_text(election_alias):
if not isinstance(election, models.Election): # pragma: no cover
return election
- elif election.embargoed and (
- not is_admin(flask.g.fas_user)
- or not is_election_admin(flask.g.fas_user, election.id)):
+ if not is_authenticated() or not is_admin(flask.g.fas_user) \
+ or not is_election_admin(flask.g.fas_user, election.id):
flask.flash(
- "The text results are only available to admins when the election"
- " is under embargo")
+ "The text results are only available to the admins",
"error")
return safe_redirect_back()
usernamemap = {}
commit 0f507e6a1f3b392f4b9a457093c299b5e7adbf66
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:30:58 2014 +0200
Add a flash message for the election admins pointing them to the text version of the
results
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index 9a00384..30a7c8f 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -330,6 +330,14 @@ def election_results(election_alias):
"embargoed pending formal announcement.")
return safe_redirect_back()
+ if is_admin(flask.g.fas_user) \
+ or is_election_admin(flask.g.fas_user, election.id):
+ flask.flash(
+ "Check out the <a href='%s'>Text version</a> "
+ "to send the annoucement" % flask.url_for(
+ 'election_results_text', election_alias=election.alias)
+ )
+
usernamemap = {}
if (election.candidates_are_fasusers): # pragma: no cover
for candidate in election.candidates:
commit 0265cac5246d6729e3518448c7e2d84f7c4ef785
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:30:25 2014 +0200
Create a new endpoint providing the election results in text
This endpoint can be used as a basis to make the announcement
diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py
index 2b5c407..9a00384 100644
--- a/fedora_elections/elections.py
+++ b/fedora_elections/elections.py
@@ -348,3 +348,37 @@ def election_results(election_alias):
usernamemap=usernamemap,
stats=stats,
)
+
+(a)APP.route('/results/<election_alias>/text')
+def election_results_text(election_alias):
+ election = get_valid_election(election_alias, ended=True)
+
+ if not isinstance(election, models.Election): # pragma: no cover
+ return election
+
+ elif election.embargoed and (
+ not is_admin(flask.g.fas_user)
+ or not is_election_admin(flask.g.fas_user, election.id)):
+ flask.flash(
+ "The text results are only available to admins when the election"
+ " is under embargo")
+ return safe_redirect_back()
+
+ usernamemap = {}
+ if (election.candidates_are_fasusers): # pragma: no cover
+ for candidate in election.candidates:
+ try:
+ usernamemap[candidate.id] = \
+ FAS2.person_by_username(candidate.name)['human_name']
+ except (KeyError, AuthError):
+ # User has their name set to private or user doesn't exist.
+ usernamemap[candidate.id] = candidate.name
+
+ stats = models.Vote.get_election_stats(SESSION, election.id)
+
+ return flask.render_template(
+ 'results_text.html',
+ election=election,
+ usernamemap=usernamemap,
+ stats=stats,
+ )
commit fd85d73c6d8f9bb31d4e711e0b7f433ce2038a74
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:29:28 2014 +0200
Add a new template presenting the results in the format of the announcements
diff --git a/fedora_elections/templates/results_text.html
b/fedora_elections/templates/results_text.html
new file mode 100644
index 0000000..59fbba0
--- /dev/null
+++ b/fedora_elections/templates/results_text.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+
+<html
xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
+ <title>{% block title %}Fedora elections{% endblock %}</title>
+ <link rel="shortcut icon" type="image/vnd.microsoft.icon"
+
href="//fedoraproject.org/static/images/favicon.ico"/>
+ </head>
+ <body>
+<pre>
+Greetings, all!
+
+The elections for {{ election.shortdesc }} have concluded, and the results
+are shown below.
+
+XXX is electing {{ election.seats_elected }} seats this time.
+A total of {{stats['n_voters'] }} ballots were cast, meaning a candidate
+could accumulate up to {{ stats['n_voters'] * stats['n_candidates'] }}
votes ({{stats['n_voters'] }} * {{ stats['n_candidates'] }}).
+
+The results for the elections are as follows:
+
+ # votes | name
+- --------+----------------------{%
+for candidate in election.candidates|sort(attribute='vote_count', reverse=True)
-%}
+ {% if loop.index <= election.seats_elected -%}
+ {# If we are below the number of user that will be selected,
+ get the number of votes and the flag to False -#}
+ {% set flag = False -%}
+ {% set votes = candidate.vote_count -%}
+ {%- elif loop.index > election.seats_elected and votes > candidate.vote_count and
not flag -%}
+ {# if we are above the number of user that will be selected (seats
+ available), check if the number of votes for this candidate is lower
+ than the number of votes for the last candidate and if the Flag is
+ False.
+ So this takes care of the case where there are 10 seats elected and
+ the 11th candidate as the same score as the 10th one.
+ In this case we would end up with one more person that the number of
+ seats available and we'll need to either find a way to select one
+ over the other or deal with having one more candidate accepted -#}
+ {% set flag = True -%}
+ {% set lastrow = True -%}
+ {%- else -%}
+ {# we are above the number of seats available, the number of votes is
+ below that of the last candidate above selected and the Flag is True
+ which means we already passed the condition above -#}
+ {% set lastrow = False -%} {%- endif %}{% if lastrow == True %}
+- --------+---------------------- {%- endif %}
+{{ candidate.vote_count | rjust(8) }} | {% if election.candidates_are_fasusers -%}
+ {{ usernamemap[candidate.id] }} {%- else -%} {{candidate.name}}
+ {%- endif %}
+{%- endfor %}
+
+
+Congratulations to the winning candidates, and thank you all
+candidates for running this elections!
+</pre>
+
+</body>
+</html>
commit 9aa5c7d0c5c3833a2ae6216381ab3ea2c7db0f8b
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Fri Jul 25 15:28:19 2014 +0200
Create a new jinja filter that rjust() some provided text
diff --git a/fedora_elections/__init__.py b/fedora_elections/__init__.py
index fd5f3e5..2fd1222 100644
--- a/fedora_elections/__init__.py
+++ b/fedora_elections/__init__.py
@@ -152,6 +152,12 @@ def inject_variables():
return dict(is_admin=is_admin(user),
version=__version__)
+(a)APP.template_filter('rjust')
+def rjust_filter(text, length):
+ """ Run a rjust command on the text for the given length
+ """
+ return str(text).rjust(length)
+
# LIST VIEWS #############################################