From d0f1ffc4563d338e134bd105ef736e9901db14b1 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 13 Aug 2018 13:50:31 +0200 Subject: [PATCH 1/5] Some more documentaion --- API.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 +++- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 API.md diff --git a/API.md b/API.md new file mode 100644 index 0000000..1f597f7 --- /dev/null +++ b/API.md @@ -0,0 +1,68 @@ +# VerlainePoll's API + +## Methods + +### Create a poll +``` +POST /polls +``` + +| Field | Description | Optional | +| -------------- | ------------------------------------ | ---------- | +| `title` | The question. | no | +| `options` | All the options. Array of strings. | no | +| `settings` | A Settings object. | yes | + +Return a Poll. + +### Retrieve a poll + +``` +GET /polls/:id +``` + +Return a Poll. + +### Vote + +``` +POST /polls/:id/vote +``` +| Field | Description | Optional | +| -------------- | -------------------------------------------- | ---------- | +| `options` | Options you want to vote for. Array of ids. | no | + +Return a Poll. + +### Delete a poll + +``` +DELETE /polls/:id +``` + +Return a Poll. + +## Entities + +### Poll + +| Attribute | Description | Nullable | +| --------------- | ------------------------------------ | ---------- | +| `id` | | no | +| `title` | The question. | no | +| `options` | All the options. Array of Options. | no | +| `settings` | A Settings object. | no | +| `creation_date` | Creation date. | no | + +### Options + +| Attribute | Description | Nullable | +| --------------- | ------------------------------------ | ---------- | +| `id` | | no | +| `label` | The option. | no | + +### Settings + +| Attribute | Description | Nullable | +| --------------- | ------------------------------------ | ---------- | +| `unique_ip` | One vote per IP address. Boolean. | yes | diff --git a/README.md b/README.md index f32fa59..300c44c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Clone the repository : mkdir db && touch db/polls.db && composer install ``` -Uncomment the dba extention in `php.ini` : +Uncomment the `dba` extention in `php.ini` : ``` extension=dba ``` @@ -25,3 +25,5 @@ location / ``` ## API + +See [API.md](API.md). \ No newline at end of file From d5ab16135db21cbc3174c0f06f2fdb7ed55ded81 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 13 Aug 2018 14:29:55 +0200 Subject: [PATCH 2/5] Remove id from Option --- API.md | 1 - 1 file changed, 1 deletion(-) diff --git a/API.md b/API.md index 1f597f7..a20505c 100644 --- a/API.md +++ b/API.md @@ -58,7 +58,6 @@ Return a Poll. | Attribute | Description | Nullable | | --------------- | ------------------------------------ | ---------- | -| `id` | | no | | `label` | The option. | no | ### Settings From 7a29c6265b2af2891c0b6685137f566625e6c776 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 13 Aug 2018 15:20:06 +0200 Subject: [PATCH 3/5] Delete a Poll --- index.php | 31 ++++++++++++++++++++++++++++--- models/Poll.php | 13 ++++++++++++- static/js/new.js | 1 + views/home.php | 1 + 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/index.php b/index.php index 2d86700..b9c1038 100644 --- a/index.php +++ b/index.php @@ -3,14 +3,19 @@ require __DIR__ . "/vendor/autoload.php"; require __DIR__ . "/models/Poll.php"; require __DIR__ . "/config/app.php"; -function format_poll($poll) +function format_poll($poll, $with_delete_token = false) { - return [ + $array = [ "id" => $poll->id, "title" => $poll->title, "creation_date" => $poll->creation_date, "options" => $poll->options, ]; + + if ($with_delete_token === true) + $array['delete_token'] = $poll->delete_token; + + return $array; } Flight::route("POST /polls", function () { @@ -20,7 +25,7 @@ Flight::route("POST /polls", function () { $request_json = $request->data; $poll = Poll::create_poll($request_json); if ($poll) - Flight::json(format_poll($poll), 201); + Flight::json(format_poll($poll, true), 201); else Flight::halt(403, "

403 Forbidden

Invalid data.

"); } @@ -86,6 +91,26 @@ Flight::route("POST /polls/@id:[a-fA-F0-9]+/vote", function ($id) { Flight::notFound(); }); +Flight::route("GET|DELETE /polls/@id:[a-fA-F0-9]+/@token:[a-fA-F0-9]+", function ($id, $token) { + $poll = Poll::load_poll($id); + if ($poll) + { + if ($poll->delete_token !== $token) + Flight::halt(401, "

