From 95e6a56f811a9f9f46e29daac0c67cab51b77d9a Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Thu, 7 Dec 2017 15:03:11 +1030 Subject: [PATCH] Basic administrator view --- eos/base/election.py | 11 +++++- eos/base/workflow.py | 7 +++- eos/psr/workflow.py | 2 + eosweb/core/main.py | 37 ++++++++++++------- eosweb/core/templates/base.html | 2 +- .../core/templates/election/admin/admin.html | 31 ++++++++++++++++ eosweb/core/templates/election/base.html | 3 ++ .../election/{ => view}/ballots.html | 0 .../templates/election/{ => view}/booth.html | 0 .../election/{ => view}/questions.html | 0 .../election/{ => view}/trustees.html | 0 .../templates/election/{ => view}/view.html | 0 local_settings.example.py | 5 +++ 13 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 eosweb/core/templates/election/admin/admin.html rename eosweb/core/templates/election/{ => view}/ballots.html (100%) rename eosweb/core/templates/election/{ => view}/booth.html (100%) rename eosweb/core/templates/election/{ => view}/questions.html (100%) rename eosweb/core/templates/election/{ => view}/trustees.html (100%) rename eosweb/core/templates/election/{ => view}/view.html (100%) diff --git a/eos/base/election.py b/eos/base/election.py index 2997b71..b4c750a 100644 --- a/eos/base/election.py +++ b/eos/base/election.py @@ -54,7 +54,16 @@ class Voter(EmbeddedObject): votes = EmbeddedObjectListField() class User(EmbeddedObject): - pass + admins = [] + + def matched_by(self, other): + return self == other + + def is_admin(self): + for admin in User.admins: + if admin.matched_by(self): + return True + return False def generate_password(): if is_python: diff --git a/eos/base/workflow.py b/eos/base/workflow.py index 46280d4..e39a9b4 100644 --- a/eos/base/workflow.py +++ b/eos/base/workflow.py @@ -117,17 +117,21 @@ class Workflow(EmbeddedObject): # ============== class TaskConfigureElection(WorkflowTask): + label = 'Configure the election and freeze the election' + #def on_enter(self): # self.status = WorkflowTask.Status.COMPLETE - pass class TaskOpenVoting(WorkflowTask): + label = 'Open voting' depends_on = ['eos.base.workflow.TaskConfigureElection'] class TaskCloseVoting(WorkflowTask): + label = 'Close voting' depends_on = ['eos.base.workflow.TaskOpenVoting'] class TaskDecryptVotes(WorkflowTask): + label = 'Decrypt the votes' depends_on = ['eos.base.workflow.TaskCloseVoting'] def on_enter(self): @@ -148,6 +152,7 @@ class TaskDecryptVotes(WorkflowTask): self.exit() class TaskReleaseResults(WorkflowTask): + label = 'Release the results' depends_on = ['eos.base.workflow.TaskDecryptVotes'] # Concrete workflows diff --git a/eos/psr/workflow.py b/eos/psr/workflow.py index 20fd2e3..52d67b0 100644 --- a/eos/psr/workflow.py +++ b/eos/psr/workflow.py @@ -22,6 +22,7 @@ import eos.base.workflow # ============== class TaskMixVotes(WorkflowTask): + label = 'Mix the votes' depends_on = ['eos.base.workflow.TaskCloseVoting'] def on_enter(self): @@ -40,6 +41,7 @@ class TaskMixVotes(WorkflowTask): self.exit() class TaskProveMixes(WorkflowTask): + label = 'Prove the mixes' depends_on = ['eos.psr.workflow.TaskMixVotes'] def on_enter(self): diff --git a/eosweb/core/main.py b/eosweb/core/main.py index 46cd75e..7e4eb51 100644 --- a/eosweb/core/main.py +++ b/eosweb/core/main.py @@ -33,6 +33,7 @@ import functools import importlib import json import os +import subprocess app = flask.Flask(__name__, static_folder=None) @@ -50,6 +51,9 @@ if 'EOSWEB_SETTINGS' in os.environ: # Connect to database db_connect(app.config['DB_NAME'], app.config['DB_URI'], app.config['DB_TYPE']) +# Set configs +User.admins = app.config['ADMINS'] + # Make Flask's serialisation, e.g. for sessions, EosObject aware class EosObjectJSONEncoder(flask.json.JSONEncoder): def default(self, obj): @@ -126,14 +130,6 @@ def setup_test_election(): election.questions.append(question) election.save() - - # Freeze election - election.workflow.get_task('eos.base.workflow.TaskConfigureElection').enter() - - # Open voting - election.workflow.get_task('eos.base.workflow.TaskOpenVoting').enter() - - election.save() @app.cli.command('close_election') @click.option('--electionid', default=None) @@ -194,6 +190,15 @@ def using_election(func): return func(election) return wrapped +def election_admin(func): + @functools.wraps(func) + def wrapped(election): + if 'user' in flask.session and flask.session['user'].is_admin(): + return func(election) + else: + return flask.Response('Administrator credentials required', 403) + return wrapped + @app.route('/election//') @using_election def election_api_json(election): @@ -202,7 +207,7 @@ def election_api_json(election): @app.route('/election//view') @using_election def election_view(election): - return flask.render_template('election/view.html', election=election) + return flask.render_template('election/view/view.html', election=election) @app.route('/election//booth') @using_election @@ -210,22 +215,28 @@ def election_booth(election): selection_model_view_map = EosObject.to_json({key._name: val for key, val in model_view_map.items()}) # ewww auth_methods = EosObject.to_json(app.config['AUTH_METHODS']) - return flask.render_template('election/booth.html', election=election, selection_model_view_map=selection_model_view_map, auth_methods=auth_methods) + return flask.render_template('election/view/booth.html', election=election, selection_model_view_map=selection_model_view_map, auth_methods=auth_methods) @app.route('/election//view/questions') @using_election def election_view_questions(election): - return flask.render_template('election/questions.html', election=election) + return flask.render_template('election/view/questions.html', election=election) @app.route('/election//view/ballots') @using_election def election_view_ballots(election): - return flask.render_template('election/ballots.html', election=election) + return flask.render_template('election/view/ballots.html', election=election) @app.route('/election//view/trustees') @using_election def election_view_trustees(election): - return flask.render_template('election/trustees.html', election=election) + return flask.render_template('election/view/trustees.html', election=election) + +@app.route('/election//admin') +@using_election +@election_admin +def election_admin_summary(election): + return flask.render_template('election/admin/admin.html', election=election) @app.route('/election//cast_ballot', methods=['POST']) @using_election diff --git a/eosweb/core/templates/base.html b/eosweb/core/templates/base.html index 65a47ac..4767ca6 100644 --- a/eosweb/core/templates/base.html +++ b/eosweb/core/templates/base.html @@ -29,7 +29,7 @@ Source Code {% if session.user %}