From 7414d3844e7893d50a37f3b8415400b5eaae471e Mon Sep 17 00:00:00 2001 From: "J. King" Date: Tue, 27 Dec 2022 14:20:13 -0500 Subject: [PATCH] Fix up the rest of the subscriptionUpdate function --- lib/Database.php | 96 +++++++++-------------------- lib/Feed.php | 14 ----- tests/cases/Database/SeriesFeed.php | 15 ----- 3 files changed, 29 insertions(+), 96 deletions(-) diff --git a/lib/Database.php b/lib/Database.php index bee2226..c28571f 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -1211,21 +1211,21 @@ class Database { /** Attempts to refresh a subscribed newsfeed, returning an indication of success * * @param string|null $user The user whose subscribed newsfeed is to be updated; this may be null to facilitate refreshing feeds from the CLI - * @param integer $id The numerical identifier of the subscription to refresh + * @param integer $subID The numerical identifier of the subscription to refresh * @param boolean $throwError Whether to throw an exception on failure in addition to storing error information in the database */ - public function subscriptionUpdate(?string $user, $id, bool $throwError = false): bool { + public function subscriptionUpdate(?string $user, $subID, bool $throwError = false): bool { // check to make sure the feed exists - if (!V::id($id)) { + if (!V::id($subID)) { throw new Db\ExceptionInput("typeViolation", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id, 'type' => "int > 0"]); } $f = $this->db->prepareArray( "SELECT - url, las_mod as modified, etag, err_count, scrape as scrapers + url, las_mod as modified, etag, err_count, scrape as scrapers, keep_rule, block_rule FROM arsse_subscriptions where id = ?", ["int"] - )->run($id)->getRow(); + )->run($subID)->getRow(); if (!$f) { throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id]); } @@ -1235,10 +1235,10 @@ class Database { // here. When an exception is thrown it should update the database with the // error instead of failing; if other exceptions are thrown, we should simply roll back try { - $feed = new Feed((int) $id, $f['url'], (string) Date::transform($f['modified'], "http", "sql"), $f['etag'], $f['username'], $f['password'], $scrape); + $feed = new Feed((int) $subID, $f['url'], (string) Date::transform($f['modified'], "http", "sql"), $f['etag'], $f['username'], $f['password'], $scrape); if (!$feed->modified) { // if the feed hasn't changed, just compute the next fetch time and record it - $this->db->prepare("UPDATE arsse_subscriptions SET updated = CURRENT_TIMESTAMP, next_fetch = ? WHERE id = ?", 'datetime', 'int')->run($feed->nextFetch, $id); + $this->db->prepare("UPDATE arsse_subscriptions SET updated = CURRENT_TIMESTAMP, next_fetch = ? WHERE id = ?", 'datetime', 'int')->run($feed->nextFetch, $subID); return false; } } catch (Feed\Exception $e) { @@ -1246,10 +1246,10 @@ class Database { $this->db->prepareArray( "UPDATE arsse_subscriptions SET updated = CURRENT_TIMESTAMP, next_fetch = ?, err_count = err_count + 1, err_msg = ? WHERE id = ?", ['datetime', 'str', 'int'] - )->run(Feed::nextFetchOnError($f['err_count']), $e->getMessage(), $id); + )->run(Feed::nextFetchOnError($f['err_count']), $e->getMessage(), $subID); if ($throwError) { throw $e; - } + } return false; } //prepare the necessary statements to perform the update @@ -1260,19 +1260,29 @@ class Database { } if (sizeof($feed->newItems)) { $qInsertArticle = $this->db->prepareArray( - "INSERT INTO arsse_articles(url,title,author,published,edited,guid,content,url_title_hash,url_content_hash,title_content_hash,feed,content_scraped) values(?,?,?,?,?,?,?,?,?,?,?,?)", - ["str", "str", "str", "datetime", "datetime", "str", "str", "str", "str", "str", "int", "str"] + "INSERT INTO arsse_articles(url,title,author,published,edited,guid,url_title_hash,url_content_hash,title_content_hash,subscription,hidden) values(?,?,?,?,?,?,?,?,?,?,?)", + ["str", "str", "str", "datetime", "datetime", "str", "str", "str", "str", "int", "bool"] ); } if (sizeof($feed->changedItems)) { $qDeleteEnclosures = $this->db->prepare("DELETE FROM arsse_enclosures WHERE article = ?", 'int'); $qDeleteCategories = $this->db->prepare("DELETE FROM arsse_categories WHERE article = ?", 'int'); - $qClearReadMarks = $this->db->prepare("UPDATE arsse_marks SET \"read\" = 0, modified = CURRENT_TIMESTAMP WHERE article = ? and \"read\" = 1", 'int'); $qUpdateArticle = $this->db->prepareArray( - "UPDATE arsse_articles SET url = ?, title = ?, author = ?, published = ?, edited = ?, modified = CURRENT_TIMESTAMP, guid = ?, content = ?, url_title_hash = ?, url_content_hash = ?, title_content_hash = ?, content_scraped = ? WHERE id = ?", - ["str", "str", "str", "datetime", "datetime", "str", "str", "str", "str", "str", "str", "int"] + "UPDATE arsse_articles SET \"read\" = 0, hidden = ?, url = ?, title = ?, author = ?, published = ?, edited = ?, modified = CURRENT_TIMESTAMP, guid = ?, content = ?, url_title_hash = ?, url_content_hash = ?, title_content_hash = ?, content_scraped = ? WHERE id = ?", + ["bool", "str", "str", "str", "datetime", "datetime", "str", "str", "str", "str", "str", "str", "int"] ); } + // prepare the keep and block rules + try { + $keep = Rule::prep($f['keep_rule'] ?? ""); + } catch (RuleException $e) { + $keep = ""; + } + try { + $block = Rule::prep($f['block_rule'] ?? ""); + } catch (RuleException $e) { + $block = ""; + } // determine if the feed icon needs to be updated, and update it if appropriate $tr = $this->db->begin(); $icon = null; @@ -1299,12 +1309,11 @@ class Database { $article->publishedDate, $article->updatedDate, $article->id, - $article->content, $article->urlTitleHash, $article->urlContentHash, $article->titleContentHash, - $feedID, - $article->scrapedContent ?? null + $subID, + !Rule::apply($keep, $block, $article->title, $article->categories) )->lastId(); // note the new ID for later use $articleMap[$k] = $articleID; @@ -1322,6 +1331,7 @@ class Database { // next update existing artricles which have been edited foreach ($feed->changedItems as $articleID => $article) { $qUpdateArticle->run( + !Rule::apply($keep, $block, $article->title, $article->categories), $article->url, $article->title, $article->author, @@ -1346,34 +1356,10 @@ class Database { } // assign a new edition ID to this version of the article $qInsertEdition->run($articleID); - $qClearReadMarks->run($articleID); - } - // hide or unhide any filtered articles - foreach ($feed->filteredItems as $user => $filterData) { - $hide = []; - $unhide = []; - foreach ($filterData['new'] as $index => $keep) { - if (!$keep) { - $hide[] = $articleMap[$index]; - } - } - foreach ($filterData['changed'] as $article => $keep) { - if (!$keep) { - $hide[] = $article; - } else { - $unhide[] = $article; - } - } - if ($hide) { - $this->articleMark($user, ['hidden' => true], (new Context)->articles($hide), false); - } - if ($unhide) { - $this->articleMark($user, ['hidden' => false], (new Context)->articles($unhide), false); - } } // lastly update the feed database itself with updated information. $this->db->prepareArray( - "UPDATE arsse_feeds SET title = ?, source = ?, updated = CURRENT_TIMESTAMP, modified = ?, etag = ?, err_count = 0, err_msg = '', next_fetch = ?, size = ?, icon = ? WHERE id = ?", + "UPDATE arsse_subscriptions SET feed_title = ?, source = ?, updated = CURRENT_TIMESTAMP, last_mod = ?, etag = ?, err_count = 0, err_msg = '', next_fetch = ?, size = ?, icon = ? WHERE id = ?", ["str", "str", "datetime", "strict str", "datetime", "int", "int", "int"] )->run( $feed->data->title, @@ -1383,7 +1369,7 @@ class Database { $feed->nextFetch, sizeof($feed->data->items), $icon, - $feedID + $subID ); $tr->commit(); return true; @@ -1410,30 +1396,6 @@ class Database { return $out; } - /** Retrieves the set of filters users have applied to a given feed - * - * The result is an associative array whose keys are usernames, values - * being an array in turn with the following keys: - * - * - "keep": The "keep" rule as a prepared pattern; any articles which fail to match this rule are hidden - * - "block": The block rule as a prepared pattern; any articles which match this rule are hidden - */ - public function feedRulesGet(int $feedID): array { - $out = []; - $result = $this->db->prepare("SELECT owner, coalesce(keep_rule, '') as keep, coalesce(block_rule, '') as block from arsse_subscriptions where feed = ? and (coalesce(keep_rule, '') || coalesce(block_rule, '')) <> '' order by owner", "int")->run($feedID); - foreach ($result as $row) { - try { - $keep = Rule::prep($row['keep']); - $block = Rule::prep($row['block']); - } catch (RuleException $e) { - // invalid rules should not normally appear in the database, but it's possible - continue; - } - $out[$row['owner']] = ['keep' => $keep, 'block' => $block]; - } - return $out; - } - /** Retrieves various identifiers for the latest $count articles in the given newsfeed. The identifiers are: * * - "id": The database record key for the article diff --git a/lib/Feed.php b/lib/Feed.php index ce4ab4c..615e1ed 100644 --- a/lib/Feed.php +++ b/lib/Feed.php @@ -452,18 +452,4 @@ class Feed { } } } - - protected function computeFilterRules(int $feedID): void { - $rules = Arsse::$db->feedRulesGet($feedID); - foreach ($rules as $user => $r) { - $stats = ['new' => [], 'changed' => []]; - foreach ($this->newItems as $index => $item) { - $stats['new'][$index] = Rule::apply($r['keep'], $r['block'], $item->title, $item->categories); - } - foreach ($this->changedItems as $index => $item) { - $stats['changed'][$index] = Rule::apply($r['keep'], $r['block'], $item->title, $item->categories); - } - $this->filteredItems[$user] = $stats; - } - } } diff --git a/tests/cases/Database/SeriesFeed.php b/tests/cases/Database/SeriesFeed.php index 2a428cf..87c1c0e 100644 --- a/tests/cases/Database/SeriesFeed.php +++ b/tests/cases/Database/SeriesFeed.php @@ -147,21 +147,6 @@ trait SeriesFeed { $this->assertResult([['id' => 1]], Arsse::$db->feedMatchIds(1, ['e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda'])); // this ID appears in both feed 1 and feed 2; only one result should be returned } - /** @dataProvider provideFilterRules */ - public function testGetRules(int $in, array $exp): void { - $this->assertSame($exp, Arsse::$db->feedRulesGet($in)); - } - - public function provideFilterRules(): iterable { - return [ - [1, ['jane.doe@example.com' => ['keep' => "`^(?i)[a-z]+`u", 'block' => "`3|6`u"], 'john.doe@example.com' => ['keep' => "", 'block' => "`^Sport$`u"]]], - [2, []], - [3, ['john.doe@example.com' => ['keep' => '`\w+`u', 'block' => ""]]], - [4, []], - [5, ['john.doe@example.com' => ['keep' => "", 'block' => "`and/or`u"]]], - ]; - } - public function testUpdateAFeed(): void { // update a valid feed with both new and changed items Arsse::$db->feedUpdate(1);