From 99ee0407525ab98e56479f183af573c3a3451a69 Mon Sep 17 00:00:00 2001 From: Philipp Dunkel Date: Thu, 21 May 2009 11:20:15 +0000 Subject: [PATCH] Voting Tool git-svn-id: http://svn.cacert.cl/Software/Voting/vote@34 d4452222-2f33-11de-9270-010000000000 --- database.php | 82 ++++++++++++++++++++ denied.php | 12 +++ index.php | 5 ++ motion.php | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++ motions.php | 83 ++++++++++++++++++++ proxy.php | 157 ++++++++++++++++++++++++++++++++++++++ styles.css | 28 +++++++ vote.php | 107 ++++++++++++++++++++++++++ 8 files changed, 685 insertions(+) create mode 100644 database.php create mode 100644 denied.php create mode 100644 index.php create mode 100644 motion.php create mode 100644 motions.php create mode 100644 proxy.php create mode 100644 styles.css create mode 100644 vote.php diff --git a/database.php b/database.php new file mode 100644 index 0000000..be20eb0 --- /dev/null +++ b/database.php @@ -0,0 +1,82 @@ +dbh = new PDO("sqlite:".dirname(__FILE__)."/database.sqlite"); + $this->statement = array(); + $this->statement['list decisions'] = $this->dbh->prepare("SELECT decisions.id, decisions.tag, voters.name AS proposer, decisions.proposed, decisions.title, decisions.content, decisions.quorum, decisions.majority, decisions.status, decisions.due, decisions.modified, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=1) AS ayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=-1) AS nayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=0) AS abstains FROM decisions, voters WHERE decisions.proponent=voters.id ORDER BY proposed DESC LIMIT 10 OFFSET 10 * (:page - 1);"); + $this->statement['closed decisions'] = $this->dbh->prepare("SELECT decisions.id, decisions.tag, voters.name AS proposer, decisions.proposed, decisions.title, decisions.content, decisions.quorum, decisions.majority, decisions.status, decisions.due, decisions.modified, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=1) AS ayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=-1) AS nayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=0) AS abstains FROM decisions, voters WHERE decisions.proponent=voters.id AND decisions.status=0 AND datetime('now','utc') > datetime(due);"); + $this->statement['get decision'] = $this->dbh->prepare("SELECT decisions.id, decisions.tag, decisions.proponent, voters.name AS proposer, decisions.proposed, decisions.title, decisions.content, decisions.quorum, decisions.majority, decisions.status, decisions.due, decisions.modified, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=1) AS ayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=-1) AS nayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=0) AS abstains FROM decisions, voters WHERE decisions.proponent=voters.id AND decisions.id=:decision;"); + $this->statement['get new decision'] = $this->dbh->prepare("SELECT decisions.id, decisions.tag, decisions.proponent, voters.name AS proposer, decisions.proposed, decisions.title, decisions.content, decisions.quorum, decisions.majority, decisions.status, decisions.due, decisions.modified, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=1) AS ayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=-1) AS nayes, (SELECT COUNT(*) FROM votes WHERE decision=decisions.id AND vote=0) AS abstains FROM decisions, voters WHERE decisions.proponent=voters.id AND decisions.id=last_insert_rowid();"); + $this->statement['get voter'] = $this->dbh->prepare("SELECT voters.id, voters.name FROM voters, emails WHERE voters.id=emails.voter AND emails.address=? AND voters.enabled=1"); + $this->statement['get voter by id'] = $this->dbh->prepare("SELECT voters.id, voters.name FROM voters WHERE id=:id;"); + $this->statement['get voters'] = $this->dbh->prepare("SELECT voters.id, voters.name FROM voters WHERE voters.enabled=1 ORDER BY name ASC;"); + $this->statement['del vote'] = $this->dbh->prepare("DELETE FROM votes WHERE decision=:decision AND voter=:voter;"); + $this->statement['do vote'] = $this->dbh->prepare("INSERT INTO votes (decision, voter, vote, voted, notes) VALUES (:decision, :voter, :vote, datetime('now','utc'), :notes);"); + $this->statement['stats'] = $this->dbh->prepare("SELECT (SELECT COUNT(*) FROM voters WHERE enabled=1) AS voters;"); + $this->statement['create decision'] = $this->dbh->prepare("INSERT INTO decisions (proposed, proponent, title, content, quorum, majority, status, due, modified) VALUES (datetime('now','utc'), :proponent, :title, :content, :quorum, :majority, 0, datetime('now','utc', :due), datetime('now','utc'));"); + $this->statement['post create'] = $this->dbh->prepare(" UPDATE decisions SET tag='m' || strftime('%Y%m%d','now') || '.' || id WHERE id=last_insert_rowid();"); + $this->statement['update decision'] = $this->dbh->prepare("UPDATE decisions SET proposed=datetime('now','utc'), proponent=:proponent, title=:title, content=:content, quorum=:quorum, majority=:majority, status=0, due=datetime('now','utc',:due), modified=datetime('now','utc') WHERE id=:id;"); + $this->statement['close decision'] = $this->dbh->prepare("UPDATE decisions SET status=:status, modified=datetime('now','utc') WHERE id=:decision"); + } + function getStatement($name) { + return $this->statement[$name]; + } + function closeVotes() { + $stmt = $this->getStatement("closed decisions"); + $upd = $this->getStatement("close decision"); + if ($stmt->execute()) { + while ($decision = $stmt->fetch()) { + $votes = $decision['ayes'] + $decision['nayes'] + $decision['abstains']; + if ($votes < $decision['quorum']) { + $decision['status'] = -1; + } else { + $votes = $decision['ayes'] + $decision['nayes']; + if (($decision['ayes'] / $votes) >= ($decision['majority'] / 100)) { + $decision['status'] = 1; + } else { + $decision['status'] = -1; + } + } + $upd->bindParam(":decision",$decision['id']); + $upd->bindParam(":status",$decision['status']); + $upd->execute(); + $state = $decision['status']==1?"accepted":"declined"; + $tag = $decision['tag']; + $title = $decision['title']; + $content = $decision['content']; + $quorum = $decision['quorum']; + $majority = $decision['majority']; + $ayes = $decision['ayes']; + $nayes = $decision['nayes']; + $abstains = $decision['abstains']; + $percent = $decision['ayes'] * 100 / $decision['ayes']+$decision['nayes']; + $body = << \ No newline at end of file diff --git a/denied.php b/denied.php new file mode 100644 index 0000000..9bb72d6 --- /dev/null +++ b/denied.php @@ -0,0 +1,12 @@ + + + CAcert Board Decisions + + + + + You are not authorized to act here!
+ If you think this is in error, please contact the administrator + If you don't know who that is, it is definitely not an error ;) + + \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..3363496 --- /dev/null +++ b/index.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/motion.php b/motion.php new file mode 100644 index 0000000..515e25c --- /dev/null +++ b/motion.php @@ -0,0 +1,211 @@ +getStatement("get voter"); + $stmt->execute(array($user)); + if (!($user = $stmt->fetch())) { + header("HTTP/1.0 302 Redirect"); + header("Location: denied.php"); + exit(); + } + $db->getStatement("stats")->execute(); + $stats = $db->getStatement("stats")->fetch(); + function htmlesc($string) { + $string = preg_replace('/&/',"&",$string); + $string = preg_replace('//',">",$string); + echo $string; + } +?> + + + CAcert Board Decisions + + + + + getStatement("update decision"); + $stmt->bindParam(":id",$_POST['motion']); + $stmt->bindParam(":proponent",$_POST['proponent']); + $stmt->bindParam(":title",$_POST['title']); + $stmt->bindParam(":content",$_POST['content']); + $stmt->bindParam(":quorum",$_POST['quorum']); + $stmt->bindParam(":majority",$_POST['majority']); + $stmt->bindParam(":due",$_POST['due']); + if ($stmt->execute()) { + ?> + The motion has been proposed!
+ Back to motions
+
+
+ getStatement("get decision")->execute(array($_POST['motion']))?$db->getStatement("get decision")->fetch():array(); + $name = $user['name']; + $tag = $decision['tag']; + $title = $decision['title']; + $content =$decision['content']; + $due = $decision['due']." UTC"; + $quorum = $decision['quorum']; + $majority = $decision['majority']; + $voteurl = "https://".$_SERVER['HTTP_HOST'].":".$_SERVER['SERVER_PORT'].preg_replace('/motion\.php/','vote.php',$_SERVER['REQUEST_URI'])."?motion=".$decision['id']; + $body = << + The motion has NOT been proposed!
+ Back to motions
+ \n",$stmt->errorInfo()); ?>
+
+
+ getStatement("create decision"); + $stmt->bindParam(":proponent",$_POST['proponent']); + $stmt->bindParam(":title",$_POST['title']); + $stmt->bindParam(":content",$_POST['content']); + $stmt->bindParam(":quorum",$_POST['quorum']); + $stmt->bindParam(":majority",$_POST['majority']); + $stmt->bindParam(":due",$_POST['due']); + if ($stmt->execute()) { + $db->getStatement("post create")->execute(); + ?> + The motion has been proposed!
+ Back to motions
+
+
+ getStatement("get new decision")->execute()?$db->getStatement("get new decision")->fetch():array(); + $name = $user['name']; + $tag = $decision['tag']; + $title = $decision['title']; + $content =$decision['content']; + $due = $decision['due']." UTC"; + $quorum = $decision['quorum']; + $majority = $decision['majority']; + $voteurl = "https://".$_SERVER['HTTP_HOST'].":".$_SERVER['SERVER_PORT'].preg_replace('/motion\.php/','vote.php',$_SERVER['REQUEST_URI'])."?motion=".$decision['id']; + $body = << + The motion has NOT been proposed!
+ Back to motions
+ \n",$stmt->errorInfo()); ?>
+
+
+ getStatement("get decision"); + if ($stmt->execute(array($_REQUEST['motion']))) { + $motion = $stmt->fetch(); + } + if (!is_numeric($motion['id'])) { + $motion = array(); + foreach (array("title","content","quorum","majority") as $column) { + $motion[$column] = ""; + } + $motion["proponent"] = $user['id']; + $motion["proposer"] = $user['name']; + } + } else { + $motion = array(); + foreach (array("title","content","quorum","majority") as $column) { + $motion[$column] = ""; + } + $motion["proponent"] = $user['id']; + $motion["proposer"] = $user['name']; + } + ?> +
method="POST"> + + " /> + + + + + + + + + + + +
ID:
Proponent:
Proposed: UTC
Title:
Text:
Quorum:
Majority:
Due: UTC
 
