Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework the rest of the pages #69

Merged
merged 22 commits into from Jan 9, 2017
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0b8674a
remove closed elections from frontpage. relabel archives to results
ryanlerch Oct 26, 2016
bf85141
show all upcoming elections on index. remove open page.
ryanlerch Oct 26, 2016
29212b0
front page style changes
ryanlerch Oct 26, 2016
0b13c75
fix enddate resetting to 00:00:00 when editing an election
ryanlerch Oct 31, 2016
0ae62e1
finish reworking all the pages
ryanlerch Nov 2, 2016
b430f92
remove edit election details page, as this is now in the main edit
ryanlerch Nov 2, 2016
749d65e
fix css to make the graph on results page show
ryanlerch Nov 29, 2016
88a2363
made the candidates list not show if election is over
ryanlerch Nov 29, 2016
284fb74
add back the red line that showing the cutoff in the results
ryanlerch Nov 29, 2016
a6f6b1f
merged the voters per candidate and averages into the results table
ryanlerch Nov 29, 2016
aafcde5
styled up the results table
ryanlerch Nov 29, 2016
b13d9ef
converted the statistics section to some dotpoints
ryanlerch Nov 29, 2016
38fd7c9
change the elections admin group back to elections
ryanlerch Nov 29, 2016
31d00b6
added requirement for arrow in requirements.txt
ryanlerch Dec 12, 2016
7a9d41a
made the datepicker dropdown work on the edit page
ryanlerch Dec 12, 2016
354b435
fixed irc voting form and simple voting form
ryanlerch Dec 12, 2016
707468a
made the edit election page 2-col
ryanlerch Dec 12, 2016
7251869
started fixing tests
ryanlerch Dec 12, 2016
db7ffe9
fix admind groups not prefilling in form
ryanlerch Dec 13, 2016
d895cae
finished fixing the tests
ryanlerch Dec 13, 2016
1943dc4
tidy up two more lines
ryanlerch Jan 9, 2017
4698dbc
fixed over-indentation
ryanlerch Jan 9, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 38 additions & 29 deletions fedora_elections/__init__.py
Expand Up @@ -31,8 +31,10 @@
import sys
import urllib
import hashlib
import arrow

from datetime import datetime, time

from datetime import datetime, time, timedelta
from functools import wraps
from urlparse import urlparse, urljoin

Expand Down Expand Up @@ -188,6 +190,14 @@ def avatar_filter(openid, size=64, default='retro'):
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():
Expand All @@ -210,7 +220,7 @@ def index():

prev_elections = models.Election.get_older_election(SESSION, now)[:5]
cur_elections = models.Election.get_open_election(SESSION, now)
next_elections = models.Election.get_next_election(SESSION, now)[:3]
next_elections = models.Election.get_next_election(SESSION, now)

voted = []
if is_authenticated():
Expand All @@ -233,17 +243,41 @@ def index():
@APP.route('/about/<election_alias>')
def about_election(election_alias):
election = models.Election.get(SESSION, alias=election_alias)

stats=[]
evolution_label = []
evolution_data = []
if not election:
flask.flash('The election, %s, does not exist.' % election_alias)
return safe_redirect_back()
elif election.status == 'Embargoed' or election.status == 'Ended':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe just elif election.status in ['Embargoed', 'Ended']?


stats = models.Vote.get_election_stats(SESSION, election.id)
cnt = 1
for delta in range((election.end_date - election.start_date).days + 1):
day = (
election.start_date + timedelta(days=delta)
).strftime('%d-%m-%Y')
evolution_label.append([cnt, day])
evolution_data.append([cnt, stats['vote_timestamps'].count(day)])
cnt += 1

usernamemap = build_name_map(election)

voted = []
if is_authenticated():
votes = models.Vote.of_user_on_election(
SESSION, flask.g.fas_user.username, election.id, count=True)
if votes > 0:
voted.append(election)

return flask.render_template(
'about.html',
election=election,
usernamemap=usernamemap)
usernamemap=usernamemap,
stats=stats,
voted=voted,
evolution_label=evolution_label,
evolution_data=evolution_data)


@APP.route('/archives')
Expand All @@ -261,31 +295,6 @@ def archived_elections():
elections=elections)


@APP.route('/open')
def open_elections():
now = datetime.utcnow()

elections = models.Election.get_open_election(SESSION, now)

if not elections:
flask.flash('There are no open elections.')
return safe_redirect_back()

