Merge branch 'develop' into stable

This commit is contained in:
Jay Trees 2022-01-17 16:07:49 +01:00
commit 698df19d3e
20 changed files with 296 additions and 69 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
/vendor/*
!/vendor/autoload.php
!/vendor/embed
!/vendor/embed/embed
!/vendor/laminas

View file

@ -17,8 +17,8 @@ require '../../index.php';
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
if (isset($_GET['userid'])) {
$user = new User($_GET['userid']);
if (isset($_GET['userid']) || isset($_SESSION['user']['id'])) {
$user = isset($_GET['userid']) ? new User($_GET['userid']) : new User();
$wishlists = $user->getWishlists();
$wishlists = array_map(function ($wishlist) {
return array(
@ -32,6 +32,16 @@ switch ($_SERVER['REQUEST_METHOD']) {
$response['success'] = true;
}
break;
case 'DELETE':
parse_str(file_get_contents("php://input"), $_DELETE);
$database->query('DELETE FROM `wishlists`
WHERE `id` = ' . $_DELETE['wishlistID'] . '
;');
$response['success'] = true;
break;
}
echo json_encode($response);

View file

@ -1,4 +1,14 @@
/**
* Footer
*/
.ui.footer {
position: sticky;
top: 100%;
}
/**
* Modal
*/
.ui.modal > .actions {
text-align: inherit;
}

View file