+
+
+ Back to motions + + diff --git a/motions.php b/motions.php new file mode 100644 index 0000000..27d1632 --- /dev/null +++ b/motions.php @@ -0,0 +1,83 @@ +closeVotes(); + $page = is_numeric($_REQUEST['page'])?$_REQUEST['page']:1; +?> + + + CAcert Board Decisions + + + + + + + + + + + getStatement("list decisions"); + $stmt->execute(array($page)); + $items = 0; + while ($row = $stmt->fetch()) { + $items++; + ?> + + + + + + + +
StatusMotionActions
"> + ".$row['due']." UTC"; break; + case 1: echo "Approved
".$row['modified']." UTC"; break; + case -1: echo "Declined
".$row['modified']." UTC"; break; + } + ?> +
+
+
+
+
+ Due: UTC
+ Proposed: ( UTC)
+ Required Votes:
+ Majority: %
+ Aye|Naye|Abstain: ||
+
+ + + +   + +
+ +
+ + diff --git a/proxy.php b/proxy.php new file mode 100644 index 0000000..77bcc89 --- /dev/null +++ b/proxy.php @@ -0,0 +1,157 @@ +getStatement("get voter"); + $stmt->execute(array($user)); + if (!($user = $stmt->fetch())) { + header("HTTP/1.0 302 Redirect"); + header("Location: denied.php"); + exit(); + } +?> + + + CAcert Board Decisions + + + + + + This is not a valid motion!
+ Back to motions
+getStatement("get decision"); + $stmt->bindParam(":decision",$_REQUEST['motion']); + if ($stmt->execute() && ($decision=$stmt->fetch()) && ($decision['status'] == 0)) { + if (is_numeric($_POST['voter']) && is_numeric($_POST['vote']) && is_numeric($_REQUEST['motion']) && ($_POST['justification'] != "")) { + $stmt = $db->getStatement("del vote"); + $stmt->bindParam(":voter",$_REQUEST['voter']); + $stmt->bindParam(":decision",$_REQUEST['motion']); + if ($stmt->execute()) { + $stmt = $db->getStatement("do vote"); + $stmt->bindParam(":voter",$_REQUEST['voter']); + $stmt->bindParam(":decision",$_REQUEST['motion']); + $stmt->bindParam(":vote",$_REQUEST['vote']); + $notes = "Proxy-Vote by ".$user['name']."\n\n".$_REQUEST['justification']."\n\n".$_SERVER['SSL_CLIENT_CERT']; + $stmt->bindParam(":notes",$notes); + if ($stmt->execute()) { + ?> + The vote has been registered.
+ Back to motions + getStatement("get voter by id"); + $stmt->bindParam(":id",$_REQUEST['voter']); + if ($stmt->execute() && ($voter=$stmt->fetch())) { + $voter = $voter['name']; + } else { + $voter = "Voter: ".$_REQUEST['voter']; + } + $name = $user['name']; + $justification = $_REQUEST['justification']; + $vote = ''; + switch($_REQUEST['vote']) { + case 1 : $vote='Aye'; break; + case -1: $vote='Naye'; break; + default: $vote='Abstain'; break; + } + $tag = $decision['tag']; + $title = $decision['title']; + $content = $decision['content']; + $due = $decision['due']." UTC"; + $body = << + The vote has NOT been registered.
+ Back to motions + \n",$stmt->errorInfo()); ?> + + The vote has NOT been registered.
+ Back to motions + \n",$stmt->errorInfo()); ?> + getStatement("get voters"); + if ($stmt->execute() && ($voters = $stmt->fetchAll())) { +?> +
+ + + + + + + + + + + + + + + + + +
VoterVote
Justification:
+
+ + Could not retrieve voters!
+ Back to motions
+ \n",$stmt->errorInfo()); ?> + + + + This is not a valid motion!
+ Back to motions
+ \n",$stmt->errorInfo()); ?> + + + diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..0610148 --- /dev/null +++ b/styles.css @@ -0,0 +1,28 @@ +html, body, th, td { + font-family: Verdana, Arial, Sans-Serif; + font-size:10px; +} +table, tr, td, th { + vertical-align:top; + border:1px solid black; + border-collapse: collapse; +} +td.navigation { + text-align:center; +} +td.approved { + color:green; +} +td.declined { + color:red; +} +td.pending { + color:blue; +} +textarea { + width:400px; + height:150px; +} +input { + width:400px; +} diff --git a/vote.php b/vote.php new file mode 100644 index 0000000..b357cf1 --- /dev/null +++ b/vote.php @@ -0,0 +1,107 @@ +getStatement("get voter"); + $stmt->execute(array($user)); + if (!($user = $stmt->fetch())) { + header("HTTP/1.0 302 Redirect"); + header("Location: denied.php"); + exit(); + } +?> + + + CAcert Board Decisions + + + + + getStatement("get decision"); + $stmt->bindParam(":decision",$_REQUEST['motion']); + if ($stmt->execute() && ($decision=$stmt->fetch())) { + if ($decision['status'] == 0) { + $stmt = $db->getStatement("del vote"); + $stmt->bindParam(":voter",$user['id']); + $stmt->bindParam(":decision",$_REQUEST['motion']); + if ($stmt->execute()) { + $stmt = $db->getStatement("do vote"); + $stmt->bindParam(":voter",$user['id']); + $stmt->bindParam(":decision",$_REQUEST['motion']); + $stmt->bindParam(":vote",$_REQUEST['vote']); + $notes="Direct Vote\n\n".$_SERVER['SSL_CLIENT_CERT']; + $stmt->bindParam(":notes",$notes); + if ($stmt->execute()) { + ?> + Your vote has been registered.
+ Back to motions + + Your vote has NOT been registered.
+ Back to motions + \n",$stmt->errorInfo()); ?> + + Your vote has NOT been registered.
+ Back to motions + \n",$stmt->errorInfo()); ?> + + Your vote has NOT been registered.
+ Voting is alread closed!
+ Back to motions + + Your vote has NOT been registered.
+ Could not find the motion to be voted!
+ Back to motions + + This call is not a valid vote!
+ Back to motions + + + \ No newline at end of file