Multiple choices and redirections

+ Now possible to allow multiple choices;
* Add partial settings support;
* Fixed and moved some redirections to appropriate pages;
* CSS adjustments.
This commit is contained in:
Madeorsk 2018-08-16 14:09:37 +02:00
parent b7ece5cdad
commit 7b0a619b0e
6 changed files with 52 additions and 29 deletions

View File

@ -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, "<h1>403 Forbidden</h1><h3>Too many votes for this IP address.</h3>");
}
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, "<h1>403 Forbidden</h1><h3>Too many votes for this IP address or too many options selected.</h3>");
}
else
Flight::halt(403, "<h1>403 Forbidden</h1><h3>Invalid data.</h3>");
@ -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.
}

View File

@ -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);
}

View File

@ -83,7 +83,7 @@ main a.button:hover
main hr
{
border: solid #343434 thin;
border: solid #0088E5 thin;
width: 25rem;
}

View File

@ -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",

View File

@ -15,6 +15,11 @@
<label for="unique_ip" class="check"></label>
<label for="unique_ip">Allow multiple votes from a single IP</label>
</div>
<div class="option">
<input type="checkbox" name="multiple_choices" value="multiple_choices" id="multiple_choices" />
<label for="multiple_choices" class="check"></label>
<label for="multiple_choices">Allow to select multiple choices in one vote</label>
</div>
<input type="submit" value="Create poll" />
</form>
<div id="result" hidden>

View File

@ -3,7 +3,7 @@
<form action="/polls/<?= $poll->id ?>/vote" method="POST" id="poll">
<?php foreach ($poll->options as $id => $option): ?>
<div class="option">
<input type="radio" name="options" value="<?= $id ?>" id="option-<?= $id ?>" />
<input type="<?= $poll->settings->multiple_choices ? "checkbox" : "radio" ?>" name="options[]" value="<?= $id ?>" id="option-<?= $id ?>" />
<label for="option-<?= $id ?>" class="check"></label>
<label for="option-<?= $id ?>"><?= $option->label ?></label>
</div>