Documents and Documentation (beta 1) (#23)
- Change to SQLite document store - Complete documentation on usage of Feed Reader Central - Update INSTALLING.md for new installation procedures Reviewed-on: #23
This commit was merged in pull request #23.
This commit is contained in:
+20
-28
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Bookmark Partial Handler
|
||||
@@ -6,43 +6,35 @@
|
||||
* This will display a button which will either add or remove a bookmark for a given item.
|
||||
*/
|
||||
|
||||
use BitBadger\PDODocument\{DocumentException, Patch};
|
||||
use FeedReaderCentral\{ItemWithFeed, Table};
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
FeedReaderCentral\Security::verifyUser();
|
||||
|
||||
$id = $_GET['id'];
|
||||
$id = key_exists('id', $_GET) ? (int)$_GET['id'] : -1;
|
||||
|
||||
$existsQuery = $db->prepare(
|
||||
'SELECT item.id FROM item INNER JOIN feed ON feed.id = item.feed_id WHERE item.id = :id AND feed.user_id = :user');
|
||||
$existsQuery->bindValue(':id', $id);
|
||||
$existsQuery->bindValue(':user', $_SESSION[Key::USER_ID]);
|
||||
$existsResult = $existsQuery->execute();
|
||||
$exists = $existsResult ? $existsResult->fetchArray(SQLITE3_ASSOC) : false;
|
||||
|
||||
if (!$exists) not_found();
|
||||
if (!$item = ItemWithFeed::retrieveById($id)) not_found();
|
||||
|
||||
if (key_exists('action', $_GET)) {
|
||||
if ($_GET['action'] == 'add') {
|
||||
$flag = 1;
|
||||
} elseif ($_GET['action'] == 'remove') {
|
||||
$flag = 0;
|
||||
}
|
||||
$flag = match ($_GET['action']) {
|
||||
'add' => 1,
|
||||
'remove' => 0,
|
||||
default => null
|
||||
};
|
||||
if (isset($flag)) {
|
||||
$update = $db->prepare('UPDATE item SET is_bookmarked = :flag WHERE id = :id');
|
||||
$update->bindValue(':id', $id);
|
||||
$update->bindValue(':flag', $flag);
|
||||
if (!$update->execute()) die(Data::error($db)['error']);
|
||||
try {
|
||||
Patch::byId(Table::ITEM, $id, ['is_bookmarked' => $flag]);
|
||||
$item->is_bookmarked = $flag;
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$bookQuery = $db->prepare('SELECT id, is_bookmarked FROM item WHERE id = :id');
|
||||
$bookQuery->bindValue(':id', $id);
|
||||
$bookResult = $bookQuery->execute();
|
||||
$bookmark = $bookResult ? $bookResult->fetchArray(SQLITE3_ASSOC) : ['id' => $id, 'is_bookmarked' => 0];
|
||||
|
||||
$action = $bookmark['is_bookmarked'] ? 'remove' : 'add';
|
||||
$icon = $bookmark['is_bookmarked'] ? 'added' : 'add'; ?>
|
||||
$action = $item->isBookmarked() ? 'remove' : 'add';
|
||||
$icon = $item->isBookmarked() ? 'added' : 'add'; ?>
|
||||
<button class="bookmark <?=$action?>" type=button role=button hx-patch="/bookmark?id=<?=$id?>&action=<?=$action?>"
|
||||
hx-target=this hx-swap=outerHTML hx-push-url=false title="<?=init_cap($action)?> Bookmark">
|
||||
<img src=/assets/bookmark-<?=$icon?>.png alt="<?=$action?> bookmark">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Feeds | Documentation'); ?>
|
||||
<h1>Feeds</h1>
|
||||
@@ -71,4 +71,3 @@ php-cli util/refresh.php all</pre>
|
||||
add <code>nice -n 1</code> (with a trailing space) before the path to the script.
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Documentation'); ?>
|
||||
<h1>Documentation Home</h1>
|
||||
@@ -31,4 +31,3 @@ page_head('Documentation'); ?>
|
||||
that can be performed via its command line interface.
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Items | Documentation'); ?>
|
||||
<h1>Items</h1>
|
||||
@@ -66,4 +66,3 @@ page_head('Items | Documentation'); ?>
|
||||
others; if the items seem to move around in the list after a refresh, this is likely the cause.
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Security Modes | Documentation'); ?>
|
||||
<h1>Configuring Security Modes</h1>
|
||||
@@ -59,4 +59,3 @@ page_head('Security Modes | Documentation'); ?>
|
||||
<p><code>php-cli util/user.php reset-single-password</code>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('About the CLI | Documentation'); ?>
|
||||
<h1>About the CLI</h1>
|
||||
@@ -21,4 +21,3 @@ page_head('About the CLI | Documentation'); ?>
|
||||
<p><code>php-cli util/some-process.php command option1 option2</code>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
+40
-34
@@ -1,70 +1,76 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Add/Edit/Delete Feed Page
|
||||
*
|
||||
* Allows users to add, edit, and delete feeds
|
||||
*/
|
||||
|
||||
use BitBadger\PDODocument\{Delete, DocumentException, Field};
|
||||
use FeedReaderCentral\{Feed, Security, Table};
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
$feedId = $_GET['id'] ?? '';
|
||||
$feedId = key_exists('id', $_GET) ? (int)$_GET['id'] : -1;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
|
||||
if (!($feed = Feed::retrieveById($feedId, $db))) not_found();
|
||||
$itemDelete = $db->prepare('DELETE FROM item WHERE feed_id = :feed');
|
||||
$itemDelete->bindValue(':feed', $feed['id']);
|
||||
if (!$itemDelete->execute()) add_error(Data::error($db)['error']);
|
||||
$feedDelete = $db->prepare('DELETE FROM feed WHERE id = :feed');
|
||||
$feedDelete->bindValue(':feed', $feed['id']);
|
||||
if ($feedDelete->execute()) {
|
||||
add_info('Feed “' . htmlentities($feed['title']) . '” deleted successfully');
|
||||
} else {
|
||||
add_error(Data::error($db)['error']);
|
||||
try {
|
||||
if (!($feed = Feed::retrieveById($feedId))) not_found();
|
||||
Delete::byFields(Table::ITEM, [Field::EQ('feed_id', $feed->id)]);
|
||||
Delete::byId(Table::FEED, $feed->id);
|
||||
add_info('Feed “' . htmlentities($feed->title) . '” deleted successfully');
|
||||
frc_redirect('/feeds');
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
}
|
||||
frc_redirect('/feeds');
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$isNew = $_POST['id'] == 'new';
|
||||
if ($isNew) {
|
||||
$result = Feed::add($_POST['url'], $db);
|
||||
} else {
|
||||
$toEdit = Feed::retrieveById($_POST['id'], $db);
|
||||
$result = $toEdit ? Feed::update($toEdit, $_POST['url'], $db) : ['error' => "Feed {$_POST['id']} not found"];
|
||||
try {
|
||||
$isNew = $_POST['id'] == '-1';
|
||||
if ($isNew) {
|
||||
$result = Feed::add($_POST['url']);
|
||||
} else {
|
||||
$feedId = (int)$_POST['id'];
|
||||
$toEdit = Feed::retrieveById($feedId);
|
||||
$result = $toEdit
|
||||
? Feed::update($toEdit, $_POST['url'])
|
||||
: ['error' => "Feed $feedId not found"];
|
||||
}
|
||||
if (key_exists('ok', $result)) {
|
||||
add_info('Feed saved successfully');
|
||||
frc_redirect('/feeds');
|
||||
}
|
||||
add_error($result['error']);
|
||||
$feedId = 'error';
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
}
|
||||
if (key_exists('ok', $result)) {
|
||||
add_info('Feed saved successfully');
|
||||
frc_redirect('/feeds');
|
||||
}
|
||||
add_error($result['error']);
|
||||
$feedId = 'error';
|
||||
}
|
||||
|
||||
if ($feedId == 'new') {
|
||||
if ($feedId == -1) {
|
||||
$title = 'Add RSS Feed';
|
||||
$feed = [ 'id' => $_GET['id'], 'url' => ''];
|
||||
$feed = new Feed(id: -1);
|
||||
} else {
|
||||
$title = 'Edit RSS Feed';
|
||||
if ($feedId == 'error') {
|
||||
$feed = ['id' => $_POST['id'] ?? '', 'url' => $_POST['url'] ?? ''];
|
||||
} elseif (!($feed = Feed::retrieveById((int) $feedId, $db))) not_found();
|
||||
$feed = new Feed(id: (int)$_POST['id'], url: $_POST['url'] ?? '');
|
||||
} elseif (!($feed = Feed::retrieveById((int)$feedId))) not_found();
|
||||
}
|
||||
|
||||
page_head($title); ?>
|
||||
<h1><?=$title?></h1>
|
||||
<article>
|
||||
<form method=POST action=/feed/ hx-post=/feed/>
|
||||
<input type=hidden name=id value=<?=$feed['id']?>>
|
||||
<input type=hidden name=id value=<?=$feed->id?>>
|
||||
<label>
|
||||
Feed URL
|
||||
<input type=url name=url required autofocus value="<?=$feed['url']?>">
|
||||
<input type=url name=url required autofocus value="<?=$feed->url?>">
|
||||
</label>
|
||||
<span class=break></span>
|
||||
<button type=submit>Save</button>
|
||||
</form>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
+13
-11
@@ -1,30 +1,32 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Feed Item List Page
|
||||
*
|
||||
* Lists items in a given feed (all, unread, or bookmarked)
|
||||
*/
|
||||
|
||||
use FeedReaderCentral\{Feed, ItemList};
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
FeedReaderCentral\Security::verifyUser();
|
||||
|
||||
if (!($feed = Feed::retrieveById($_GET['id'], $db))) not_found();
|
||||
$id = key_exists('id', $_GET) ? (int)$_GET['id'] : -1;
|
||||
if (!($feed = Feed::retrieveById($id))) not_found();
|
||||
|
||||
$list = match (true) {
|
||||
key_exists('unread', $_GET) => ItemList::unreadForFeed($feed['id'], $db),
|
||||
key_exists('bookmarked', $_GET) => ItemList::bookmarkedForFeed($feed['id'], $db),
|
||||
default => ItemList::allForFeed($feed['id'], $db)
|
||||
key_exists('unread', $_GET) => ItemList::unreadForFeed($feed->id),
|
||||
key_exists('bookmarked', $_GET) => ItemList::bookmarkedForFeed($feed->id),
|
||||
default => ItemList::allForFeed($feed->id)
|
||||
};
|
||||
|
||||
page_head(($list->itemType != '' ? "$list->itemType Items | " : '') . strip_tags($feed['title']));
|
||||
page_head(($list->itemType != '' ? "$list->itemType Items | " : '') . strip_tags($feed->title));
|
||||
if ($list->itemType == '') {
|
||||
echo '<h1>' . htmlentities($feed['title']) . '</h1>';
|
||||
echo '<h1>' . htmlentities($feed->title) . '</h1>';
|
||||
} else {
|
||||
echo '<h1 class=item_heading>' . htmlentities($feed['title']) . '</h1>';
|
||||
echo '<h1 class=item_heading>' . htmlentities($feed->title) . '</h1>';
|
||||
echo "<div class=item_published>$list->itemType Items</div>";
|
||||
}
|
||||
$list->render();
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
+33
-40
@@ -1,51 +1,44 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Feed Maintenance Page
|
||||
*
|
||||
* List feeds and provide links for maintenance actions
|
||||
*/
|
||||
|
||||
use BitBadger\PDODocument\{Custom, Field, Query};
|
||||
use BitBadger\PDODocument\Mapper\{ArrayMapper, DocumentMapper};
|
||||
use FeedReaderCentral\{Feed, Key, Table};
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
FeedReaderCentral\Security::verifyUser();
|
||||
|
||||
$feedQuery = $db->prepare('SELECT * FROM feed WHERE user_id = :user ORDER BY lower(title)');
|
||||
$feedQuery->bindValue(':user', $_SESSION[Key::USER_ID]);
|
||||
if (!($feedResult = $feedQuery->execute())) {
|
||||
add_error(Data::error($db)['error']);
|
||||
$field = Field::EQ('user_id', $_SESSION[Key::USER_ID], ':user');
|
||||
$feeds = Custom::list(Query\Find::byFields(Table::FEED, [$field]) . " ORDER BY lower(data->>'title')",
|
||||
$field->appendParameter([]), new DocumentMapper(Feed::class));
|
||||
|
||||
page_head('Your Feeds');
|
||||
echo '<h1>Your Feeds</h1><article><p class=action_buttons>' . hx_get('/feed/?id=-1', 'Add Feed') . '</p>';
|
||||
foreach ($feeds->items() as /** @var Feed $feed */ $feed) {
|
||||
$item = Table::ITEM;
|
||||
$counts = Custom::single(<<<SQL
|
||||
SELECT (SELECT COUNT(*) FROM $item WHERE data->>'feed_id' = :feed) AS total,
|
||||
(SELECT COUNT(*) FROM $item WHERE data->>'feed_id' = :feed AND data->>'is_read' = 0) AS unread,
|
||||
(SELECT COUNT(*) FROM $item WHERE data->>'feed_id' = :feed AND data->>'is_bookmarked' = 1) AS marked
|
||||
SQL, [':feed' => $feed->id], new ArrayMapper()) ?? ['total' => 0, 'unread' => 0, 'marked' => 0];
|
||||
echo '<p><strong>' . htmlentities($feed->title) . '</strong><br>'
|
||||
. '<span class=meta><em>Last Updated ' . date_time($feed->updated_on) . ' • '
|
||||
. 'As of ' . date_time($feed->checked_on) . '</em><br>' . hx_get("/feed/?id=$feed->id", 'Edit') . ' • '
|
||||
. 'Read ' . ($counts['unread'] > 0 ? hx_get("/feed/items?id=$feed->id&unread", 'Unread') : 'Unread')
|
||||
. " ({$counts['unread']}) | "
|
||||
. ($counts['total'] > 0 ? hx_get("/feed/items?id=$feed->id", 'All') : 'All') . " ({$counts['total']}) | "
|
||||
. ($counts['marked'] > 0 ? hx_get("/feed/items?id=$feed->id&bookmarked", 'Bookmarked') : 'Bookmarked')
|
||||
. " ({$counts['marked']}) • "
|
||||
. "<a href=/feed/?id=$feed->id hx-delete=/feed/?id=$feed->id "
|
||||
. ' hx-confirm="Are you sure you want to delete “' . htmlspecialchars($feed->title)
|
||||
. '”? This will remove the feed and all its items, including unread and bookmarked.">Delete</a>'
|
||||
. '</span>';
|
||||
}
|
||||
|
||||
page_head('Your Feeds'); ?>
|
||||
<h1>Your Feeds</h1>
|
||||
<article>
|
||||
<p class=action_buttons><?=hx_get('/feed/?id=new', 'Add Feed')?></p><?php
|
||||
if ($feedResult) {
|
||||
while ($feed = $feedResult->fetchArray(SQLITE3_ASSOC)) {
|
||||
$feedId = $feed['id'];
|
||||
$countQuery = $db->prepare(<<<'SQL'
|
||||
SELECT (SELECT COUNT(*) FROM item WHERE feed_id = :feed) AS total,
|
||||
(SELECT COUNT(*) FROM item WHERE feed_id = :feed AND is_read = 0) AS unread,
|
||||
(SELECT COUNT(*) FROM item WHERE feed_id = :feed AND is_bookmarked = 1) AS marked
|
||||
SQL);
|
||||
$countQuery->bindValue(':feed', $feed['id']);
|
||||
$countResult = $countQuery->execute();
|
||||
$counts = $countResult
|
||||
? $countResult->fetchArray(SQLITE3_ASSOC) : ['total' => 0, 'unread' => 0, 'marked' => 0]; ?>
|
||||
<p><strong><?=htmlentities($feed['title'])?></strong><br>
|
||||
<span class=meta><em>Last Updated <?=date_time($feed['updated_on'])?> •
|
||||
As of <?=date_time($feed['checked_on'])?></em><br>
|
||||
<?=hx_get("/feed/?id=$feedId", 'Edit')?> • Read
|
||||
<?=$counts['unread'] > 0 ? hx_get("/feed/items?id=$feedId&unread", 'Unread') : 'Unread'?>
|
||||
(<?=$counts['unread']?>) |
|
||||
<?=$counts['total'] > 0 ? hx_get("/feed/items?id=$feedId", 'All') : 'All'?> (<?=$counts['total']?>) |
|
||||
<?=$counts['marked'] > 0 ? hx_get("/feed/items?id=$feedId&bookmarked", 'Bookmarked') : 'Bookmarked'?>
|
||||
(<?=$counts['marked']?>) •
|
||||
<a href=/feed/?id=<?=$feedId?> hx-delete=/feed/?id=<?=$feedId?>
|
||||
hx-confirm="Are you sure you want to delete “<?=htmlentities($feed['title'], ENT_QUOTES)?>”? This will remove the feed and all its items, including unread and bookmarked.">Delete</a>
|
||||
</span><?php
|
||||
}
|
||||
} ?>
|
||||
</article><?php
|
||||
echo '</article>';
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Home Page
|
||||
*
|
||||
* Displays a list of unread or bookmarked items for the current user
|
||||
*/
|
||||
|
||||
use FeedReaderCentral\{Feed, ItemList};
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
FeedReaderCentral\Security::verifyUser();
|
||||
|
||||
if (key_exists('refresh', $_GET)) {
|
||||
$refreshResult = Feed::refreshAll($db);
|
||||
$refreshResult = Feed::refreshAll();
|
||||
if (key_exists('ok', $refreshResult)) {
|
||||
add_info('All feeds refreshed successfully');
|
||||
} else {
|
||||
@@ -20,8 +22,8 @@ if (key_exists('refresh', $_GET)) {
|
||||
}
|
||||
|
||||
$list = match (true) {
|
||||
key_exists('bookmarked', $_GET) => ItemList::allBookmarked($db),
|
||||
default => ItemList::allUnread($db)
|
||||
key_exists('bookmarked', $_GET) => ItemList::allBookmarked(),
|
||||
default => ItemList::allUnread()
|
||||
};
|
||||
$title = "Your $list->itemType Items";
|
||||
|
||||
@@ -34,4 +36,3 @@ if ($list->itemType == 'Unread') {
|
||||
echo '</h1>';
|
||||
$list->render();
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
+35
-57
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Item View Page
|
||||
@@ -6,85 +6,64 @@
|
||||
* Retrieves and displays an item from a feed belonging to the current user
|
||||
*/
|
||||
|
||||
use BitBadger\PDODocument\{Delete, DocumentException, Patch};
|
||||
use FeedReaderCentral\{ItemWithFeed, Table};
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
FeedReaderCentral\Security::verifyUser();
|
||||
|
||||
$id = match (true) {
|
||||
key_exists('id', $_POST) => (int)$_POST['id'],
|
||||
key_exists('id', $_GET) => (int)$_GET['id'],
|
||||
default => -1
|
||||
};
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// "Keep as New" button sends a POST request to reset the is_read flag before going back to the list of unread items
|
||||
$isValidQuery = $db->prepare(<<<'SQL'
|
||||
SELECT COUNT(*)
|
||||
FROM item INNER JOIN feed ON feed.id = item.feed_id
|
||||
WHERE item.id = :id AND feed.user_id = :user
|
||||
SQL);
|
||||
$isValidQuery->bindValue(':id', $_POST['id']);
|
||||
$isValidQuery->bindValue(':user', $_SESSION[Key::USER_ID]);
|
||||
$isValidResult = $isValidQuery->execute();
|
||||
if ($isValidResult && $isValidResult->fetchArray(SQLITE3_NUM)[0] == 1) {
|
||||
$keepUnread = $db->prepare('UPDATE item SET is_read = 0 WHERE id = :id');
|
||||
$keepUnread->bindValue(':id', $_POST['id']);
|
||||
$keepUnread->execute();
|
||||
try {
|
||||
// "Keep as New" button sends a POST request to reset the is_read flag before going back to the item list
|
||||
if (ItemWithFeed::existsById($id)) {
|
||||
Patch::byId(Table::ITEM, $id, ['is_read' => 0]);
|
||||
}
|
||||
frc_redirect($_POST['from']);
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
}
|
||||
$db->close();
|
||||
frc_redirect($_POST['from']);
|
||||
}
|
||||
|
||||
$from = $_GET['from'] ?? '/';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
|
||||
$deleteQuery = $db->prepare(<<<'SQL'
|
||||
DELETE FROM item
|
||||
WHERE id IN (
|
||||
SELECT item.id
|
||||
FROM item INNER JOIN feed ON feed.id = item.feed_id
|
||||
WHERE item.id = :id
|
||||
AND feed.user_id = :user)
|
||||
SQL);
|
||||
$deleteQuery->bindValue(':id', $_GET['id']);
|
||||
$deleteQuery->bindValue(':user', $_SESSION[Key::USER_ID]);
|
||||
if ($deleteQuery->execute()) {
|
||||
add_info('Item deleted');
|
||||
} else {
|
||||
add_error(Data::error($db)['error']);
|
||||
try {
|
||||
if (ItemWithFeed::existsById($id)) Delete::byId(Table::ITEM, $id);
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
}
|
||||
$db->close();
|
||||
frc_redirect($from);
|
||||
}
|
||||
|
||||
$query = $db->prepare(<<<'SQL'
|
||||
SELECT item.title AS item_title, item.item_link, item.published_on, item.updated_on, item.content,
|
||||
feed.title AS feed_title
|
||||
FROM item INNER JOIN feed ON feed.id = item.feed_id
|
||||
WHERE item.id = :id
|
||||
AND feed.user_id = :user
|
||||
SQL);
|
||||
$query->bindValue(':id', $_GET['id']);
|
||||
$query->bindValue(':user', $_SESSION[Key::USER_ID]);
|
||||
$result = $query->execute();
|
||||
$item = $result ? $result->fetchArray(SQLITE3_ASSOC) : false;
|
||||
|
||||
if ($item) {
|
||||
$markRead = $db->prepare('UPDATE item SET is_read = 1 WHERE id = :id');
|
||||
$markRead->bindValue(':id', $_GET['id']);
|
||||
$markRead->execute();
|
||||
if (!$item = ItemWithFeed::retrieveById($id)) not_found();
|
||||
try {
|
||||
Patch::byId(Table::ITEM, $id, ['is_read' => 1]);
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
}
|
||||
|
||||
$published = date_time($item['published_on']);
|
||||
$updated = isset($item['updated_on']) ? date_time($item['updated_on']) : null;
|
||||
$published = date_time($item->published_on);
|
||||
$updated = isset($item->updated_on) ? date_time($item->updated_on) : null;
|
||||
|
||||
page_head(htmlentities("{$item['item_title']} | {$item['feed_title']}")); ?>
|
||||
page_head(htmlentities("$item->title | {$item->feed->title}")); ?>
|
||||
<h1 class=item_heading>
|
||||
<span class=bookmark hx-get="/bookmark?id=<?=$_GET['id']?>" hx-trigger=load hx-target=this hx-swap=outerHTML
|
||||
hx-push-url=false></span>
|
||||
<a href="<?=$item['item_link']?>" target=_blank rel=noopener><?=strip_tags($item['item_title'])?></a><br>
|
||||
<a href="<?=$item->item_link?>" target=_blank rel=noopener><?=strip_tags($item->title)?></a><br>
|
||||
</h1>
|
||||
<div class=item_published>
|
||||
From <strong><?=htmlentities($item['feed_title'])?></strong><br>
|
||||
Published <?=date_time($item['published_on'])?><?=$updated && $updated != $published ? " (Updated $updated)" : ''?>
|
||||
From <strong><?=htmlentities($item->feed->title)?></strong><br>
|
||||
Published <?=date_time($item->published_on)?><?=$updated && $updated != $published ? " (Updated $updated)" : ''?>
|
||||
</div>
|
||||
<article>
|
||||
<div class=item_content><?=str_replace('<a ', '<a target=_blank rel=noopener ', $item['content'])?></div>
|
||||
<div class=item_content><?=str_replace('<a ', '<a target=_blank rel=noopener ', $item->content)?></div>
|
||||
<form class=action_buttons action=/item method=POST hx-post=/item>
|
||||
<input type=hidden name=id value=<?=$_GET['id']?>>
|
||||
<input type=hidden name=from value="<?=$from?>">
|
||||
@@ -94,4 +73,3 @@ page_head(htmlentities("{$item['item_title']} | {$item['feed_title']}")); ?>
|
||||
</form>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Item Search Page
|
||||
@@ -8,14 +8,13 @@
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
FeedReaderCentral\Security::verifyUser();
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
$items = $_GET['items'] ?? 'all';
|
||||
|
||||
if ($search != '') {
|
||||
$list = ItemList::matchingSearch($search, $items == 'bookmarked', $db);
|
||||
$list = FeedReaderCentral\ItemList::matchingSearch($search, $items == 'bookmarked');
|
||||
}
|
||||
|
||||
page_head('Item Search'); ?>
|
||||
@@ -42,4 +41,3 @@ page_head('Item Search'); ?>
|
||||
} ?>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* User Log Off Page
|
||||
*/
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
if (key_exists(Key::USER_ID, $_SESSION)) session_destroy();
|
||||
if (key_exists(FeedReaderCentral\Key::USER_ID, $_SESSION)) session_destroy();
|
||||
|
||||
frc_redirect('/');
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* User Log On Page
|
||||
*
|
||||
* Accepts the user's e-mail address (multi-user) and password (multi-user or single-user-with-password) and attempts
|
||||
* to log them on to Feed Reader Central
|
||||
*/
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
use FeedReaderCentral\{Key, Security};
|
||||
|
||||
Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
// Users already logged on have no need of this page
|
||||
if (key_exists(Key::USER_ID, $_SESSION)) frc_redirect('/');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
Security::logOnUser($_POST['email'] ?? '', $_POST['password'], $_POST['returnTo'] ?? null, $db);
|
||||
Security::logOnUser($_POST['email'] ?? '', $_POST['password'], $_POST['returnTo'] ?? null);
|
||||
// If we're still here, something didn't work; preserve the returnTo parameter
|
||||
$_GET['returnTo'] = $_POST['returnTo'];
|
||||
}
|
||||
@@ -37,4 +46,3 @@ page_head('Log On'); ?>
|
||||
</form>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
||||
Reference in New Issue
Block a user