First cut of item-with-feed and list impl

- Add strict types to all files
- Convert many queries to document commands
This commit is contained in:
2024-06-02 22:14:19 -04:00
parent b88ad1f268
commit 93dd8e880f
35 changed files with 309 additions and 319 deletions

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
/**
* Bookmark Partial Handler
@@ -7,30 +7,17 @@
*/
use BitBadger\Documents\DocumentException;
use BitBadger\Documents\SQLite\Configuration;
use BitBadger\Documents\SQLite\Find;
use BitBadger\Documents\SQLite\Patch;
use FeedReaderCentral\Item;
use FeedReaderCentral\Key;
use FeedReaderCentral\Security;
use FeedReaderCentral\ItemWithFeed;
use FeedReaderCentral\Table;
include '../start.php';
Security::verifyUser();
FeedReaderCentral\Security::verifyUser();
$id = $_GET['id'];
// TODO: adapt query once "by fields" is available
$db = Configuration::dbConn();
$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)) {
$flag = match ($_GET['action']) {
@@ -40,15 +27,14 @@ if (key_exists('action', $_GET)) {
};
if (isset($flag)) {
try {
Patch::byId(Table::ITEM, $id, ['is_bookmarked' => $flag], $db);
Patch::byId(Table::ITEM, $id, ['is_bookmarked' => $flag]);
$item->is_bookmarked = $flag;
} catch (DocumentException $ex) {
add_error("$ex");
}
}
}
if (!$item = Find::byId(Table::ITEM, $id, Item::class)) not_found();
$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?>"

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
include '../../start.php';

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
include '../../start.php';

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
include '../../start.php';

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
include '../../start.php';

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
include '../../start.php';

View File

@@ -1,4 +1,5 @@
<?php
<?php declare(strict_types=1);
/**
* Add/Edit/Delete Feed Page
*
@@ -25,7 +26,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
Delete::byFields(Table::ITEM, [Field::EQ('feed_id', $feed->id)]);
Delete::byId(Table::FEED, $feed->id);
add_info('Feed &ldquo;' . htmlentities($feed->title) . '&rdquo; deleted successfully');
$db->close();
frc_redirect('/feeds');
} catch (DocumentException $ex) {
add_error("$ex");

View File

@@ -1,26 +1,24 @@
<?php
<?php declare(strict_types=1);
/**
* Feed Item List Page
*
* Lists items in a given feed (all, unread, or bookmarked)
*/
use BitBadger\Documents\SQLite\Configuration;
use FeedReaderCentral\Feed;
use FeedReaderCentral\ItemList;
use FeedReaderCentral\Security;
include '../../start.php';
Security::verifyUser();
FeedReaderCentral\Security::verifyUser();
if (!($feed = Feed::retrieveById($_GET['id']))) not_found();
$db = Configuration::dbConn();
$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']));
@@ -32,4 +30,3 @@ if ($list->itemType == '') {
}
$list->render();
page_foot();
$db->close();

View File

@@ -1,4 +1,5 @@
<?php
<?php declare(strict_types=1);
/**
* Feed Maintenance Page
*
@@ -12,12 +13,11 @@ use BitBadger\Documents\Query;
use BitBadger\Documents\SQLite\Custom;
use FeedReaderCentral\Feed;
use FeedReaderCentral\Key;
use FeedReaderCentral\Security;
use FeedReaderCentral\Table;
include '../start.php';
Security::verifyUser();
FeedReaderCentral\Security::verifyUser();
// TODO: adapt query when document list is done
$field = Field::EQ('user_id', $_SESSION[Key::USER_ID], '@user');

View File

@@ -1,4 +1,5 @@
<?php
<?php declare(strict_types=1);
/**
* Home Page
*
@@ -8,15 +9,15 @@
use BitBadger\Documents\SQLite\Configuration;
use FeedReaderCentral\Feed;
use FeedReaderCentral\ItemList;
use FeedReaderCentral\Security;
include '../start.php';
Security::verifyUser();
FeedReaderCentral\Security::verifyUser();
$db = Configuration::dbConn();
if (key_exists('refresh', $_GET)) {
$db = Configuration::dbConn();
$refreshResult = Feed::refreshAll($db);
$db->close();
if (key_exists('ok', $refreshResult)) {
add_info('All feeds refreshed successfully');
} else {
@@ -25,8 +26,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";
@@ -39,4 +40,3 @@ if ($list->itemType == 'Unread') {
echo '</h1>';
$list->render();
page_foot();
$db->close();

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
/**
* Item View Page
@@ -7,22 +7,19 @@
*/
use BitBadger\Documents\DocumentException;
use BitBadger\Documents\SQLite\Configuration;
use BitBadger\Documents\SQLite\Delete;
use BitBadger\Documents\SQLite\Patch;
use FeedReaderCentral\Item;
use FeedReaderCentral\Key;
use FeedReaderCentral\Security;
use FeedReaderCentral\ItemWithFeed;
use FeedReaderCentral\Table;
include '../start.php';
Security::verifyUser();
FeedReaderCentral\Security::verifyUser();
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
// "Keep as New" button sends a POST request to reset the is_read flag before going back to the item list
if (Item::retrieveByIdForUser($_POST['id'])) {
if (ItemWithFeed::existsById($_POST['id'])) {
Patch::byId(Table::ITEM, $_POST['id'], ['is_read' => 0]);
}
frc_redirect($_POST['from']);
@@ -35,7 +32,7 @@ $from = $_GET['from'] ?? '/';
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
try {
if (Item::retrieveByIdForUser($_GET['id'])) {
if (ItemWithFeed::existsById($_GET['id'])) {
Delete::byId(Table::ITEM, $_GET['id']);
}
} catch (DocumentException $ex) {
@@ -44,43 +41,29 @@ if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
frc_redirect($from);
}
// TODO: convert this query
$db = Configuration::dbConn();
$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 = ItemWithFeed::retrieveById($_GET['id'])) not_found();
if ($item) {
try {
Patch::byId(Table::ITEM, $_GET['id'], ['is_read' => 1], $db);
} catch (DocumentException $ex) {
add_error("$ex");
}
try {
Patch::byId(Table::ITEM, $_GET['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?>">
@@ -90,4 +73,3 @@ page_head(htmlentities("{$item['item_title']} | {$item['feed_title']}")); ?>
</form>
</article><?php
page_foot();
$db->close();

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
/**
* Item Search Page
@@ -6,20 +6,15 @@
* Search for items across all feeds
*/
use BitBadger\Documents\SQLite\Configuration;
use FeedReaderCentral\ItemList;
use FeedReaderCentral\Security;
include '../start.php';
Security::verifyUser();
FeedReaderCentral\Security::verifyUser();
$search = $_GET['search'] ?? '';
$items = $_GET['items'] ?? 'all';
$db = Configuration::dbConn();
if ($search != '') {
$list = ItemList::matchingSearch($search, $items == 'bookmarked', $db);
$list = FeedReaderCentral\ItemList::matchingSearch($search, $items == 'bookmarked');
}
page_head('Item Search'); ?>
@@ -46,4 +41,3 @@ page_head('Item Search'); ?>
} ?>
</article><?php
page_foot();
$db->close();

View File

@@ -1,4 +1,5 @@
<?php
<?php declare(strict_types=1);
/**
* User Log Off Page
*/

View File

@@ -1,4 +1,12 @@
<?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';
use FeedReaderCentral\Key;