From 939f5b04552ce72e7d6bc94a078dc0162a82d762 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Oct 16 2017 15:20:13 +0000 Subject: [PATCH 1/2] Link to the text version of the results in the admin banner Signed-off-by: Pierre-Yves Chibon --- diff --git a/fedora_elections/templates/about.html b/fedora_elections/templates/about.html index 3494c0b..2518b27 100644 --- a/fedora_elections/templates/about.html +++ b/fedora_elections/templates/about.html @@ -101,6 +101,8 @@

You are only seeing these results because you are an admin.

The results for this election are currently embargoed pending formal announcement

+

Consult the text version of the results

{% endif %}

Results

From 023730a14613ec9342bcabff094b04e69ea331ef Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Oct 16 2017 15:32:45 +0000 Subject: [PATCH 2/2] Project wide flake8 fixes Signed-off-by: Pierre-Yves Chibon --- diff --git a/fedora_elections/__init__.py b/fedora_elections/__init__.py index feb3d8f..ced565e 100644 --- a/fedora_elections/__init__.py +++ b/fedora_elections/__init__.py @@ -26,27 +26,27 @@ __version__ = '2.6.1' -import logging -import os -import sys -import urllib -import hashlib -import arrow +import logging # noqa +import os # noqa +import sys # noqa +import urllib # noqa +import hashlib # noqa +import arrow # noqa -from datetime import datetime, time, timedelta -from functools import wraps -from urlparse import urlparse, urljoin +from datetime import datetime, time, timedelta # noqa +from functools import wraps # noqa +from urlparse import urlparse, urljoin # noqa -import flask +import flask # noqa -from fedora.client import AuthError, AppError -from fedora.client.fas2 import AccountSystem -from flask_fas_openid import FAS +from fedora.client import AuthError, AppError # noqa +from fedora.client.fas2 import AccountSystem # noqa +from flask_fas_openid import FAS # noqa -import fedora_elections.fedmsgshim -import fedora_elections.mail_logging -import fedora_elections.proxy +import fedora_elections.fedmsgshim # noqa +import fedora_elections.mail_logging # noqa +import fedora_elections.proxy # noqa APP = flask.Flask(__name__) APP.config.from_object('fedora_elections.default_config') @@ -82,12 +82,12 @@ FAS2 = AccountSystem( # modular imports -from fedora_elections import models +from fedora_elections import models # noqa SESSION = models.create_session(APP.config['DB_URL']) -from fedora_elections import forms +from fedora_elections import forms # noqa -from fedora_elections.utils import build_name_map +from fedora_elections.utils import build_name_map # noqa def is_authenticated(): @@ -101,8 +101,7 @@ def is_safe_url(target): website not some other malicious one. """ ref_url = urlparse(flask.request.host_url) - test_url = urlparse( - urljoin(flask.request.host_url, target)) + test_url = urlparse(urljoin(flask.request.host_url, target)) return test_url.scheme in ('http', 'https') and \ ref_url.netloc == test_url.netloc @@ -144,14 +143,6 @@ def is_election_admin(user, election_id): return len(set(user.groups).intersection(set(admingroups))) > 0 -def is_safe_url(target): - ''' Check is a url is safe to use or not. ''' - ref_url = urlparse(flask.request.host_url) - test_url = urlparse(urljoin(flask.request.host_url, target)) - return test_url.scheme in ('http', 'https') and \ - ref_url.netloc == test_url.netloc - - def safe_redirect_back(next=None, fallback=('index', {})): ''' Safely redirect the user to its previous page. ''' targets = [] @@ -184,20 +175,24 @@ def rjust_filter(text, length): """ return str(text).rjust(length) + @APP.template_filter('avatar') def avatar_filter(openid, size=64, default='retro'): query = urllib.urlencode({'s': size, 'd': default}) hashhex = hashlib.sha256(openid).hexdigest() return "https://seccdn.libravatar.org/avatar/%s?%s" % (hashhex, query) + @APP.template_filter('humanize') def humanize_date(date): return arrow.get(date).humanize() + @APP.template_filter('prettydate') def prettydate(date): return date.strftime('%A %B %d %Y %X UTC') + # pylint: disable=W0613 @APP.before_request def set_session(): @@ -243,7 +238,7 @@ def index(): @APP.route('/about/') def about_election(election_alias): election = models.Election.get(SESSION, alias=election_alias) - stats=[] + stats = [] evolution_label = [] evolution_data = [] if not election: @@ -284,16 +279,15 @@ def about_election(election_alias): def archived_elections(): now = datetime.utcnow() - elections = models.Election.get_older_election(SESSION, now) + old_elections = models.Election.get_older_election(SESSION, now) - if not elections: + if not old_elections: flask.flash('There are no archived elections.') return safe_redirect_back() return flask.render_template( 'archive.html', - elections=elections) - + elections=old_elections) @APP.route('/login', methods=('GET', 'POST')) @@ -326,5 +320,5 @@ def auth_logout(): # Finalize the import of other controllers -import admin -import elections +import admin # noqa +import elections # noqa diff --git a/fedora_elections/admin.py b/fedora_elections/admin.py index 5d560de..292e30a 100644 --- a/fedora_elections/admin.py +++ b/fedora_elections/admin.py @@ -35,8 +35,7 @@ from fedora_elections import fedmsgshim from fedora_elections import forms from fedora_elections import models from fedora_elections import ( - APP, SESSION, FAS2, is_authenticated, is_admin, is_election_admin, - is_safe_url, safe_redirect_back + APP, SESSION, FAS2, is_authenticated, is_admin ) @@ -52,7 +51,6 @@ def election_admin_required(f): return decorated_function - @APP.route('/admin/new', methods=('GET', 'POST')) @election_admin_required def admin_new_election(): @@ -227,8 +225,9 @@ def admin_add_candidate(election_alias): fas_name = None if election.candidates_are_fasusers: # pragma: no cover try: - fas_name = FAS2.person_by_username(form.name.data)['human_name'] - except (KeyError, AuthError), err: + fas_name = FAS2.person_by_username( + form.name.data)['human_name'] + except (KeyError, AuthError): flask.flash( 'User `%s` does not have a FAS account.' % form.name.data, 'error') @@ -284,7 +283,7 @@ def admin_add_multi_candidate(election_alias): try: fas_name = FAS2.person_by_username( candidate[0])['human_name'] - except (KeyError, AuthError), err: + except (KeyError, AuthError): SESSION.rollback() flask.flash( 'User `%s` does not have a FAS account.' @@ -350,12 +349,11 @@ def admin_edit_candidate(election_alias, candidate_id): if form.validate_on_submit(): form.populate_obj(candidate) - fas_name = None if election.candidates_are_fasusers: # pragma: no cover try: candidate.fas_name = FAS2.person_by_username( candidate.name)['human_name'] - except (KeyError, AuthError), err: + except (KeyError, AuthError): SESSION.rollback() flask.flash( 'User `%s` does not have a FAS account.' diff --git a/fedora_elections/elections.py b/fedora_elections/elections.py index 3f9af76..ac80ef7 100644 --- a/fedora_elections/elections.py +++ b/fedora_elections/elections.py @@ -24,18 +24,16 @@ # Pierre-Yves Chibon # -from datetime import datetime, time, timedelta +from datetime import datetime from functools import wraps import flask -from fedora.client import AuthError -from fedora_elections import fedmsgshim from fedora_elections import forms from fedora_elections import models from fedora_elections import ( - APP, SESSION, FAS2, is_authenticated, is_admin, is_election_admin, - is_safe_url, safe_redirect_back, + APP, SESSION, is_authenticated, is_admin, is_election_admin, + safe_redirect_back, ) from fedora_elections.utils import build_name_map @@ -121,13 +119,36 @@ def vote(election_alias): return safe_redirect_back() +@APP.route('/results//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 + + 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() + + usernamemap = build_name_map(election) + + stats = models.Vote.get_election_stats(SESSION, election.id) + + return flask.render_template( + 'results_text.html', + election=election, + usernamemap=usernamemap, + stats=stats, + ) + + def vote_range(election, revote): votes = models.Vote.of_user_on_election( SESSION, flask.g.fas_user.username, election.id) num_candidates = election.candidates.count() - - cand_ids = [str(cand.id) for cand in election.candidates] next_action = 'confirm' max_selection = num_candidates @@ -140,11 +161,12 @@ def vote_range(election, revote): if form.validate_on_submit(): if form.action.data == 'submit': - candidates = [ + candidates = [ candidate for candidate in form - if candidate and candidate.short_name not in ['csrf_token', 'action'] - ] + if candidate + and candidate.short_name not in ['csrf_token', 'action'] + ] process_vote(candidates, election, votes, revote) flask.flash("Your vote has been recorded. Thank you!") return safe_redirect_back() @@ -188,7 +210,8 @@ def vote_select(election, revote): cnt = [ candidate for candidate in form - if candidate.data and candidate.short_name not in ['csrf_token', 'action'] + if candidate.data + and candidate.short_name not in ['csrf_token', 'action'] ] if len(cnt) > max_selection: flask.flash('Too many candidates submitted', 'error') @@ -197,7 +220,8 @@ def vote_select(election, revote): candidates = [ candidate for candidate in form - if candidate and candidate.short_name not in ['csrf_token', 'action'] + if candidate + and candidate.short_name not in ['csrf_token', 'action'] ] process_vote(candidates, election, votes, revote, cand_name) flask.flash("Your vote has been recorded. Thank you!") @@ -233,10 +257,11 @@ def vote_simple(election, revote): if form.validate_on_submit(): if form.action.data == 'submit': - candidates = [ + candidates = [ candidate for candidate in form - if candidate and candidate.short_name not in ['csrf_token', 'action'] + if candidate + and candidate.short_name not in ['csrf_token', 'action'] ] process_vote(candidates, election, votes, revote, value=1) flask.flash("Your vote has been recorded. Thank you!") @@ -270,10 +295,11 @@ def vote_irc(election, revote): fasusers=election.candidates_are_fasusers) if form.validate_on_submit(): if form.action.data == 'submit': - candidates = [ + candidates = [ candidate for candidate in form - if candidate and candidate.short_name not in ['csrf_token', 'action'] + if candidate + and candidate.short_name not in ['csrf_token', 'action'] ] process_vote(candidates, election, votes, revote, cand_name) flask.flash("Your vote has been recorded. Thank you!") @@ -290,32 +316,9 @@ def vote_irc(election, revote): num_candidates=num_candidates, nextaction=next_action) -@APP.route('/results//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 - - 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() - - usernamemap = build_name_map(election) - - stats = models.Vote.get_election_stats(SESSION, election.id) - - return flask.render_template( - 'results_text.html', - election=election, - usernamemap=usernamemap, - stats=stats, - ) - -def process_vote(candidates, election, votes, revote, cand_name=None, value=None): +def process_vote( + candidates, election, votes, revote, cand_name=None, value=None): for index in range(len(candidates)): candidate = candidates[index] if revote and (index+1 <= len(votes)): @@ -338,7 +341,7 @@ def process_vote(candidates, election, votes, revote, cand_name=None, value=None voter=flask.g.fas_user.username, timestamp=datetime.utcnow(), candidate_id=cand_id, - value= value if value else int(candidate.data), + value=value if value else int(candidate.data), ) SESSION.add(new_vote) SESSION.commit() diff --git a/fedora_elections/forms.py b/fedora_elections/forms.py index 2419afd..f218965 100644 --- a/fedora_elections/forms.py +++ b/fedora_elections/forms.py @@ -2,7 +2,6 @@ import flask import wtforms -import flask_wtf as wtf try: from flask_wtf import FlaskForm except ImportError: @@ -10,7 +9,7 @@ except ImportError: from fedora.client import AuthError -from fedora_elections import SESSION, FAS2 +from fedora_elections import SESSION, FAS2, APP from fedora_elections.models import Election diff --git a/fedora_elections/models.py b/fedora_elections/models.py index e7d9d3d..1772d4d 100644 --- a/fedora_elections/models.py +++ b/fedora_elections/models.py @@ -1,26 +1,18 @@ # -*- coding: utf-8 -*- +from datetime import datetime import sqlalchemy as sa from sqlalchemy import create_engine from sqlalchemy import func as safunc -from sqlalchemy.ext.associationproxy import association_proxy -from sqlalchemy.ext.compiler import compiles from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import scoped_session -from sqlalchemy.orm import relation, relationship +from sqlalchemy.orm import relationship from sqlalchemy.orm import backref -from sqlalchemy.orm.collections import attribute_mapped_collection -from sqlalchemy.orm.collections import mapped_collection -from sqlalchemy.orm.exc import NoResultFound -from sqlalchemy.sql import and_ -from sqlalchemy.sql.expression import Executable, ClauseElement BASE = declarative_base() -from datetime import datetime - def create_tables(db_url, alembic_ini=None, debug=False): """ Create the tables in the database using the information from the diff --git a/fedora_elections/utils.py b/fedora_elections/utils.py index cc82fc2..4bf23d1 100644 --- a/fedora_elections/utils.py +++ b/fedora_elections/utils.py @@ -2,8 +2,6 @@ import fedora_elections -from fedora.client import AuthError - def build_name_map(election): """ Returns a mapping of candidate ids to fas human_names. """