Implement batch operations on elections #11
This commit is contained in:
parent
fd6f6bc4b1
commit
1bb0197b46
@ -1,5 +1,5 @@
|
|||||||
# Eos - Verifiable elections
|
# Eos - Verifiable elections
|
||||||
# Copyright © 2017-18 RunasSudo (Yingtong Li)
|
# Copyright © 2017-2019 RunasSudo (Yingtong Li)
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -120,50 +120,6 @@ def run_tests(prefix, lang):
|
|||||||
def sessdb():
|
def sessdb():
|
||||||
app.session_interface.db.create_all()
|
app.session_interface.db.create_all()
|
||||||
|
|
||||||
# TODO: Will remove this once we have a web UI
|
|
||||||
@app.cli.command('drop_db_and_setup')
|
|
||||||
def setup_test_election():
|
|
||||||
# DANGER!
|
|
||||||
dbinfo.provider.reset_db()
|
|
||||||
|
|
||||||
# Set up election
|
|
||||||
election = PSRElection()
|
|
||||||
election.workflow = PSRWorkflow()
|
|
||||||
|
|
||||||
# Set election details
|
|
||||||
election.name = 'Test Election'
|
|
||||||
|
|
||||||
from eos.redditauth.election import RedditUser
|
|
||||||
election.voters.append(UserVoter(user=EmailUser(name='Alice', email='alice@localhost')))
|
|
||||||
election.voters.append(UserVoter(user=EmailUser(name='Bob', email='bob@localhost')))
|
|
||||||
election.voters.append(UserVoter(user=EmailUser(name='Carol', email='carol@localhost')))
|
|
||||||
election.voters.append(UserVoter(user=RedditUser(username='RunasSudo')))
|
|
||||||
|
|
||||||
for voter in election.voters:
|
|
||||||
if isinstance(voter, UserVoter):
|
|
||||||
if isinstance(voter.user, EmailUser):
|
|
||||||
emails.voter_email_password(election, voter)
|
|
||||||
|
|
||||||
election.mixing_trustees.append(InternalMixingTrustee(name='Eos Voting'))
|
|
||||||
election.mixing_trustees.append(InternalMixingTrustee(name='Eos Voting'))
|
|
||||||
|
|
||||||
election.sk = EGPrivateKey.generate()
|
|
||||||
election.public_key = election.sk.public_key
|
|
||||||
|
|
||||||
question = PreferentialQuestion(prompt='President', choices=[
|
|
||||||
Ticket(name='ACME Party', choices=[
|
|
||||||
Choice(name='John Smith'),
|
|
||||||
Choice(name='Joe Bloggs', party='Independent ACME')
|
|
||||||
]),
|
|
||||||
Choice(name='John Q. Public')
|
|
||||||
], min_choices=0, max_choices=3, randomise_choices=True)
|
|
||||||
election.questions.append(question)
|
|
||||||
|
|
||||||
question = ApprovalQuestion(prompt='Chairman', choices=[Choice(name='John Doe'), Choice(name='Andrew Citizen')], min_choices=0, max_choices=1)
|
|
||||||
election.questions.append(question)
|
|
||||||
|
|
||||||
election.save()
|
|
||||||
|
|
||||||
@app.cli.command('verify_election')
|
@app.cli.command('verify_election')
|
||||||
@click.option('--electionid', default=None)
|
@click.option('--electionid', default=None)
|
||||||
def verify_election(electionid):
|
def verify_election(electionid):
|
||||||
@ -227,6 +183,22 @@ def tick_scheduler():
|
|||||||
|
|
||||||
# === Views ===
|
# === Views ===
|
||||||
|
|
||||||
|
def using_election(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapped(election_id, **kwargs):
|
||||||
|
election = Election.get_by_id(election_id)
|
||||||
|
return func(election, **kwargs)
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
def election_admin(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
if 'user' in flask.session and flask.session['user'].is_admin():
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
return flask.Response('Administrator credentials required', 403)
|
||||||
|
return wrapped
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
elections = Election.get_all()
|
elections = Election.get_all()
|
||||||
@ -250,21 +222,34 @@ def elections():
|
|||||||
|
|
||||||
return flask.render_template('elections.html', elections=elections)
|
return flask.render_template('elections.html', elections=elections)
|
||||||
|
|
||||||
def using_election(func):
|
@app.route('/elections/batch', methods=['GET', 'POST'])
|
||||||
@functools.wraps(func)
|
@election_admin
|
||||||
def wrapped(election_id, **kwargs):
|
def elections_batch():
|
||||||
|
if flask.request.method == 'POST':
|
||||||
|
# Execute
|
||||||
|
for k, v in flask.request.form.items():
|
||||||
|
if k.startswith('election_') and v:
|
||||||
|
election_id = k[9:]
|
||||||
election = Election.get_by_id(election_id)
|
election = Election.get_by_id(election_id)
|
||||||
return func(election, **kwargs)
|
for workflow_task in election.workflow.tasks:
|
||||||
return wrapped
|
if workflow_task.status == eos.base.workflow.WorkflowTaskStatus.READY:
|
||||||
|
task = WorkflowTaskEntryWebTask(
|
||||||
|
election_id=election._id,
|
||||||
|
workflow_task=workflow_task._name,
|
||||||
|
status=TaskStatus.READY,
|
||||||
|
run_strategy=EosObject.lookup(app.config['TASK_RUN_STRATEGY'])()
|
||||||
|
)
|
||||||
|
task.run()
|
||||||
|
break
|
||||||
|
|
||||||
def election_admin(func):
|
elections = []
|
||||||
@functools.wraps(func)
|
for election in Election.get_all():
|
||||||
def wrapped(*args, **kwargs):
|
if any(workflow_task.status == eos.base.workflow.WorkflowTaskStatus.READY for workflow_task in election.workflow.tasks):
|
||||||
if 'user' in flask.session and flask.session['user'].is_admin():
|
elections.append(election)
|
||||||
return func(*args, **kwargs)
|
|
||||||
else:
|
elections.sort(key=lambda e: e.name)
|
||||||
return flask.Response('Administrator credentials required', 403)
|
|
||||||
return wrapped
|
return flask.render_template('elections_batch.html', elections=elections)
|
||||||
|
|
||||||
@app.route('/election/<election_id>/')
|
@app.route('/election/<election_id>/')
|
||||||
@using_election
|
@using_election
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{#
|
{#
|
||||||
Eos - Verifiable elections
|
Eos - Verifiable elections
|
||||||
Copyright © 2017-18 RunasSudo (Yingtong Li)
|
Copyright © 2017-2019 RunasSudo (Yingtong Li)
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -23,6 +23,10 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>All elections: Eos Voting for {{ eosweb.app.config['ORG_NAME'] }}</h1>
|
<h1>All elections: Eos Voting for {{ eosweb.app.config['ORG_NAME'] }}</h1>
|
||||||
|
|
||||||
|
{% if session.user and session.user.is_admin() %}
|
||||||
|
<div style="text-align: right; font-size: small;"><a href="{{ url_for('elections_batch') }}">Batch operations</a></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<p>Please choose an election from the list below:</p>
|
<p>Please choose an election from the list below:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
56
eosweb/core/templates/elections_batch.html
Normal file
56
eosweb/core/templates/elections_batch.html
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{#
|
||||||
|
Eos - Verifiable elections
|
||||||
|
Copyright © 2017-2019 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/>.
|
||||||
|
#}
|
||||||
|
|
||||||
|
{% block title %}Perform batch operations{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Perform batch operations</h1>
|
||||||
|
|
||||||
|
<form method="POST">
|
||||||
|
<table class="ui selectable celled table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Next stage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for election in elections %}
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" name="election_{{ election._id }}" id="election_{{ election._id }}"></td>
|
||||||
|
<td>{{ election.name }}</td>
|
||||||
|
<td>
|
||||||
|
<ul style="padding-left: 1em; margin: 0;">
|
||||||
|
{% for task in election.workflow.tasks %}
|
||||||
|
{% if task.status == eos.base.workflow.WorkflowTaskStatus.READY %}
|
||||||
|
<li>{{ task.label }}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<input class="ui primary button" type="submit" value="Execute">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user