401 Unauthorized

Invalid token.

"); + + $poll->delete(); + + if (Flight::request()->type === "application/json") + Flight::json(format_poll($poll), 204); + else + { + Flight::redirect('/'); + } + } + else + Flight::notFound(); +}); + Flight::route("/", function () { global $VERLAINE; Flight::render("home", ["app_url" => $VERLAINE["app_url"]], "body_content"); diff --git a/models/Poll.php b/models/Poll.php index 5dd8112..7d56e7b 100644 --- a/models/Poll.php +++ b/models/Poll.php @@ -22,6 +22,7 @@ class Poll ]; } $poll->gen_new_id(); + $poll->delete_token = bin2hex(openssl_random_pseudo_bytes(16)); $poll->save(); return $poll; } @@ -46,6 +47,7 @@ class Poll $poll->title = $saved_poll_data->title; $poll->creation_date = $saved_poll_data->creation_date; $poll->options = $saved_poll_data->options; + $poll->delete_token = $saved_poll_data->delete_token; dba_close($db); return $poll; @@ -61,8 +63,9 @@ class Poll public $title; public $creation_date; public $options = []; + public $delete_token; - public function gen_new_id() + private function gen_new_id() { $db = dba_open(SAVE_PATH . "/polls.db", "rd"); @@ -97,7 +100,15 @@ class Poll "title" => $this->title, "creation_date" => $this->creation_date, "options" => $this->options, + "delete_token" => $this->delete_token ]), $db); dba_close($db); } + + public function delete() + { + $db = dba_open(SAVE_PATH . "/polls.db", "wd"); + dba_delete($this->id, $db); + dba_close($db); + } } diff --git a/static/js/new.js b/static/js/new.js index a1d0012..5f3d533 100644 --- a/static/js/new.js +++ b/static/js/new.js @@ -48,6 +48,7 @@ document.addEventListener("DOMContentLoaded", () => { let result_el = document.getElementById("result"); result_el.innerHTML = result_el.innerHTML.replace(/:poll_title/g, json.title); result_el.innerHTML = result_el.innerHTML.replace(/:poll_url/g, `/polls/${json.id}`); + result_el.innerHTML = result_el.innerHTML.replace(/:delete_url/g, `/polls/${json.id}/${json.delete_token}`); result_el.removeAttribute("hidden"); }); }); diff --git a/views/home.php b/views/home.php index f541cf5..658e008 100644 --- a/views/home.php +++ b/views/home.php @@ -14,6 +14,7 @@ From 9469ffb88b5d2bea3c90e0cdde626f45e423d72b Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 13 Aug 2018 15:23:26 +0200 Subject: [PATCH 4/5] DELETE: Change HTTP Status Code to 204 --- index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.php b/index.php index b9c1038..0916b61 100644 --- a/index.php +++ b/index.php @@ -104,7 +104,7 @@ Flight::route("GET|DELETE /polls/@id:[a-fA-F0-9]+/@token:[a-fA-F0-9]+", function Flight::json(format_poll($poll), 204); else { - Flight::redirect('/'); + Flight::redirect('/', 204); } } else From a0333c7065746e00e38762afab41b8721aba7c9c Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 13 Aug 2018 16:22:24 +0200 Subject: [PATCH 5/5] WIP: DELETE Redirect on error --- index.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/index.php b/index.php index 0916b61..fb57ece 100644 --- a/index.php +++ b/index.php @@ -95,16 +95,27 @@ Flight::route("GET|DELETE /polls/@id:[a-fA-F0-9]+/@token:[a-fA-F0-9]+", function $poll = Poll::load_poll($id); if ($poll) { - if ($poll->delete_token !== $token) - Flight::halt(401, "

401 Unauthorized

Invalid token.

"); - - $poll->delete(); - if (Flight::request()->type === "application/json") - Flight::json(format_poll($poll), 204); + { + if ($poll->delete_token === $token) + { + $poll->delete(); + + Flight::json(format_poll($poll), 204); + } + else + Flight::halt(401, "

401 Unauthorized

Invalid token.

"); + } else { - Flight::redirect('/', 204); + if ($poll->delete_token === $token) + { + $poll->delete(); + + Flight::redirect('/', 204); + } + else + Flight::redirect('/', 401); } } else