From d8407330a0c478b4add975555492934747355f8b Mon Sep 17 00:00:00 2001 From: "J. King" Date: Tue, 26 Mar 2019 16:51:44 -0400 Subject: [PATCH] Add a function to get when feeds were last updated This is an optimization for Fever, which returns this information with every API call. --- lib/Database.php | 20 ++++++++++++++++- tests/cases/Database/SeriesSubscription.php | 24 ++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/Database.php b/lib/Database.php index 86bb8b35..24869078 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -10,7 +10,6 @@ use JKingWeb\DrUUID\UUID; use JKingWeb\Arsse\Db\Statement; use JKingWeb\Arsse\Misc\Query; use JKingWeb\Arsse\Context\Context; -use JKingWeb\Arsse\Context\ExclusionContext; use JKingWeb\Arsse\Misc\Date; use JKingWeb\Arsse\Misc\ValueInfo; @@ -751,6 +750,8 @@ class Database { arsse_subscriptions.feed as feed, url,favicon,source,folder,pinned,err_count,err_msg,order_type,added, arsse_feeds.updated as updated, + arsse_feeds.modified as edited, + arsse_subscriptions.modified as modified, topmost.top as top_folder, coalesce(arsse_subscriptions.title, arsse_feeds.title) as title, (articles - marked) as unread @@ -946,6 +947,23 @@ class Database { return (string) $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->getValue(); } + /** Returns the time at which any of a user's subscriptions (or a specific subscription) was last refreshed, as a DateTimeImmutable object */ + public function subscriptionRefreshed(string $user, int $id = null) { + if (!Arsse::$user->authorize($user, __FUNCTION__)) { + throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); + } + $q = new Query("SELECT max(arsse_feeds.updated) from arsse_feeds join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id"); + $q->setWhere("arsse_subscriptions.owner = ?", "str", $user); + if ($id) { + $q->setWhere("arsse_subscriptions.id = ?", "int", $id); + } + $out = $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->getValue(); + if (!$out && $id) { + throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id]); + } + return ValueInfo::normalize($out, ValueInfo::T_DATE | ValueInfo::M_NULL, "sql"); + } + /** Ensures the specified subscription exists and raises an exception otherwise * * Returns an associative array containing the id of the subscription and the id of the underlying newsfeed diff --git a/tests/cases/Database/SeriesSubscription.php b/tests/cases/Database/SeriesSubscription.php index 9756a281..d65fb3eb 100644 --- a/tests/cases/Database/SeriesSubscription.php +++ b/tests/cases/Database/SeriesSubscription.php @@ -47,6 +47,7 @@ trait SeriesSubscription { 'title' => "str", 'username' => "str", 'password' => "str", + 'updated' => "datetime", 'next_fetch' => "datetime", 'favicon' => "str", ], @@ -134,9 +135,9 @@ trait SeriesSubscription { ], ]; $this->data['arsse_feeds']['rows'] = [ - [1,"http://example.com/feed1", "Ook", "", "",strtotime("now"),''], - [2,"http://example.com/feed2", "eek", "", "",strtotime("now - 1 hour"),'http://example.com/favicon.ico'], - [3,"http://example.com/feed3", "Ack", "", "",strtotime("now + 1 hour"),''], + [1,"http://example.com/feed1", "Ook", "", "",strtotime("now"),strtotime("now"),''], + [2,"http://example.com/feed2", "eek", "", "",strtotime("now - 1 hour"),strtotime("now - 1 hour"),'http://example.com/favicon.ico'], + [3,"http://example.com/feed3", "Ack", "", "",strtotime("now + 1 hour"),strtotime("now + 1 hour"),''], ]; // initialize a partial mock of the Database object to later manipulate the feedUpdate method Arsse::$db = Phake::partialMock(Database::class, static::$drv); @@ -491,4 +492,21 @@ trait SeriesSubscription { $this->assertException("notAuthorized", "User", "ExceptionAuthz"); Arsse::$db->subscriptionTagsGet("john.doe@example.com", 1); } + + public function testGetRefreshTimeOfASubscription() { + $user = "john.doe@example.com"; + $this->assertTime(strtotime("now + 1 hour"), Arsse::$db->subscriptionRefreshed($user)); + $this->assertTime(strtotime("now - 1 hour"), Arsse::$db->subscriptionRefreshed($user, 1)); + } + + public function testGetRefreshTimeOfAMissingSubscription() { + $this->assertException("subjectMissing", "Db", "ExceptionInput"); + $this->assertTime(strtotime("now - 1 hour"), Arsse::$db->subscriptionRefreshed("john.doe@example.com", 2)); + } + + public function testGetRefreshTimeOfASubscriptionWithoutAuthority() { + Phake::when(Arsse::$user)->authorize->thenReturn(false); + $this->assertException("notAuthorized", "User", "ExceptionAuthz"); + $this->assertTime(strtotime("now + 1 hour"), Arsse::$db->subscriptionRefreshed("john.doe@example.com")); + } }