@ -1,38 +1,47 @@
$(function() {
/**
* URL Parameter
*/
const urlParams = new URLSearchParams(window.location.search);
/**
* Fomantic UI
*/
$.fn.api.settings.api = {
'get wishlists' : '/includes/api/wishlists.php'
'get wishlists' : '/includes/api/wishlists.php',
'delete wishlist' : '/includes/api/wishlists.php'
};
$('.ui.dropdown.wishlists').dropdown({
filterRemoteData: true
});
wishlistRefresh();
});
function wishlistRefresh() {
$('.ui.dropdown.wishlists').api({
action: 'get wishlists',
method: 'GET',
data : {
userid: 1
},
on: 'now',
onResponse: function(response) {
console.log('onResponse');
// make some adjustments to response
return response;
},
successTest: function(response) {
console.log('successTest');
// test whether a JSON response is valid
return response.success || false;
},
onComplete: function(response, element, xhr) {
$('.ui.dropdown.wishlists').removeClass('loading');
},
onSuccess: function(response, element, xhr) {
$('.ui.dropdown.wishlists')
.dropdown({
values: response.results
$('.ui.dropdown.wishlists').dropdown({
values: response.results,
placeholder: 'No wishlist selected.'
})
.dropdown('set selected', response.results[0].value);
if (urlParams.has('wishlist')) {
$('.ui.dropdown.wishlists').dropdown('set selected', urlParams.get('wishlist'));
}
},
onFailure: function(response, element, xhr) {
console.log('onFailure');
@ -47,4 +56,4 @@ $(function() {
// navigated to a new page, CORS issue, or user canceled request
}
});
});
}

View file

@ -0,0 +1,9 @@
$(function() {
$('.ui.form').form({
on: 'blur',
fields: {
email: 'email',
password: ['minLength[6]', 'empty'],
}
});
});

View file

@ -0,0 +1,75 @@
$(function() {
/**
* Delete Wishlist
*/
$('.ui.dropdown.wishlists').on('change', function() {
var wishlistValue = $('.ui.dropdown.wishlists').dropdown('get value');
$('[name="wishlist_delete_id"]').val(wishlistValue);
if (wishlistValue) {
$('.wishlist-view').removeClass('disabled');
$('.wishlist-delete button').removeClass('disabled');
} else {
$('.wishlist-view').addClass('disabled');
$('.wishlist-delete button').addClass('disabled');
}
});
$('.wishlist-delete').on('submit', function(event) {
var wishlistValue = $('.ui.dropdown.wishlists').dropdown('get value');
if (wishlistValue) {
$('body')
.modal({
title: 'Really delete?',
class: 'tiny',
content: 'Do you really want to delete the wishlist <strong>' + $('.ui.dropdown.wishlists').dropdown('get text') + '</strong>?',
actions: [
{
text: 'Yes, delete',
class: 'approve red'
},
{
text: 'No, keep',
class: 'deny'
},
],
onApprove: function() {
$('.ui.dropdown.wishlists').api({
action: 'delete wishlist',
method: 'DELETE',
data: {
wishlistID: wishlistValue
},
on: 'now',
onResponse: function(response) {
return response;
},
successTest: function(response) {
return response.success || false;
},
onComplete: function(response, element, xhr) {
},
onSuccess: function(response, element, xhr) {
wishlistRefresh();
},
onFailure: function(response, element, xhr) {
},
onError: function(errorMessage, element, xhr) {
},
onAbort: function(errorMessage, element, xhr) {
}
});
}
})
.modal('show');
}
event.preventDefault();
});
});

View file

@ -14,8 +14,13 @@ class Options
{
public bool $updateAvailable = false;
public string $version;
public function __construct(private Database $database)
{
$this->version = $this->getOption('version')
? $this->getOption('version')
: '0.1.0';
}
public function getOption(string $key): string

View file

@ -89,6 +89,15 @@ class Page
$scriptDefault = 'includes/assets/js/default.js';
$scriptDefaultModified = filemtime($scriptDefault);
echo '<script defer src="' . $scriptDefault . '?m=' . $scriptDefaultModified . '"></script>';
/** Page */
$scriptPage = 'includes/assets/js/' . $this->name . '.js';
if (file_exists($scriptPage)) {
$scriptPageModified = filemtime($scriptPage);
echo '<script defer src="' . $scriptPage . '?m=' . $scriptPageModified . '"></script>';
}
?>
<title><?= $this->title ?> - wishthis</title>
@ -177,6 +186,14 @@ class Page
<div class="sixteen wide column">
<h4 class="ui inverted header">wishthis</h4>
<div class="ui inverted link list">
<?php
global $options;
echo 'v' . $options->version;
?>
</div>
<div class="ui inverted link list">
<a class="item" href="https://github.com/grandeljay/wishthis" target="_blank"><i class="big github icon"></i></a>
</div>

View file

@ -66,7 +66,7 @@ class User
$products = $database->query(
'SELECT *
FROM products
WHERE wishlist = ' . $this->id . ';'
WHERE wishlist = ' . $wishlist . ';'
)->fetchAll();
return $products;

View file

@ -15,8 +15,10 @@ $page->navigation();
<main>
<div class="ui container">
<h1 class="ui header"><?= $page->title ?></h1>
<div class="ui segment">
<h1 class="ui header">Welcome to wishthis</h1>
<h2 class="ui header">Welcome to wishthis</h2>
<p>
wishthis is a simple, intuitive and modern plattform to create,
manage and view your wishes for any kind of occasion.

View file

@ -99,40 +99,42 @@ switch ($step) {
* Users
*/
$database->query('CREATE TABLE `users` (
`id` int AUTO_INCREMENT,
`id` int PRIMARY KEY AUTO_INCREMENT,
`email` varchar(64) NOT NULL UNIQUE,
`password` varchar(128) NOT NULL,
PRIMARY KEY (id)
`password` varchar(128) NOT NULL
);');
/**
* Wishlists
*/
$database->query('CREATE TABLE `wishlists` (
`id` int AUTO_INCREMENT,
`id` int PRIMARY KEY AUTO_INCREMENT,
`user` int NOT NULL,
`name` varchar(128) NOT NULL,
PRIMARY KEY (id)
FOREIGN KEY (`user`)
REFERENCES `users` (`id`)
ON DELETE CASCADE
);');
/**
* Products
*/
$database->query('CREATE TABLE `products` (
`id` int NOT NULL AUTO_INCREMENT,
`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,
`wishlist` int NOT NULL,
`url` VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
FOREIGN KEY (`wishlist`)
REFERENCES `wishlists` (`id`)
ON DELETE CASCADE
);');
/**
* Options
*/
$database->query('CREATE TABLE `options` (
`id` int AUTO_INCREMENT,
`id` int PRIMARY KEY AUTO_INCREMENT,
`key` varchar(64) NOT NULL UNIQUE,
`value` varchar(128) NOT NULL,
PRIMARY KEY (id)
`value` varchar(128) NOT NULL
);');
$database->query('INSERT INTO `options`
@ -152,5 +154,3 @@ switch ($step) {
<?php
break;
}
$page->footer();

View file

@ -30,9 +30,9 @@ $page->navigation();
?>
<main>
<div class="ui container">
<div class="ui segment">
<h1 class="ui header">Login</h1>
<h1 class="ui header"><?= $page->title ?></h1>
<div class="ui segment">
<form class="ui form" method="post">
<div class="field">
<label>Email</label>

30
includes/pages/logout.php Normal file
View file

@ -0,0 +1,30 @@
<?php
/**
* logout.php
*
* @author Jay Trees <github.jay@grandel.anonaddy.me>
*/
use wishthis\Page;
$page = new page(__FILE__, 'Logout');
session_destroy();
$page->header();
$page->navigation();
?>
<main>
<div class="ui container">
<h1 class="ui header"><?= $page->title ?></h1>
<div class="ui segment">
<h2 class="ui header">Goodbye</h2>
<p>You have been logged out.</p>
</div>
</div>
</main>
<?php
$page->footer();

View file

@ -16,7 +16,7 @@ if (isset($_POST['email'], $_POST['password'])) {
("' . $_POST['email'] . '", "' . sha1($_POST['password']) . '")
;');
header('Location: ?page=login');
header('Location: /?page=login');
die();
}
@ -26,7 +26,7 @@ $page->navigation();
<main>
<div class="ui container">
<div class="ui segment">
<h1 class="ui header">Register</h1>
<h1 class="ui header"><?= $page->title ?></h1>
<form class="ui form" method="post">
<div class="field">
@ -38,6 +38,8 @@ $page->navigation();
<input type="password" name="password" />
</div>
<div class="ui error message"></div>
<input class="ui primary button" type="submit" value="Register" />
</form>
</div>

View file

@ -16,9 +16,7 @@ if (isset($_POST['name'])) {
(' . $_SESSION['user']['id'] . ', "' . $_POST['name'] . '")
;');
$_SESSION['user'] = $user;
header('Location: ?page=home');
header('Location: /?page=wishlist-product-add');
die();
}
@ -27,8 +25,9 @@ $page->navigation();
?>
<main>
<div class="ui container">
<h1 class="ui header"><?= $page->title ?></h1>
<div class="ui segment">
<h1 class="ui header">Create a wishlist</h1>
<form class="ui form" method="post">
<div class="field">
<label>Name</label>

View file

@ -23,7 +23,7 @@ $user = new User();
<main>
<div class="ui container">
<div class="ui segment">
<h1 class="ui header">Add a product</h1>
<h1 class="ui header"><?= $page->title ?></h1>
<form class="ui form" method="post">
<div class="field">

View file

@ -15,17 +15,31 @@ $page->navigation();
$products = array();
/**
* Get wishlist products
*/
if (isset($_GET['wishlist'])) {
$user = new User();
$wishlist = $_GET['wishlist'];
$products = $user->getProducts($wishlist);
}
/**
* Delete wishlist
*/
if (isset($_POST['wishlist_delete_id'])) {
$database->query('DELETE FROM `wishlists`
WHERE id = ' . $_POST['wishlist_delete_id'] . '
;');
}
?>
<main>
<div class="ui container">
<h1 class="ui header"><?= $page->title ?></h1>
<div class="ui horizontal segments">
<div class="ui segment">
<h1 class="ui header">View wishlist</h1>
<h2 class="ui header">Wishlists</h2>
<p>Please select a wishlist to view.</p>
<form class="ui form" method="get">
@ -37,7 +51,7 @@ if (isset($_GET['wishlist'])) {
</select>
</div>
<input class="ui primary button" type="submit" value="View" />
<input class="ui primary button wishlist-view disabled" type="submit" value="View" />
</form>
</div>
@ -45,10 +59,19 @@ if (isset($_GET['wishlist'])) {
<h2 class="ui header">Options</h1>
<p>Wishlist related options.</p>
<button class="ui labeled icon button">
<button class="ui small labeled icon button disabled">
<i class="share icon"></i>
Share
</button>
<form class="ui form wishlist-delete" method="post" style="display: inline-block;">
<input type="hidden" name="wishlist_delete_id" />
<button class="ui small labeled red icon button disabled" type="submit">
<i class="trash icon"></i>
Delete
</button>
</form>
</div>
</div>
@ -118,8 +141,30 @@ if (isset($_GET['wishlist'])) {
<?php } ?>
</div>
<?php } else { ?>
<?php if (isset($_GET['wishlist'])) { ?>
<div class="ui icon message">
<i class="info circle icon"></i>
<div class="content">
<div class="header">
Empty
</div>
<p>The selected wishlist seems to be empty.</p>
<a class="ui mini button" href="/?page=wishlist-product-add">Add a product</a>
</div>
</div>
<?php } else { ?>
<div class="ui icon message">
<i class="info circle icon"></i>
<div class="content">
<div class="header">
No wishlist selected
</div>
<p>Select a wishlist to see it's products.</p>
</div>
</div>
<?php } ?>
<?php } ?>
</div>
</main>

View file

@ -73,9 +73,7 @@ if (!$options) {
* Update
*/
if ($options) {
$version_current = $options->getOption('version') ?? '0.0.0';
if (-1 === version_compare($version_current, $version_new)) {
if (-1 === version_compare($options->version, $version_new)) {
$options->updateAvailable = true;
}
}

56
package-lock.json generated
View file

@ -220,9 +220,9 @@
"integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg=="
},
"node_modules/@types/node": {
"version": "14.18.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.5.tgz",
"integrity": "sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A=="
"version": "14.18.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.6.tgz",
"integrity": "sha512-lrCEyAVs0sJ+uq5uPn2j1NkAHryhBA8Q1fP2hC2zRiOPyJBMB53ZsdmNX3yPo/sj29EH/3452h1DsIoPTiGELg=="
},
"node_modules/@types/vinyl": {
"version": "2.0.6",
@ -808,9 +808,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001299",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz",
"integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==",
"version": "1.0.30001300",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz",
"integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
@ -1434,9 +1434,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.4.44",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.44.tgz",
"integrity": "sha512-tHGWiUUmY7GABK8+DNcr474cnZDTzD8x1736SlDosVH8+/vRJeqfaIBAEHFtMjddz/0T4rKKYsxEc8BwQRdBpw=="
"version": "1.4.46",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.46.tgz",
"integrity": "sha512-UtV0xUA/dibCKKP2JMxOpDtXR74zABevuUEH4K0tvduFSIoxRVcYmQsbB51kXsFTX8MmOyWMt8tuZAlmDOqkrQ=="
},
"node_modules/end-of-stream": {
"version": "1.4.4",
@ -4732,14 +4732,22 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node_modules/node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-notifier": {
@ -7451,9 +7459,9 @@
"integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg=="
},
"@types/node": {
"version": "14.18.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.5.tgz",
"integrity": "sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A=="
"version": "14.18.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.6.tgz",
"integrity": "sha512-lrCEyAVs0sJ+uq5uPn2j1NkAHryhBA8Q1fP2hC2zRiOPyJBMB53ZsdmNX3yPo/sj29EH/3452h1DsIoPTiGELg=="
},
"@types/vinyl": {
"version": "2.0.6",
@ -7903,9 +7911,9 @@
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
},
"caniuse-lite": {
"version": "1.0.30001299",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz",
"integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw=="
"version": "1.0.30001300",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz",
"integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA=="
},
"chalk": {
"version": "1.1.3",
@ -8420,9 +8428,9 @@
}
},
"electron-to-chromium": {
"version": "1.4.44",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.44.tgz",
"integrity": "sha512-tHGWiUUmY7GABK8+DNcr474cnZDTzD8x1736SlDosVH8+/vRJeqfaIBAEHFtMjddz/0T4rKKYsxEc8BwQRdBpw=="
"version": "1.4.46",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.46.tgz",
"integrity": "sha512-UtV0xUA/dibCKKP2JMxOpDtXR74zABevuUEH4K0tvduFSIoxRVcYmQsbB51kXsFTX8MmOyWMt8tuZAlmDOqkrQ=="
},
"end-of-stream": {
"version": "1.4.4",
@ -11142,9 +11150,9 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}

7
vendor/autoload.php vendored Normal file
View file

@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit5f3db9fc1d0cf1dd6a77a1d84501b4b1::getLoader();