voted = []
if is_authenticated():
for elec in elections:
votes = models.Vote.of_user_on_election(
SESSION, flask.g.fas_user.username, elec.id, count=True)
if votes > 0:
voted.append(elec)

return flask.render_template(
'index.html',
next_elections=elections,
voted=voted,
tag='open',
title='Open Elections')


@APP.route('/login', methods=('GET', 'POST'))
def auth_login():
Expand Down
30 changes: 13 additions & 17 deletions fedora_elections/admin.py
Expand Up @@ -126,25 +126,13 @@ def admin_new_election():
submit_text='Create election')


@APP.route('/admin/<election_alias>/')
@APP.route('/admin/<election_alias>/', methods=('GET', 'POST'))
@election_admin_required
def admin_view_election(election_alias):
election = models.Election.get(SESSION, alias=election_alias)
if not election:
flask.abort(404)

return flask.render_template(
'admin/view_election.html',
election=election)


@APP.route('/admin/<election_alias>/edit', methods=('GET', 'POST'))
@election_admin_required
def admin_edit_election(election_alias):
election = models.Election.get(SESSION, alias=election_alias)
if not election:
flask.abort(404)

print election.admin_groups_list
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this one can be dropped :)

form = forms.ElectionForm(election.id, obj=election)
if form.validate_on_submit():
form.embargoed.data = int(form.embargoed.data)
Expand All @@ -160,6 +148,12 @@ def admin_edit_election(election_alias):
form.candidates_are_fasusers.data)
form.populate_obj(election)

# Fix start_date and end_date to use datetime
election.start_date = datetime.combine(election.start_date, time())
election.end_date = datetime.combine(election.end_date,
time(23, 59, 59))
SESSION.add(election)

admin_groups = set(election.admin_groups_list)

new_groups = set(
Expand Down Expand Up @@ -213,10 +207,12 @@ def admin_edit_election(election_alias):

form.admin_grp.data = ', '.join(election.admin_groups_list)
form.lgl_voters.data = ', '.join(election.legal_voters_list)

return flask.render_template(
'admin/election_form.html',
form=form,
submit_text='Edit election')
'admin/view_election.html',
election=election,
form=form,
submit_text='Edit election')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Over-indented?



@APP.route('/admin/<election_alias>/candidates/new', methods=('GET', 'POST'))
Expand Down
62 changes: 1 addition & 61 deletions fedora_elections/elections.py
Expand Up @@ -74,11 +74,8 @@ def get_valid_election(election_alias, ended=False):
return safe_redirect_back()

elif not ended and election.status in ('Ended', 'Embargoed'):
flask.flash(
'This election is closed. You have been redirected to the '
'election results.')
return flask.redirect(flask.url_for(
'election_results', election_alias=election.alias))
'about_election', election_alias=election.alias))

elif ended and election.status == 'In progress':
flask.flash(
Expand Down Expand Up @@ -293,63 +290,6 @@ def vote_irc(election, revote):
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)

if not isinstance(election, models.Election): # pragma: no cover
return election

elif election.embargoed:
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()

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(
'election_results_text', election_alias=election.alias)
)

usernamemap = build_name_map(election)

stats = models.Vote.get_election_stats(SESSION, election.id)

cnt = 1
evolution_label = []
evolution_data = []
for delta in range((election.end_date - election.start_date).days + 1):
day = (
election.start_date + timedelta(days=delta)
).strftime('%d-%m-%Y')
evolution_label.append([cnt, day])
evolution_data.append([cnt, stats['vote_timestamps'].count(day)])
cnt += 1

return flask.render_template(
'results.html',
election=election,
usernamemap=usernamemap,
stats=stats,
evolution_label=evolution_label,
evolution_data=evolution_data,
)


@APP.route('/results/<election_alias>/text')
def election_results_text(election_alias):
election = get_valid_election(election_alias, ended=True)
Expand Down
27 changes: 27 additions & 0 deletions fedora_elections/static/elections.css
Expand Up @@ -9,3 +9,30 @@
.stretch-cell{
min-width:99%
}

.voting-sheet{
border: 2px solid black
}

.c-select.fullwidth{
width:100%;
}

.evolution-container {
box-sizing: border-box;
height: 325px;
padding: 10px 10px 15px 10px;
margin: 15px auto 30px auto;
}

.evolution-placeholder {
width: 100%;
height: 100%;
font-size: 14px;
line-height: 1.2em;
}

