1
0
mirror of https://git.cant.at/Madeorsk/PollVerlaine synced 2024-11-25 08:04:33 +01:00

Merge remote-tracking branch 'origin/tagada'

This commit is contained in:
Madeorsk 2018-08-13 17:08:09 +02:00
commit f738330baf
7 changed files with 122 additions and 6 deletions

67
API.md Normal file
View File

@ -0,0 +1,67 @@
# 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 |
| --------------- | ------------------------------------ | ---------- |
| `label` | The option. | no |
### Settings
| Attribute | Description | Nullable |
| --------------- | ------------------------------------ | ---------- |
| `unique_ip` | One vote per IP address. Boolean. | yes |

View File

@ -9,7 +9,7 @@ Clone the repository :
mkdir db && touch db/polls.db && composer install mkdir db && touch db/polls.db && composer install
``` ```
Uncomment the dba extention in `php.ini` : Uncomment the `dba` extention in `php.ini` :
``` ```
extension=dba extension=dba
``` ```
@ -25,3 +25,5 @@ location /
``` ```
## API ## API
See [API.md](API.md).

View File

@ -3,14 +3,19 @@ require __DIR__ . "/vendor/autoload.php";
require __DIR__ . "/models/Poll.php"; require __DIR__ . "/models/Poll.php";
require __DIR__ . "/config/app.php"; require __DIR__ . "/config/app.php";
function format_poll($poll) function format_poll($poll, $with_delete_token = false)
{ {
return [ $array = [
"id" => $poll->id, "id" => $poll->id,
"title" => $poll->title, "title" => $poll->title,
"creation_date" => $poll->creation_date, "creation_date" => $poll->creation_date,
"options" => $poll->options, "options" => $poll->options,
]; ];
if ($with_delete_token === true)
$array['delete_token'] = $poll->delete_token;
return $array;
} }
Flight::route("POST /polls", function () { Flight::route("POST /polls", function () {
@ -20,7 +25,7 @@ Flight::route("POST /polls", function () {
$request_json = $request->data; $request_json = $request->data;
$poll = Poll::create_poll($request_json); $poll = Poll::create_poll($request_json);
if ($poll) if ($poll)
Flight::json(format_poll($poll), 201); Flight::json(format_poll($poll, true), 201);
else else
Flight::halt(403, "<h1>403 Forbidden</h1><h3>Invalid data.</h3>"); Flight::halt(403, "<h1>403 Forbidden</h1><h3>Invalid data.</h3>");
} }
@ -103,6 +108,35 @@ Flight::route("GET /polls/@id:[a-fA-F0-9]+/results", function ($id) {
Flight::notFound(); 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 (Flight::request()->type === "application/json")
{
if ($poll->delete_token === $token)
{
$poll->delete();
Flight::json(format_poll($poll), 204);
}
else
Flight::halt(401, "<h1>401 Unauthorized</h1><h3>Invalid token.</h3>");
}
else
{
if ($poll->delete_token === $token)
{
$poll->delete();
Flight::redirect('/', 204);
}
else
Flight::redirect('/', 401);
}
}
else
Flight::notFound();
});
Flight::route("/", function () { Flight::route("/", function () {
global $VERLAINE; global $VERLAINE;
Flight::render("home", ["app_url" => $VERLAINE["app_url"]], "body_content"); Flight::render("home", ["app_url" => $VERLAINE["app_url"]], "body_content");

View File

@ -22,6 +22,7 @@ class Poll
]; ];
} }
$poll->gen_new_id(); $poll->gen_new_id();
$poll->delete_token = bin2hex(openssl_random_pseudo_bytes(16));
$poll->save(); $poll->save();
return $poll; return $poll;
} }
@ -46,6 +47,7 @@ class Poll
$poll->title = $saved_poll_data->title; $poll->title = $saved_poll_data->title;
$poll->creation_date = $saved_poll_data->creation_date; $poll->creation_date = $saved_poll_data->creation_date;
$poll->options = $saved_poll_data->options; $poll->options = $saved_poll_data->options;
$poll->delete_token = $saved_poll_data->delete_token;
dba_close($db); dba_close($db);
return $poll; return $poll;
@ -61,8 +63,9 @@ class Poll
public $title; public $title;
public $creation_date; public $creation_date;
public $options = []; public $options = [];
public $delete_token;
public function gen_new_id() private function gen_new_id()
{ {
$db = dba_open(SAVE_PATH . "/polls.db", "rd"); $db = dba_open(SAVE_PATH . "/polls.db", "rd");
@ -97,7 +100,15 @@ class Poll
"title" => $this->title, "title" => $this->title,
"creation_date" => $this->creation_date, "creation_date" => $this->creation_date,
"options" => $this->options, "options" => $this->options,
"delete_token" => $this->delete_token
]), $db); ]), $db);
dba_close($db); dba_close($db);
} }
public function delete()
{
$db = dba_open(SAVE_PATH . "/polls.db", "wd");
dba_delete($this->id, $db);
dba_close($db);
}
} }

View File

@ -48,6 +48,7 @@ document.addEventListener("DOMContentLoaded", () => {
let result_el = document.getElementById("result"); 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_title/g, json.title);
result_el.innerHTML = result_el.innerHTML.replace(/:poll_url/g, `/polls/${json.id}`); 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"); result_el.removeAttribute("hidden");
}); });
}); });

View File

@ -14,6 +14,7 @@
<div id="result" hidden> <div id="result" hidden>
<p>Your poll <strong>:poll_title</strong> is ready!</p> <p>Your poll <strong>:poll_title</strong> is ready!</p>
<input type="text" name="pollurl" value="<?= $app_url ?>:poll_url" /> <input type="text" name="pollurl" value="<?= $app_url ?>:poll_url" />
<input type="text" name="deleteurl" value="<?= $app_url ?>:delete_url" />
<a class="button" href=":poll_url">See the poll!</a> <a class="button" href=":poll_url">See the poll!</a>
</div> </div>
</main> </main>

View File

@ -10,5 +10,5 @@
<?php endforeach; ?> <?php endforeach; ?>
<input type="submit" value="Vote" /> <input type="submit" value="Vote" />
</form> </form>
<a class="button margin">Jump to results</a> <a class="button margin" href="/polls/<?= $poll->id ?>/results">Jump to results</a>
</main> </main>