summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Dunkel <Philipp Dunkel@d4452222-2f33-11de-9270-010000000000>2009-05-21 11:20:15 +0000
committerPhilipp Dunkel <Philipp Dunkel@d4452222-2f33-11de-9270-010000000000>2009-05-21 11:20:15 +0000
commit99ee0407525ab98e56479f183af573c3a3451a69 (patch)
treede4748eefcb13504c4c5e6d9cc29bdce17a7cbd4
downloadcacert-boardvoting-99ee0407525ab98e56479f183af573c3a3451a69.tar.gz
cacert-boardvoting-99ee0407525ab98e56479f183af573c3a3451a69.tar.xz
cacert-boardvoting-99ee0407525ab98e56479f183af573c3a3451a69.zip
Voting Tool
git-svn-id: http://svn.cacert.cl/Software/Voting/vote@34 d4452222-2f33-11de-9270-010000000000
-rw-r--r--database.php82
-rw-r--r--denied.php12
-rw-r--r--index.php5
-rw-r--r--motion.php211
-rw-r--r--motions.php83
-rw-r--r--proxy.php157
-rw-r--r--styles.css28
-rw-r--r--vote.php107
8 files changed, 685 insertions, 0 deletions
diff --git a/database.php b/database.php
new file mode 100644
index 0000000..be20eb0
--- /dev/null
+++ b/database.php
@@ -0,0 +1,82 @@
+<?php
+ $board = "cacert-board@lists.cacert.org";
+ class DB {
+ function __construct() {
+ $this->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 = <<<BODY
+Dear Board,
+
+The motion with the identifier $tag has been $state.
+
+Motion:
+ $title
+ $content
+
+Votes:
+ Quorum: $quorum
+ Majority: $majority%
+
+ Ayes: $ayes
+ Nayes: $nayes
+ Abstentions: $abstains
+
+ Percentage: $percent%
+
+Kind regards,
+the voting system.
+
+BODY;
+ mail($board,"Re: ".$decision['tag']." - ".$decision['title'],$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 @@
+<html>
+ <head>
+ <title>CAcert Board Decisions</title>
+ <meta http-equiv="Content-Type" content="text/html; charset='UTF-8'" />
+ <link rel="stylesheet" type="text/css" href="styles.css" />
+ </head>
+ <body>
+ <b>You are not authorized to act here!</b><br/>
+ <i>If you think this is in error, please contact the administrator</i>
+ <i>If you don't know who that is, it is definitely not an error ;)</i>
+ </body>
+</html> \ 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 @@
+<?php
+ header("HTTP/1.0 301 Redirect");
+ header("Location: motions.php");
+ exit();
+?> \ 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 @@
+<?php
+ if ($_SERVER['HTTPS'] != 'on') {
+ header("HTTP/1.0 302 Redirect");
+ header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
+ exit();
+ }
+ $user = $_SERVER['REMOTE_USER'];
+ require_once("database.php");
+ $db = new DB();
+ $stmt = $db->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('/&/',"&amp;",$string);
+ $string = preg_replace('/</',"&lt;",$string);
+ $string = preg_replace('/>/',"&gt;",$string);
+ echo $string;
+ }
+?>
+<html>
+ <head>
+ <title>CAcert Board Decisions</title>
+ <meta http-equiv="Content-Type" content="text/html; charset='UTF-8'" />
+ <link rel="stylesheet" type="text/css" href="styles.css" />
+ </head>
+ <body>
+ <?php
+ if ($_REQUEST['action'] == "store") {
+ if (is_numeric($_REQUEST['motion'])) {
+ $stmt = $db->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()) {
+ ?>
+ <b>The motion has been proposed!</b><br/>
+ <a href="motions.php">Back to motions</a><br/>
+ <br/>
+ <br/>
+ <?php
+ $decision = $db->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 = <<<BODY
+Dear Board,
+
+$name has modified motion $tag to the following:
+
+$title
+$content
+
+To pass a minimum of $quorum votes and a $majority% acceptance will be required.
+Voting will close $due.
+
+To vote please choose:
+
+Aye: $voteurl&vote=1
+Naye: $voteurl&vote=-1
+Abstain: $voteurl&vote=0
+
+Please be aware, that if you have voted already your votr is still registered and valid.
+If this modification has an impact on how you wish to vote, you are responsible for voting
+again.
+
+Kind regards,
+the voting system
+BODY;
+ mail($board,"Re: $tag - $title",$body);
+ } else {
+ ?>
+ <b>The motion has NOT been proposed!</b><br/>
+ <a href="motions.php">Back to motions</a><br/>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i><br/>
+ <br/>
+ <br/>
+ <?php
+ }
+ } else {
+ $stmt = $db->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();
+ ?>
+ <b>The motion has been proposed!</b><br/>
+ <a href="motions.php">Back to motions</a><br/>
+ <br/>
+ <br/>
+ <?php
+ $decision = $db->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 = <<<BODY
+Dear Board,
+
+$name has made the following motion:
+
+$title
+$content
+
+To pass a minimum of $quorum votes and a $majority% acceptance will be required.
+Voting will close $due.
+
+To vote please choose:
+
+Aye: $voteurl&vote=1
+Naye: $voteurl&vote=-1
+Abstain: $voteurl&vote=0
+
+Kind regards,
+the voting system
+BODY;
+ mail($board,"$tag - $title",$body);
+ } else {
+ ?>
+ <b>The motion has NOT been proposed!</b><br/>
+ <a href="motions.php">Back to motions</a><br/>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i><br/>
+ <br/>
+ <br/>
+ <?php
+ }
+ }
+
+ }
+ if (is_numeric($_REQUEST['motion'])) {
+ $stmt = $db->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'];
+ }
+ ?>
+ <form <?php if (is_numeric($_REQUEST['motion'])) { echo(" action=\"?\""); } ?> method="POST">
+ <input type="hidden" name="action" value="store" />
+ <?php
+ if (is_numeric($_REQUEST['motion'])) {
+ ?><input type="hidden" name="motion" value="<?php echo($_REQUEST["motion"]); ?>" /><?php
+ }
+ ?>
+ <table>
+ <tr><td>ID:</td><td><?php htmlesc($motion['tag']); ?></td></tr>
+ <tr><td>Proponent:</td><td><?php htmlesc($motion['proposer']); ?><input type="hidden" name="proponent" value="<?php htmlesc($user['id']); ?>"></td></tr>
+ <tr><td>Proposed:</td><td><?php htmlesc($motion['proposed']); ?> UTC</td></tr>
+ <tr><td>Title:</td><td><input name="title" value="<?php htmlesc($motion['title'])?>"></td></tr>
+ <tr><td>Text:</td><td><textarea name="content"><?php htmlesc($motion['content'])?></textarea></td></tr>
+ <tr><td>Quorum:</td><td><select name="quorum">
+ <option value="<?php echo(ceil($stats["voters"])); ?>" <?php if($motion['quorum'] == $stats["voters"]) { echo(" selected=\"selected\""); } ?>>100% Votes (<?php echo($stats["voters"]); ?>)</option>
+ <option value="<?php echo(ceil($stats["voters"] / 2)); ?>" <?php if($motion['quorum'] == ceil($stats["voters"] / 2)) { echo(" selected=\"selected\""); } ?>>50% Votes (<?php echo(ceil($stats["voters"] / 2)); ?>)</option>
+ <option value="2" <?php if($motion['quorum'] == 2) { echo(" selected=\"selected\""); } ?>>2 Votes</option>
+ <option value="1" <?php if($motion['quorum'] == 1) { echo(" selected=\"selected\""); } ?>>1 Vote</option>
+ </select></td></tr>
+ <tr><td>Majority:</td><td><select name="majority">
+ <option value="50" <?php if($motion['majority'] == 50) { echo(" selected=\"selected\""); } ?>>50%</option>
+ <option value="67" <?php if($motion['majority'] == 67) { echo(" selected=\"selected\""); } ?>>67%</option>
+ <option value="75" <?php if($motion['majority'] == 75) { echo(" selected=\"selected\""); } ?>>75%</option>
+ <option value="100" <?php if($motion['majority'] == 100) { echo(" selected=\"selected\""); } ?>>100%</option>
+ </td></tr>
+ <tr><td rowspan="2">Due:</td><td><?php echo($motion['due'])?> UTC</td></tr>
+ <tr><td><select name="due">
+ <option value="+3 days">In 3 Days</option>
+ <option value="+7 days">In 1 Week</option>
+ <option value="+14 days">In 2 Weeks</option>
+ </select></td></tr>
+ <tr><td>&nbsp;</td><td><input type="submit" value="Propose" /></td></tr>
+ </table>
+ </form>
+ <br/>
+ <a href="motions.php">Back to motions</a>
+ </body>
+</html>
diff --git a/motions.php b/motions.php
new file mode 100644
index 0000000..27d1632
--- /dev/null
+++ b/motions.php
@@ -0,0 +1,83 @@
+<?php
+ require_once("database.php");
+ $db = new DB();
+ $db->closeVotes();
+ $page = is_numeric($_REQUEST['page'])?$_REQUEST['page']:1;
+?>
+<html>
+ <head>
+ <title>CAcert Board Decisions</title>
+ <meta http-equiv="Content-Type" content="text/html; charset='UTF-8'" />
+ <link rel="stylesheet" type="text/css" href="styles.css" />
+ </head>
+ <body>
+ <table class="list">
+ <tr>
+ <th>Status</th>
+ <th>Motion</th>
+ <th>Actions</th>
+ </tr>
+ <?php
+ $stmt = $db->getStatement("list decisions");
+ $stmt->execute(array($page));
+ $items = 0;
+ while ($row = $stmt->fetch()) {
+ $items++;
+ ?><tr>
+ <td class="<?php switch($row['status']) { case 0: echo "pending"; break; case 1: echo "approved"; break; case -1: echo "declined"; break; }?>">
+ <?php
+ switch($row['status']) {
+ case 0: echo "Pending<br/><i>".$row['due']." UTC</i>"; break;
+ case 1: echo "Approved<br/><i>".$row['modified']." UTC</i>"; break;
+ case -1: echo "Declined<br/><i>".$row['modified']." UTC</i>"; break;
+ }
+ ?>
+ </td>
+ <td>
+ <i><?php echo $row['tag'] ?></i><br/>
+ <b><?php echo $row['title']; ?></b><br/>
+ <pre><?php echo $row['content']; ?></pre>
+ <br/>
+ <i>Due: <?php echo($row['due']); ?> UTC</i><br/>
+ <i>Proposed: <?php echo($row['proposer']); ?> (<?php echo($row['proposed']); ?> UTC)</i><br/>
+ <i>Required Votes: <?php echo($row['quorum']); ?></i><br/>
+ <i>Majority: <?php echo($row['majority']); ?>%</i><br/>
+ <i>Aye|Naye|Abstain: <?php echo($row['ayes']); ?>|<?php echo($row['nayes']); ?>|<?php echo($row['abstains']); ?></i><br/>
+ </td><?php
+ ?><td class="actions">
+ <?php
+ if ($row['status'] == 0) {
+ ?>
+ <ul>
+ <li><a href="vote.php?motion=<?php echo($row['id']); ?>&amp;vote=1">Aye</a></li>
+ <li><a href="vote.php?motion=<?php echo($row['id']); ?>&amp;vote=0">Abstain</a></li>
+ <li><a href="vote.php?motion=<?php echo($row['id']); ?>&amp;vote=-1">Naye</a></li>
+ <li><a href="proxy.php?motion=<?php echo($row['id']); ?>">Proxy Vote</a></li>
+ <li><a href="motion.php?motion=<?php echo($row['id']); ?>">Modify</a></li>
+ </ul>
+ <?php
+ } else {
+ ?>
+ &nbsp;
+ <?php
+ }
+ ?>
+ </td>
+ </tr><?php
+ }
+ ?>
+ <tr>
+ <td colspan="2" class="navigation">
+ <?php if ($page>1) { ?><a href="?page=<?php echo($page-1); ?>">&lt;</a><?php } else { ?>&nbsp;<?php } ?>
+ &nbsp;
+ <?php if ($items>9) { ?><a href="?page=<?php echo($page+1); ?>">&gt;</a><?php } else { ?>&nbsp;<?php } ?>
+ </td>
+ <td class="actions">
+ <ul>
+ <li><a href="motion.php">New Motion</a></li>
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/proxy.php b/proxy.php
new file mode 100644
index 0000000..77bcc89
--- /dev/null
+++ b/proxy.php
@@ -0,0 +1,157 @@
+<?php
+ if ($_SERVER['HTTPS'] != 'on') {
+ header("HTTP/1.0 302 Redirect");
+ header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
+ exit();
+ }
+ $user = $_SERVER['REMOTE_USER'];
+ require_once("database.php");
+ $db = new DB();
+ $stmt = $db->getStatement("get voter");
+ $stmt->execute(array($user));
+ if (!($user = $stmt->fetch())) {
+ header("HTTP/1.0 302 Redirect");
+ header("Location: denied.php");
+ exit();
+ }
+?>
+<html>
+ <head>
+ <title>CAcert Board Decisions</title>
+ <meta http-equiv="Content-Type" content="text/html; charset='UTF-8'" />
+ <link rel="stylesheet" type="text/css" href="styles.css" />
+ </head>
+ <body>
+<?php
+ if (!is_numeric($_REQUEST['motion'])) {
+?>
+ <b>This is not a valid motion!</b><br/>
+ <a href="motions.php">Back to motions</a><br/>
+<?php
+ } else {
+ $stmt = $db->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()) {
+ ?>
+ <b>The vote has been registered.</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <?php
+ $stmt = $db->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 = <<<BODY
+Dear Board,
+
+$name has just registered a proxy vote of $vote for $voter on motion $tag.
+
+The justification for this was:
+$justification
+
+Motion:
+$title
+$content
+
+Kind regards,
+the vote system
+
+BODY;
+ mail($board,"Re: $tag - $title",$body);
+ } else {
+ ?>
+ <b>The vote has NOT been registered.</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i>
+ <?php
+ }
+ } else {
+ ?>
+ <b>The vote has NOT been registered.</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i>
+ <?php
+ }
+ } else {
+ $stmt = $db->getStatement("get voters");
+ if ($stmt->execute() && ($voters = $stmt->fetchAll())) {
+?>
+ <form method="POST" action="?motion=<?php echo($_REQUEST['motion']); ?>">
+ <table>
+ <tr>
+ <th>Voter</th><th>Vote</th>
+ </tr>
+ <tr>
+ <td><select name="voter"><?php
+ foreach ($voters as $voter) {
+?>
+ <option value="<?php echo($voter['id']); ?>"<?php if ($voter['id'] == $_POST['voter']) { echo(" selected=\"selected\""); } ?>><?php echo($voter['name']); ?></option>
+<?php
+ }
+ ?></select></td>
+ <td><select name="vote">
+ <option value="1"<?php if (1 == $_POST['voter']) { echo(" selected=\"selected\""); } ?>>Aye</option>
+ <option value="0"<?php if (0 == $_POST['voter']) { echo(" selected=\"selected\""); } ?>>Abstain</option>
+ <option value="-1"<?php if (-1 == $_POST['voter']) { echo(" selected=\"selected\""); } ?>>Naye</option>
+ </select></td>
+ </tr>
+ <tr>
+ <th colspan="2">Justification:</th>
+ </tr>
+ <tr>
+ <td colspan="2"><textarea name="justification"><?php echo($_POST['justification']); ?></textarea></td>
+ </tr>
+ <tr>
+ <td colspan="2"><input type="submit" value="Proxy Vote" /></td>
+ </tr>
+ </table>
+ </form>
+<?php
+ } else {
+?>
+ <b>Could not retrieve voters!</b><br/>
+ <a href="motions.php">Back to motions</a><br/>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i>
+<?php
+ }
+ }
+?>
+
+<?php
+ } else {
+?>
+ <b>This is not a valid motion!</b><br/>
+ <a href="motions.php">Back to motions</a><br/>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i>
+<?php
+ }
+ }
+?>
+ </body>
+</html>
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 @@
+<?php
+ if ($_SERVER['HTTPS'] != 'on') {
+ header("HTTP/1.0 302 Redirect");
+ header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
+ exit();
+ }
+ $user = $_SERVER['REMOTE_USER'];
+ require_once("database.php");
+ $db = new DB();
+ $stmt = $db->getStatement("get voter");
+ $stmt->execute(array($user));
+ if (!($user = $stmt->fetch())) {
+ header("HTTP/1.0 302 Redirect");
+ header("Location: denied.php");
+ exit();
+ }
+?>
+<html>
+ <head>
+ <title>CAcert Board Decisions</title>
+ <meta http-equiv="Content-Type" content="text/html; charset='UTF-8'" />
+ <link rel="stylesheet" type="text/css" href="styles.css" />
+ </head>
+ <body>
+ <?php
+ if (is_numeric($_REQUEST['motion']) && is_numeric($_REQUEST['vote'])) {
+ $stmt = $db->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()) {
+ ?>
+ <b>Your vote has been registered.</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <?php
+ $name = $user['name'];
+ $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 = <<<BODY
+Dear Board,
+
+$name has just voted $vote on motion $tag.
+
+Motion:
+ $title
+ $content
+
+Kind regards,
+the vote system
+
+BODY;
+ mail($board,"Re: $tag - $title",$body);
+ } else {
+ ?>
+ <b>Your vote has NOT been registered.</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i>
+ <?php
+ }
+ } else {
+ ?>
+ <b>Your vote has NOT been registered.</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <i><?php echo join("<br/>\n",$stmt->errorInfo()); ?></i>
+ <?php
+ }
+ } else {
+ ?>
+ <b>Your vote has NOT been registered.</b><br/>
+ <b>Voting is alread closed!</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <?php
+ }
+ } else {
+ ?>
+ <b>Your vote has NOT been registered.</b><br/>
+ <b>Could not find the motion to be voted!</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <?php
+ }
+ } else {
+ ?>
+ <b>This call is not a valid vote!</b><br/>
+ <a href="motions.php">Back to motions</a>
+ <?php
+ }
+ ?>
+ </body>
+</html> \ No newline at end of file