--- /dev/null
+<?php
+$GLOBALS['db'] = new PDO("sqlite:database.db");
+
+$qid = $_GET['qid'] ?? NULL;
+$view = $_GET['view'] ?? 'vote';
+
+function query_db($query, $params=null)
+{
+ $statement = $GLOBALS['db']->prepare($query);
+ $statement->setFetchMode(PDO::FETCH_ASSOC);
+ $result = $statement->execute($params);
+ #$statement->debugDumpParams();
+ if (!$result)
+ {
+ error(500, "Uh-oh, something went wrong. Sorry!");
+ }
+ return $statement;
+}
+
+function get_title($qid)
+{
+ $q = query_db(
+ "SELECT title FROM questions WHERE qid = ?",
+ [ $qid ])->fetch();
+
+ return $q['title'];
+}
+
+function get_options($qid)
+{
+ $q = query_db(
+ "SELECT * FROM options WHERE qid = ?",
+ [ $qid ])->fetchAll();
+
+ $opts = array_map(fn($row) => $row['name'], $q);
+ shuffle($opts);
+ return $opts;
+}
+
+function get_results($qid)
+{
+ $q = query_db(
+ "SELECT * FROM options WHERE qid = ?",
+ [ $qid ])->fetchAll();
+
+ $results = [];
+ foreach ($q as $opt)
+ {
+ // Get all points for option
+ $qq = query_db(
+ "SELECT SUM(points) FROM responses WHERE oid = ?",
+ [ $opt['oid'] ])->fetch();
+ $results[$opt['name']] = $qq['SUM(points)'] ?? 0;
+ }
+ asort($results);
+ return array_reverse($results);
+}
+
+function get_num_responses($qid)
+{
+ $q = query_db(
+ "SELECT COUNT(*) FROM responses INNER JOIN options USING (oid) WHERE qid = ?",
+ [ $qid ])->fetch();
+ return $q["COUNT(*)"];
+}
+
+function get_end_date($qid)
+{
+ $q = query_db(
+ "SELECT enddate FROM questions WHERE qid = ?",
+ [ $qid ])->fetch();
+ return $q['enddate'];
+}
+
+function add_vote($qid, $opt, $points)
+{
+ $q = query_db(
+ "SELECT oid FROM options WHERE qid = ? AND name = ?",
+ [$qid, $opt])->fetch();
+
+ if ($q)
+ {
+ $oid = $q['oid'];
+ query_db(
+ "INSERT INTO responses(oid, points) VALUES (?, ?)",
+ [$oid, $points])->fetch();
+ }
+ else
+ {
+ error_log($opt);
+ }
+}
+
+function create_new_poll($title, $options, $enddate)
+{
+ // Create new question
+ $q = query_db(
+ "INSERT INTO questions(title, enddate) VALUES (?, ?) RETURNING qid",
+ [$title, $enddate])->fetch();
+ $qid = $q['qid'];
+
+ // Create options (splitting input into lines)
+ foreach(preg_split("/((\r?\n)|(\r\n?))/", $options) as $o)
+ {
+ query_db(
+ "INSERT INTO options(qid, name) VALUES (?, ?)",
+ [$qid, $o])->fetch();
+ }
+
+ return $qid;
+}
+
+function poll_url($qid, $view="vote")
+{
+ return "?qid=$qid&view=$view";
+}
+
+// Creating new poll
+if (isset($_POST['title']) and isset($_POST['options']))
+{
+ $qid = create_new_poll($_POST['title'], $_POST['options'], $_POST['enddate'] ?? NULL);
+ // Redirect to poll
+ header("Location: ".poll_url($qid));
+ exit;
+}
+
+// Voting
+if (isset($_POST['qid']))
+{
+ foreach ($_POST as $key => $value)
+ {
+ $prefix = "opt-";
+ if (str_starts_with($key, $prefix))
+ {
+ $opt = substr($key, strlen($prefix));
+ $opt = str_replace("_", " ", $opt);
+ add_vote($_POST['qid'], $opt, (int) $value);
+ }
+ }
+
+ // Redirect to results
+ header("Location: ".poll_url($qid, "results"));
+ exit;
+}
+
+// Background JSON check whether more people have voted
+if (isset($qid) && isset($_GET['count'])) {
+ // Check of more users have joined
+ header('Content-type: application/json');
+ if ($_GET['count'] != get_num_responses($qid)) echo '{"reload": true}';
+ else echo '{"reload": false}';
+ exit;
+}
+
+$ended = false;
+if (isset($qid)) {
+ $enddate = get_end_date($qid);
+ $nowdate = gmdate("Y-m-d\TH:i");
+ $ended = $nowdate > $enddate;
+}
+
+?>
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Poll!</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <style>
+ body {
+ font-family: sans-serif;
+ max-width: 30em;
+ margin: 10px auto;
+ border: 1px solid #cca;
+ padding: 10px;
+ background-color: #ffd;
+ color: #434;
+ }
+ input, textarea {
+ margin: 5px;
+ font-family: sans-serif;
+ font-size: 1em;
+ }
+ input[type=submit] {
+ background: #fdf;
+ color: #434;
+ border: 0;
+ cursor: pointer;
+ border-radius: 5px;
+ padding: 5px;
+ font-weight: bold;
+ }
+ input[disabled] {
+ background: none;
+ border: none;
+ color: #434;
+ }
+ ul {
+ list-style-type: none;
+ padding: 0px;
+ }
+ li {
+ margin: 10px 0px;
+ line-height: 1em;
+ }
+ </style>
+
+ <?php if (isset($qid) && $view == "results"): ?>
+ <script>
+ async function reloadIfChanged() {
+ const url = "/?qid=<?= $qid ?>&count=<?= get_num_responses($qid) ?>";
+ const response = await fetch(url);
+ const result = await response.json();
+ if (result.reload) location.reload();
+ else setTimeout(reloadIfChanged, 10000);
+ }
+ </script>
+ <?php endif ?>
+
+</head>
+
+<?php if (isset($qid) && $view == "results"): # Periodically reload ?>
+<body onload="setTimeout('reloadIfChanged()', 10000)">
+<?php else: ?>
+<body>
+<?php endif ?>
+
+<?php #########################################################################
+# VOTE
+
+if (isset($qid) && $view == "vote" && !$ended): ?>
+
+ <h2><?= get_title($qid) ?></h2>
+<?php if (isset($enddate)): ?>
+ <p>Closes: <input type="datetime-local" value="<?= $enddate ?>" disabled> (UTC)</p>
+<?php endif ?>
+ <p>
+ The option with the most points wins!
+ Give your favorite option 5 points, second favorite 4 points, etc.
+ Or give them all 5 points if you really can't decide.
+ </p>
+ <form method="post">
+ <input name="qid" type="hidden" value="<?= $qid ?>">
+ <ul>
+ <?php foreach (get_options($qid) as $opt): ?>
+ <li><input name="opt-<?= $opt ?>" type="number" min="0" max="5">
+ <b><?= $opt ?></b></li>
+ <?php endforeach ?>
+ </ul>
+ <input type="submit" value="Cast Vote!">
+ </form>
+ <br><a href="<?= poll_url($qid, "results") ?>">Show Results</a>
+ <br><br><a href="/">New Poll</a>
+
+<?php #########################################################################
+# RESULTS
+
+elseif (isset($qid)): ?>
+ <h2><?= get_title($qid) ?></h2>
+
+<?php if ($ended): ?>
+ <p>Poll has ended.</p>
+<?php endif ?>
+
+ <ul>
+ <?php foreach (get_results($qid) as $opt => $points): ?>
+ <li><b><?= $opt ?></b><br>
+ <!-- Point Count Bar -->
+ <small>
+ <?php for ($i = 0; $i < $points; $i ++): ?>/<?php endfor ?>
+ </small> (<?= $points ?>)
+ </li>
+ <?php endforeach ?>
+ </ul>
+ <br><a href="/">New Poll</a>
+
+<?php #########################################################################
+# NEW POLL
+
+else: ?>
+ <h2>New Poll</h2>
+ <form method="post">
+ <label>Question:<br>
+ <input type="text" name="title"></label><br>
+ <label>Options (one per line):<br>
+ <textarea rows="8" cols="30" name="options"></textarea></label><br>
+ <label>Closes on (optional) (UTC):<br>
+ <input type="datetime-local" name="enddate"></label><br>
+ <input type="submit" value="Create Poll">
+ </form>
+<?php endif ?>
+
+</body>
+</html>
+