Add voter information page
This commit is contained in:
parent
f086f97b2d
commit
4b5177e16b
@ -44,6 +44,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import pytz
|
import pytz
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import uuid
|
||||||
|
|
||||||
app = flask.Flask(__name__, static_folder=None)
|
app = flask.Flask(__name__, static_folder=None)
|
||||||
|
|
||||||
@ -244,6 +245,13 @@ def election_view_questions(election):
|
|||||||
def election_view_ballots(election):
|
def election_view_ballots(election):
|
||||||
return flask.render_template('election/view/ballots.html', election=election)
|
return flask.render_template('election/view/ballots.html', election=election)
|
||||||
|
|
||||||
|
@app.route('/election/<election_id>/voter/<voter_id>')
|
||||||
|
@using_election
|
||||||
|
def election_voter_view(election, voter_id):
|
||||||
|
voter_id = uuid.UUID(voter_id)
|
||||||
|
voter = next(voter for voter in election.voters if voter._id == voter_id)
|
||||||
|
return flask.render_template('election/voter/view.html', election=election, voter=voter)
|
||||||
|
|
||||||
@app.route('/election/<election_id>/view/trustees')
|
@app.route('/election/<election_id>/view/trustees')
|
||||||
@using_election
|
@using_election
|
||||||
def election_view_trustees(election):
|
def election_view_trustees(election):
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
.monoout {
|
.monoout {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
||||||
padding: .78571429em 1em;
|
padding: .78571429em 1em;
|
||||||
@ -60,6 +61,11 @@ time[title] {
|
|||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fix nested selectable tables */
|
||||||
|
.ui.table.selectable tr > td.selectable:hover {
|
||||||
|
background: initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
body, html {
|
body, html {
|
||||||
/* Default height: 100% causes blank pages */
|
/* Default height: 100% causes blank pages */
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui main text container" id="main_container">
|
<div class="ui main text container" id="main_container" {% block mainContainerOpts %}{% endblock %}>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block electioncontent %}
|
{% block electioncontent %}
|
||||||
<table class="ui celled table">
|
<table class="ui selectable celled table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Voter</th>
|
<th>Voter</th>
|
||||||
@ -29,13 +29,15 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for voter in election.voters %}
|
{% for voter in election.voters %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ voter.name }}</td>
|
<td class="selectable"><a href="{{ url_for('election_voter_view', election_id=election._id, voter_id=voter._id) }}">{{ voter.name }}</a></td>
|
||||||
{% set votes = voter.votes.get_all() %}
|
{% set votes = voter.votes.get_all() %}
|
||||||
{% if votes|length > 0 %}
|
<td class="selectable"><a href="{{ url_for('election_voter_view', election_id=election._id, voter_id=voter._id) }}">
|
||||||
<td class="hash">{{ SHA256().update_obj(votes[-1].ballot).hash_as_b64(True) }}</td>
|
{% if votes|length > 0 %}
|
||||||
{% else %}
|
<span class="hash">{{ SHA256().update_obj(votes[-1].ballot).hash_as_b64(True) }}</span>
|
||||||
<td class="hash"></td>
|
{% else %}
|
||||||
{% endif %}
|
|
||||||
|
{% endif %}
|
||||||
|
</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
82
eosweb/core/templates/election/voter/view.html
Normal file
82
eosweb/core/templates/election/voter/view.html
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{#
|
||||||
|
Eos - Verifiable elections
|
||||||
|
Copyright © 2017-18 RunasSudo (Yingtong Li)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
|
||||||
|
{# Big tables on this page #}
|
||||||
|
{% block mainContainerOpts %}style="max-width: 100% !important;"{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}{{ voter.name }} – {{ election.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ election.name }}</h1>
|
||||||
|
|
||||||
|
<p><small><b>{{ election.kind|title }} fingerprint:</b> <span class="hash">{{ SHA256().update_obj(election).hash_as_b64() }}</span></small></p>
|
||||||
|
|
||||||
|
<h2>{{ voter.name }}</h2>
|
||||||
|
|
||||||
|
<h3>Votes cast</h3>
|
||||||
|
|
||||||
|
<table class="ui celled table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="two wide column">Cast at</th>
|
||||||
|
<th class="three wide column">Comment</th>
|
||||||
|
{% if session.user and session.user.is_admin() %}
|
||||||
|
<th class="three wide column">Client</th>
|
||||||
|
<th class="eight wide column">Ballot fingerprint (<i class="dropdown icon" style="margin: 0;"></i>Content/Actions )</th>
|
||||||
|
{% else %}
|
||||||
|
<th class="eleven wide column">Ballot fingerprint (<i class="dropdown icon" style="margin: 0;"></i>Content )</th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for vote in voter.votes.get_all() %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ vote.cast_at|pretty_date }}</td>
|
||||||
|
<td>{% if vote.comment %}{{ vote.comment }}{% endif %}</td>
|
||||||
|
{% if session.user and session.user.is_admin() %}
|
||||||
|
<td>
|
||||||
|
{% if vote.cast_ip %}{{ vote.cast_ip }}{% if vote.cast_fingerprint %}<br>{% endif %}{% endif %}
|
||||||
|
{% if vote.cast_fingerprint %}<span class="hash">{{ eos.core.hashing.SHA256().update_text(eos.core.objects.EosObject.to_json(vote.cast_fingerprint)).hash_as_b64(True) }}</span>{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
<td>
|
||||||
|
<div class="ui accordion">
|
||||||
|
<div class="title">
|
||||||
|
<i class="dropdown icon"></i>
|
||||||
|
<span class="hash">{{ eos.core.hashing.SHA256().update_obj(vote).hash_as_b64(True) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="monoout" style="max-height: 10em;">{% if session.user and session.user.is_admin() %}{{ eos.core.objects.EosObject.to_json(eos.core.objects.EosObject.serialise_and_wrap(vote)) }}{% else %}{{ eos.core.objects.EosObject.to_json(eos.core.objects.EosObject.serialise_and_wrap(vote, options=eos.core.objects.SerialiseOptions(should_protect=True))) }}{% endif %}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block basecontent %}
|
||||||
|
{{ super() }}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$('.ui.accordion').accordion();
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user