#results .firstout tr,
#results .firstout td {
border-top: 2px solid red !important;
}
78 changes: 51 additions & 27 deletions fedora_elections/templates/_formhelpers.html
Expand Up @@ -15,7 +15,7 @@
<tr>
<td>{% if usernamemap %} {{ usernamemap[field.name] }} {%
else %} {{ field.label }} {% endif %}</td>
<td>{{ field(**kwargs)|safe }}</td>
<td>{{ field(class_="c-select", **kwargs)|safe }}</td>
{% if after %} <td>{{ after }}</td>{% endif %}
{% if field.errors %}{% for error in field.errors
%}<td class="error">{{ error }}</td>{% endfor %}{% endif %}
Expand Down Expand Up @@ -47,7 +47,7 @@
<div class="form-group {% if field.errors %}has-danger{% endif %}">
{% if usernamemap %} {{ usernamemap[field.name] }} {%
else %} {{ field.label() }} {% endif %}
{{ field(class_="c-select", **kwargs)|safe }}
{{ field(class_="c-select fullwidth", **kwargs)|safe }}
{% if after %} <div><small class="text-muted">{{ after }}</small></div>{% endif %}
{% if field.errors %}
{% for error in field.errors%}
Expand All @@ -72,30 +72,54 @@
</div>
{% endmacro %}

{% macro render_field_data_in_row(field, num_candidates, usernamemap=None, after="") %}
<tr>
<td>{% if usernamemap %} {{ usernamemap[field.name] }} {%
else %} {{ field.label }} {% endif %}</td>
<td>
{% set weightpercent = (field.data | int *100) / num_candidates %}
{% if weightpercent >= 90 %}
<div class="vthot">
{% elif weightpercent >= 70 %}
<div class="vtwarm">
{% elif weightpercent >= 50 %}
<div class="vtmedwarm">
{% elif weightpercent >= 30 %}
<div class="vtmedcool">
{% elif weightpercent >= 10 %}
<div class="vtcool">
{% else %}
<div class="vtcold">
{% macro render_field_data_in_row(field, usernamemap=None, after="") %}
<div class="list-group-item {% if field.errors %}has-danger list-group-item-danger{% endif %}">
{% if usernamemap %} {{ usernamemap[field.name] }} {%
else %} {{ field.label }} {% endif %}
{{ field(class_="c-select pull-xs-right")}}
{% if after %} <div><small class="text-muted">{{ after }}</small></div>{% endif %}
{% if field.errors %}
{% for error in field.errors%}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
{% endif %}
{{ field }}
</div>
</td>
{% if after %} <td>{{ after }}</td>{% endif %}
{% if field.errors %}{% for error in field.errors
%}<td class="error">{{ error }}</td>{% endfor %}{% endif %}
</tr>
</div>
{% endmacro %}

{% macro render_radio_field_in_row(field, usernamemap=None, after="") %}
<div class="list-group-item {% if field.errors %}has-danger list-group-item-danger{% endif %}">
{{ field(class_="pull-xs-right")}}
{% if after %} <div><small class="text-muted">{{ after }}</small></div>{% endif %}
{% if field.errors %}
{% for error in field.errors%}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
{% endmacro %}

{% macro render_election_form(form, submit_text="") %}
<form action="" method="post">
<fieldset>
{{ render_bootstrap_textfield_in_row(form.alias) }}
{{ render_bootstrap_textfield_in_row(form.shortdesc) }}
{{ render_bootstrap_textfield_in_row(form.description) }}
{{ render_bootstrap_selectfield_in_row(form.voting_type, fieldclass="c-select") }}
{{ render_bootstrap_textfield_in_row(form.max_votes) }}
{{ render_bootstrap_textfield_in_row(form.url) }}
{{ render_bootstrap_textfield_in_row(form.start_date, addon=" at 00:00:00 UTC") }}
{{ render_bootstrap_textfield_in_row(form.end_date, addon=" at 23:59:59 UTC") }}
{{ render_bootstrap_textfield_in_row(form.seats_elected) }}
{{ render_bootstrap_checkbox_in_row(form.candidates_are_fasusers) }}
{{ render_bootstrap_checkbox_in_row(form.embargoed) }}
{{ render_bootstrap_textfield_in_row(form.lgl_voters, after="FAS groups allowed to vote on this election (CLA-done is always required)") }}
{{ render_bootstrap_textfield_in_row(form.admin_grp, after="FAS groups allowed to view the result despite the embargo") }}
</fieldset>

<br class="clear">
<p class="buttons">
<input type="submit" class="btn btn-primary btn-block" value="{{submit_text}}">
</p>
{{ form.csrf_token }}
</form>
{% endmacro %}