diff --git a/index.php b/index.php
index 5efeb78..6edc20f 100644
--- a/index.php
+++ b/index.php
@@ -41,8 +41,14 @@ Flight::route("GET /polls/@id:[a-fA-F0-9]+", function ($id) {
Flight::json(format_poll($poll));
else
{
- Flight::render("poll", ["poll" => $poll], "body_content");
- Flight::render("layout");
+ // If unique_ip option is enabled => Only allow unregistered IPs.
+ if (!$poll->settings->unique_ip && isset($poll->ips[Flight::request()->ip]))
+ Flight::redirect("/polls/$id/results"); // A vote is already registered with this IP: redirect.
+ else
+ {
+ Flight::render("poll", ["poll" => $poll], "body_content");
+ Flight::render("layout");
+ }
}
}
else
@@ -59,17 +65,14 @@ Flight::route("POST /polls/@id:[a-fA-F0-9]+/vote", function ($id) {
{
if (isset(Flight::request()->data["options"]) && is_array(Flight::request()->data["options"]))
{ // Check that an options id array exists.
- //TODO Check that only the authorized number of options are selected.
- if($poll->vote(Flight::request()->data["options"]) === false) // Vote for the given options.
- {
- Flight::halt(403, "
403 Forbidden
Too many votes for this IP address.
");
- }
- else
+ if ($poll->vote(Flight::request()->data["options"])) // Vote for the given options.
{
// Then save and show poll data.
$poll->save();
Flight::json(format_poll($poll));
}
+ else
+ Flight::halt(403, "
403 Forbidden
Too many votes for this IP address or too many options selected.
");
}
else
Flight::halt(403, "
403 Forbidden
Invalid data.
");
@@ -79,18 +82,16 @@ Flight::route("POST /polls/@id:[a-fA-F0-9]+/vote", function ($id) {
if (isset(Flight::request()->data["options"]))
{ // Check that any data has been sent.
$selected_options = Flight::request()->data["options"];
- if (is_string($selected_options))
- { // If it is a string, input[type="radio"] were used so only one option is selected.
- if($poll->vote([intval($selected_options)]) === false) // Vote for the selected option.
- {
- Flight::redirect('/', 401);
- }
- else
+ if (is_array($selected_options))
+ {
+ if($poll->vote($selected_options)) // Vote for the selected option.
{
$poll->save();
Flight::redirect("/polls/$id/results"); // Redirect to the results.
}
- } //TODO: Multiple options case.
+ else
+ Flight::redirect("/polls/$id"); // Error: Redirect to the vote page.
+ }
else
Flight::redirect("/polls/$id"); // Error: Redirect to the vote page.
}
diff --git a/models/Poll.php b/models/Poll.php
index 1edc25a..201e401 100644
--- a/models/Poll.php
+++ b/models/Poll.php
@@ -4,6 +4,16 @@ require __DIR__ . "/../config/app.php";
define("SAVE_PATH", __DIR__ . "/../db");
+define("DEFAULT_SETTINGS", ["unique_ip" => true, "multiple_choices" => false]);
+
+function settings_or_default($settings)
+{
+ return [
+ "unique_ip" => isset($settings["unique_ip"]) ? $settings["unique_ip"] : DEFAULT_SETTINGS["unique_ip"],
+ "multiple_choices" => isset($settings["multiple_choices"]) ? $settings["multiple_choices"] : DEFAULT_SETTINGS["multiple_choices"],
+ ];
+}
+
class Poll
{
/**
@@ -23,7 +33,7 @@ class Poll
"votes" => 0,
];
}
- $poll->settings = $request_data->settings;
+ $poll->settings = isset($request_data->settings) ? settings_or_default($request_data->settings) : DEFAULT_SETTINGS;
$poll->gen_new_id();
$poll->delete_token = bin2hex(openssl_random_pseudo_bytes(16));
$poll->save();
@@ -70,7 +80,7 @@ class Poll
public $title;
public $creation_date;
public $options = [];
- public $settings = [];
+ public $settings;
public $ips = [];
public $delete_token;
@@ -98,14 +108,20 @@ class Poll
*/
public function vote(array $options)
{
- if($this->settings->unique_ip === false)
- {
- if(isset($this->ips[Flight::request()->ip]))
- return false;
+ if (empty($options))
+ return false; // Disallow void selection vote. TODO: Allow it in settings?
+
+ if (!$this->settings->unique_ip)
+ { // If unique_ip option is enabled => Only allow unregistered IPs.
+ if (isset($this->ips[Flight::request()->ip]))
+ return false; // A vote is already registered with this IP: error.
else
- $this->ips[Flight::request()->ip] = true;
+ $this->ips[Flight::request()->ip] = true; // We register the IP in the used IPs array.
}
+ if (!$this->settings->multiple_choices && count($options) > 1)
+ return false; // If multiple_choices is not selected, disallow an options array with more than one selected option.
+
// For each option in the list, add 1 to the vote number in the poll data.
foreach ($options as $option)
if (isset($this->options[intval($option)])) // Check invalid options id.
@@ -125,7 +141,7 @@ class Poll
"options" => $this->options,
"delete_token" => $this->delete_token,
"ips" => $this->ips,
- "settings" => $this->settings
+ "settings" => $this->settings,
]), $db);
dba_close($db);
}
diff --git a/static/css/common.css b/static/css/common.css
index 049441e..a93de49 100644
--- a/static/css/common.css
+++ b/static/css/common.css
@@ -83,7 +83,7 @@ main a.button:hover
main hr
{
- border: solid #343434 thin;
+ border: solid #0088E5 thin;
width: 25rem;
}
diff --git a/static/js/new.js b/static/js/new.js
index 7a95d90..4380b3a 100644
--- a/static/js/new.js
+++ b/static/js/new.js
@@ -37,9 +37,10 @@ document.addEventListener("DOMContentLoaded", () => {
body: JSON.stringify({
title: form.querySelector(`input[name="title"]`).value,
options: get_choices(form),
- settings: {
- "unique_ip": form.querySelector(`input[name="unique_ip"]`).checked,
- }
+ settings: {
+ unique_ip: form.querySelector(`input[name="unique_ip"]`).checked,
+ multiple_choices: form.querySelector(`input[name="multiple_choices"]`).checked,
+ }
}),
headers: {
"Content-Type": "application/json",
diff --git a/views/home.php b/views/home.php
index f4b952b..016bbc4 100644
--- a/views/home.php
+++ b/views/home.php
@@ -15,6 +15,11 @@
+