Compare commits

..

14 Commits

9 changed files with 228 additions and 61 deletions

View File

@ -5,8 +5,13 @@ require_once __DIR__ .'/bootstrap.php';
if (isset($_GET['code'])) { if (isset($_GET['code'])) {
$success = $api->authenticate($_GET['code']); $success = $api->authenticate($_GET['code']);
$from = empty($_GET['from']) ? null : $_GET['from'];
$page = 'index.php';
if (!empty($_GET['from'])) {
$page = $_GET['from'];
}
if ($success) { if ($success) {
redirect('index.php'); redirect($page);
} else { } else {
quit(get_page_header().'Echo error authenticating'); quit(get_page_header().'Echo error authenticating');
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "hutattedonmyarm/dragonpolls", "name": "hutattedonmyarm/dragonpolls",
"version": "1.1.0-beta", "version": "1.2.0-beta",
"description": "A polling client for pnut.io", "description": "A polling client for pnut.io",
"require": { "require": {
"hutattedonmyarm/apnuti": "@dev" "hutattedonmyarm/apnuti": "@dev"

66
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "6fc1593cab1017ef65d6e12dc56c499c", "content-hash": "25a44e30da5350cab5a81a2d96b1750a",
"packages": [ "packages": [
{ {
"name": "hutattedonmyarm/apnuti", "name": "hutattedonmyarm/apnuti",
@ -12,7 +12,7 @@
"dist": { "dist": {
"type": "path", "type": "path",
"url": "../APnutI", "url": "../APnutI",
"reference": "51a798ea3e39570e47eb3d55fc838d61cc0967f6" "reference": "2f5aa63306ed989499a2f2003d8cfcc36061d341"
}, },
"require": { "require": {
"ext-curl": "*", "ext-curl": "*",
@ -43,52 +43,58 @@
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "2.2.0", "version": "2.9.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Seldaek/monolog.git", "url": "https://github.com/Seldaek/monolog.git",
"reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "url": "https://api.github.com/repos/Seldaek/monolog/zipball/437cb3628f4cf6042cc10ae97fc2b8472e48ca1f",
"reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2", "php": ">=7.2",
"psr/log": "^1.0.1" "psr/log": "^1.0.1 || ^2.0 || ^3.0"
}, },
"provide": { "provide": {
"psr/log-implementation": "1.0.0" "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
}, },
"require-dev": { "require-dev": {
"aws/aws-sdk-php": "^2.4.9 || ^3.0", "aws/aws-sdk-php": "^2.4.9 || ^3.0",
"doctrine/couchdb": "~1.0@dev", "doctrine/couchdb": "~1.0@dev",
"elasticsearch/elasticsearch": "^7", "elasticsearch/elasticsearch": "^7 || ^8",
"graylog2/gelf-php": "^1.4.2", "ext-json": "*",
"graylog2/gelf-php": "^1.4.2 || ^2@dev",
"guzzlehttp/guzzle": "^7.4",
"guzzlehttp/psr7": "^2.2",
"mongodb/mongodb": "^1.8", "mongodb/mongodb": "^1.8",
"php-amqplib/php-amqplib": "~2.4", "php-amqplib/php-amqplib": "~2.4 || ^3",
"php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.15",
"phpspec/prophecy": "^1.6.1", "phpstan/phpstan": "^0.12.91",
"phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "^8.5.14",
"phpunit/phpunit": "^8.5", "predis/predis": "^1.1 || ^2.0",
"predis/predis": "^1.1", "rollbar/rollbar": "^1.3 || ^2 || ^3",
"rollbar/rollbar": "^1.3", "ruflin/elastica": "^7",
"ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0",
"swiftmailer/swiftmailer": "^5.3|^6.0" "symfony/mailer": "^5.4 || ^6",
"symfony/mime": "^5.4 || ^6"
}, },
"suggest": { "suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server", "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
"ext-mbstring": "Allow to work properly with unicode symbols", "ext-mbstring": "Allow to work properly with unicode symbols",
"ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
"ext-openssl": "Required to send log messages using SSL",
"ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
"mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
"php-console/php-console": "Allow sending log messages to Google Chrome",
"rollbar/rollbar": "Allow sending log messages to Rollbar", "rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server" "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
}, },
@ -123,7 +129,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/Seldaek/monolog/issues", "issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/2.2.0" "source": "https://github.com/Seldaek/monolog/tree/2.9.2"
}, },
"funding": [ "funding": [
{ {
@ -135,20 +141,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-12-14T13:15:25+00:00" "time": "2023-10-27T15:25:26+00:00"
}, },
{ {
"name": "psr/log", "name": "psr/log",
"version": "1.1.3", "version": "1.1.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/log.git", "url": "https://github.com/php-fig/log.git",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -172,7 +178,7 @@
"authors": [ "authors": [
{ {
"name": "PHP-FIG", "name": "PHP-FIG",
"homepage": "http://www.php-fig.org/" "homepage": "https://www.php-fig.org/"
} }
], ],
"description": "Common interface for logging libraries", "description": "Common interface for logging libraries",
@ -183,9 +189,9 @@
"psr-3" "psr-3"
], ],
"support": { "support": {
"source": "https://github.com/php-fig/log/tree/1.1.3" "source": "https://github.com/php-fig/log/tree/1.1.4"
}, },
"time": "2020-03-23T09:12:05+00:00" "time": "2021-05-03T11:20:27+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],
@ -198,5 +204,5 @@
"prefer-lowest": false, "prefer-lowest": false,
"platform": [], "platform": [],
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.0.0" "plugin-api-version": "2.6.0"
} }

View File

@ -20,11 +20,14 @@ function get_page_header(
$newpoll_class = ''; $newpoll_class = '';
if ($api->isAuthenticated(false, true)) { if ($api->isAuthenticated(false, true)) {
$u = $api->getAuthorizedUser(); $u = $api->getAuthorizedUser();
$greeting = 'Welcome, ' . ($u->name ?? '@'.$u->username); $user_avatar_url = $u->getAvatarUrl(30);
$user_avatar_url_srcset = get_source_set($u, 30);
$avatar = '<img src="' . $user_avatar_url . '" class="avatar" srcset="' . $user_avatar_url_srcset . '"/>';
$greeting = $avatar . '<span class="greeting">Welcome, ' . ($u->name ?? '@'.$u->username) . '</span>';
$logout_link = '<a href="logout.php" class="logout">Logout</a>'; $logout_link = '<a href="logout.php" class="logout">Logout</a>';
} else { } else {
$newpoll_class = 'disabled'; $newpoll_class = 'disabled';
$greeting = '<a href="' . $api->getAuthURL() . '">Login with pnut</a>'; $greeting = '<a href="' . $api->getAuthURL('?from=' . $_SERVER['REQUEST_URI']) . '">Login with pnut</a>';
} }
$title = ''; $title = '';
if ($include_app_name) { if ($include_app_name) {
@ -67,7 +70,7 @@ function get_page_header(
. $favicons . $favicons
. '<title>'.$title.'</title><link rel="stylesheet" href="styles/style.css">' . '<title>'.$title.'</title><link rel="stylesheet" href="styles/style.css">'
. $script_str . $script_str
. '<meta name="viewport" content="width=device-width,initial-scale=1">' . '<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">'
. '</head><body><header>' . '</head><body><header>'
. $home_link . $home_link
. $new_poll_link . $new_poll_link
@ -126,7 +129,7 @@ function get_source_set($user, int $base_size, int $max_scale = 3): string
function make_banner(string $type, string $content, string $custom_symbol = null): string function make_banner(string $type, string $content, string $custom_symbol = null): string
{ {
if (empty($custom_symbol)) { if (empty($custom_symbol)) {
$custom_symbol = $type === 'success' ? '✓' : '𐄂'; $custom_symbol = $type === 'success' ? '&#2713;' : '&#x00D7;';
} }
return '<div class="banner-wrapper">' return '<div class="banner-wrapper">'

View File

@ -58,10 +58,12 @@ foreach ($polls as $poll) {
<div class="poll" onclick="location.href='view_poll.php?id=<?= $poll->id ?>'"> <div class="poll" onclick="location.href='view_poll.php?id=<?= $poll->id ?>'">
<div class="header"> <div class="header">
<div class="user"> <div class="user">
<img src="<?= $user_avatar_url ?>" class="avatar" srcset="<?= $user_avatar_url_srcset ?>"/> <div class="usernamewrapper">
<div class="usernames"> <img src="<?= $user_avatar_url ?>" class="avatar" srcset="<?= $user_avatar_url_srcset ?>"/>
<b><?= $user_name.'<br>' ?></b> <div class="usernames">
<span class="username"><?= $username ?></span> <b><?= $user_name.'<br>' ?></b>
<span class="username"><?= $username ?></span>
</div>
</div> </div>
<div class="spacer"></div> <div class="spacer"></div>
<div class="datewrapper"> <div class="datewrapper">

View File

@ -32,7 +32,7 @@ if (!empty($_POST['submit'])) {
$duration_total_minutes = $duration_days*60*24 + $duration_hours * 60 + $duration_minutes; $duration_total_minutes = $duration_days*60*24 + $duration_hours * 60 + $duration_minutes;
try { try {
$poll = Poll::create($api, $prompt, $options, $max_options, $duration_total_minutes, $is_anonymous, $is_public); $poll = Poll::create($api, $prompt, $options, $max_options, $duration_total_minutes, $is_anonymous, $is_public);
redirect('post_poll.php?poll_token='.$poll->token.'&id='.$poll->id.'&prompt='.urlencode($prompt)); redirect('post_poll.php?poll_token='.$poll->token.'&id='.$poll->id);
} catch (\Exception $e) { } catch (\Exception $e) {
quit('Something went wrong creating the poll: "' . $e->getMessage() . '"'); quit('Something went wrong creating the poll: "' . $e->getMessage() . '"');
} }

View File

@ -68,22 +68,34 @@ if (empty($_GET['id']) || !is_numeric($_GET['id']) || $_GET['id'] <= 0) {
quit('Invalid poll ID'); quit('Invalid poll ID');
} }
if (empty($_GET['poll_token'])) { $poll_token = empty($_GET['poll_token']) ? null : $_GET['poll_token'];
$prompt = empty($_GET['prompt']) ? null : $_GET['prompt'];
$poll_id = (int)$_GET['id'];
$poll = null;
$is_public = false;
try {
$poll = $api->getPoll($poll_id, $poll_token);
$poll_token = $poll->token;
$prompt = $poll->prompt;
$is_public = $poll->is_public;
} catch (\Exception $e) {
// Do nothing, check for token and prompt later
}
if (empty($poll_token)) {
quit('Invalid poll token'); quit('Invalid poll token');
} }
if (empty($_GET['prompt'])) { if (empty($prompt)) {
quit('Invalid prompt'); quit('Invalid prompt');
} }
$poll_id = (int)$_GET['id']; $poll_id = (int)$_GET['id'];
$poll_token = $_GET['poll_token'];
$prompt = $_GET['prompt'];
$dir_name = dirname($_SERVER['SCRIPT_NAME']); $dir_name = dirname($_SERVER['SCRIPT_NAME']);
if ($dir_name === '.' || $dir_name === '/') { if ($dir_name === '.' || $dir_name === '/') {
$dir_name = ''; $dir_name = '';
} }
$scheme = empty($_SERVER['REQUEST_SCHEME']) ? 'http' : $_SERVER['REQUEST_SCHEME']; $scheme = empty($_SERVER['REQUEST_SCHEME']) ? 'http' : $_SERVER['REQUEST_SCHEME'];
$url = $scheme $url = $scheme
. '://' . '://'
@ -126,9 +138,11 @@ Do you want to post about your poll?
<button type="submit" name="submit" value="submit">Post to pnut</button> <button type="submit" name="submit" value="submit">Post to pnut</button>
</form> </form>
<a href="/view_poll.php?id=<?= $poll_id ?>">Take me straight to the poll</a> <a href="/view_poll.php?id=<?= $poll_id ?>">Take me straight to the poll</a>
<p> <?php if (!$is_public) { ?>
Note, that if your poll is set to private, you will either need to share your poll with a post, <p>
or give the poll's access token to everyone who should be able to vote in your poll. Your access token is: Note, that your poll is set to private. You will either need to share your poll with a post,
<pre><?= $poll_token ?></pre> or give the poll's access token to everyone who should be able to vote in your poll. Your access token is:
</p> <pre><?= $poll_token ?></pre>
</p>
<?php } ?>
<?= get_page_footer() ?> <?= get_page_footer() ?>

View File

@ -1,13 +1,15 @@
/* Globals */ /* Globals */
:root { :root {
--main-bg-color: rgb(48, 48, 48); --main-bg-color: rgb(223, 223, 223);
--secondary-bg-color: rgba(10, 10, 10, 0.7); --secondary-bg-color: rgba(20, 20, 20, 0.7);
--main-fg-color: white; --ternary-bg-color: rgba(175, 175, 175, 0.7);
--main-fg-color: black;
--secondary-fg-color: rgb(210, 210, 210);
--main-accent-color: rgb(253, 122, 0); --main-accent-color: rgb(253, 122, 0);
--disabled-color: gray; --disabled-color: gray;
--green: green; --green: green;
--default-shadow: 3px 3px 10px 1px var(--secondary-bg-color); --default-shadow: 3px 3px 10px 1px var(--secondary-bg-color);
--error-color-translucent: rgba(255, 0, 0, 0.3); --error-color-translucent: rgba(193, 0, 0, 0.87);
--error-color: rgba(255, 0, 0); --error-color: rgba(255, 0, 0);
} }
@supports (color: color(display-p3 1 1 1)) { @supports (color: color(display-p3 1 1 1)) {
@ -16,6 +18,40 @@
} }
} }
@media (prefers-color-scheme: dark) {
:root {
--main-bg-color: rgb(48, 48, 48);
--secondary-bg-color: rgba(10, 10, 10, 0.7);
--ternary-bg-color: rgba(10, 10, 10, 0.7);
--main-fg-color: white;
--secondary-fg-color: rgb(210, 210, 210);
--main-accent-color: rgb(253, 122, 0);
--disabled-color: gray;
--green: green;
--default-shadow: 3px 3px 10px 1px var(--secondary-bg-color);
--error-color-translucent: rgba(255, 0, 0, 0.3);
--error-color: rgba(255, 0, 0);
}
@supports (color: color(display-p3 1 1 1)) {
:root {
--main-accent-color: color(display-p3 0.927 0.506 0.028)
}
}
}
@media (prefers-color-scheme: light) {
::placeholder {
opacity: 1;
color: rgb(73, 73, 73);
}
:-ms-input-placeholder {
color: rgb(73, 73, 73);
}
::-ms-input-placeholder {
color: rgb(73, 73, 73);
}
}
a:visited, a { a:visited, a {
color: var(--main-accent-color); color: var(--main-accent-color);
} }
@ -84,6 +120,7 @@ header {
margin-bottom: 8px; margin-bottom: 8px;
background: var(--secondary-bg-color); background: var(--secondary-bg-color);
box-shadow: var(--default-shadow); box-shadow: var(--default-shadow);
color: var(--secondary-fg-color);
} }
.spacer { .spacer {
@ -107,6 +144,23 @@ header .newpolllink svg {
stroke-width: 1em; stroke-width: 1em;
} }
header .avatar {
width: 30px;
height: 30px;
margin-right: 4px;
}
@media (max-width: 450px) {
.linklabel {
display: none;
}
}
@media (max-width: 380px) {
.greeting {
display: none;
}
}
/* Polls */ /* Polls */
.poll { .poll {
display: inline-block; display: inline-block;
@ -127,6 +181,11 @@ header .newpolllink svg {
box-shadow: var(--default-shadow); box-shadow: var(--default-shadow);
} }
.poll .user .usernamewrapper {
display: flex;
align-items: center;
}
.datewrapper { .datewrapper {
display: grid; display: grid;
grid-column-gap: 8px; grid-column-gap: 8px;
@ -154,9 +213,28 @@ datewrapper time {
} }
.poll .header .user .avatar { .poll .header .user .avatar {
width: 50px; width: 50px;
height: 50px;
} }
.option-responses .avatar { .option-responses .avatar {
width: 20px; width: 20px;
height: 20px;
}
@media (max-width: 450px) {
.poll-grid .poll .user {
flex-direction: column;
align-items: start;
}
.datewrapper {
margin-left: 0;
}
}
@media (max-width: 380px) {
.poll .user {
flex-direction: column;
align-items: start;
}
} }
/* Success banner */ /* Success banner */
@ -210,13 +288,13 @@ datewrapper time {
} }
.create-poll input[type=number] { .create-poll input[type=number] {
max-width: 3em; max-width: 3em;
background-color: var(--secondary-bg-color); background-color: var(--ternary-bg-color);
color: var(--main-accent-color); color: var(--main-accent-color);
} }
.create-poll input[type=text] { .create-poll input[type=text] {
display: block; display: block;
width: 100%; width: 100%;
background-color: var(--secondary-bg-color); background-color: var(--ternary-bg-color);
color: var(--main-accent-color); color: var(--main-accent-color);
} }
.create-poll input[type=text]:focus { .create-poll input[type=text]:focus {
@ -262,6 +340,42 @@ datewrapper time {
color: var(--main-text-color); color: var(--main-text-color);
} }
@media (max-width: 800px) {
#prompt {
grid-row: 2;
}
label[for=prompt] {
grid-row: 2;
}
.create-poll label[for=options] {
grid-row: 3;
}
.create-poll #options {
grid-row: 3;
}
.create-poll label[for=anonymous] {
grid-row: 4
}
.create-poll label[for=public] {
grid-row: 5
}
.create-poll label[for=max_options] {
grid-row: 6
}
.create-poll label[for=duration] {
grid-row: 7
}
#duration {
grid-row: 7;
}
.create-poll button[type=submit] {
grid-row: 8;
}
.create-poll .error {
grid-row: 1;
}
}
/* Footer */ /* Footer */
footer { footer {
display: flex; display: flex;
@ -276,10 +390,34 @@ footer .sourcecode svg {
stroke-width: 1.5em; stroke-width: 1.5em;
} }
/* Deal with the pill on iOS */
@supports (padding: env(safe-area-inset-left)) {
@media (max-width: 1000px) {
header {
padding-left: max(env(safe-area-inset-left, 20px), 8px);
padding-right: env(safe-area-inset-right, 20px);
padding-top: calc(env(safe-area-inset-top, 20px) + 8px);
}
footer {
padding-left: calc(env(safe-area-inset-left, 20px) + 8px);
padding-right: env(safe-area-inset-right, 20px);
padding-bottom: max(env(safe-area-inset-bottom, 20px), 8px);
}
main {
padding-left: max(env(safe-area-inset-left, 20px), 8px);
padding-right: max(env(safe-area-inset-right, 20px), 8px);
}
body {
margin: 0;
}
}
}
/* Poll grid */ /* Poll grid */
.poll-grid { .poll-grid {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center;
} }
.poll-grid .poll { .poll-grid .poll {
@ -289,6 +427,7 @@ footer .sourcecode svg {
margin: 8px; margin: 8px;
transition: all 0.2s; transition: all 0.2s;
cursor: pointer; cursor: pointer;
width: 500px;
} }
.poll-grid .poll:hover { .poll-grid .poll:hover {

View File

@ -127,13 +127,11 @@ if (array_key_exists('poll_created', $_GET) && $_GET['poll_created'] == 1) { ?>
<div class="option-responses" style="grid-row: <?= $row++ ?>;grid-column: 2;"> <div class="option-responses" style="grid-row: <?= $row++ ?>;grid-column: 2;">
<?php foreach ($option->respondent_ids as $res_id) { <?php foreach ($option->respondent_ids as $res_id) {
$u = $api->getUser($res_id, $user_args); ?> $u = $api->getUser($res_id, $user_args); ?>
<a href="https://pnut.io/@<?= $u->username ?>"> <a href="https://pnut.io/@<?= $u->username ?>"><img
<img
src="<?= $u->getAvatarUrl(20) ?>" src="<?= $u->getAvatarUrl(20) ?>"
srcset="<?= get_source_set($u, 20) ?>" srcset="<?= get_source_set($u, 20) ?>"
class="avatar" class="avatar"
title="@<?= $u->username ?>"> title="@<?= $u->username ?>"></a>
</a>
<?php } ?> <?php } ?>
</div> </div>
<?php } ?> <?php } ?>