From 7faec3b0db504a530e0205d6cad30b779931c1af Mon Sep 17 00:00:00 2001 From: "J. King" Date: Wed, 27 Mar 2019 11:54:47 -0400 Subject: [PATCH] Fever fixes - Ensure the last refresh time is included in authenticated requests - Use a partial mock in auth tests so that other processing does not get in the way of results - Make sure the group list includes unused groups - Make sure the update time of subscriptions is correct --- lib/REST/Fever/API.php | 57 +++++++++++++++--------------- tests/cases/REST/Fever/TestAPI.php | 15 +++++--- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/lib/REST/Fever/API.php b/lib/REST/Fever/API.php index 0d24337..c5a93a3 100644 --- a/lib/REST/Fever/API.php +++ b/lib/REST/Fever/API.php @@ -60,23 +60,9 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { // check that the user specified credentials if ($this->logIn(strtolower($inW['api_key'] ?? ""))) { $out['auth'] = 1; + $out = $this->processRequest($out, $inR, $inW); } else { $out['auth'] = 0; - return $this->formatResponse($out, $xml); - } - // handle each possible parameter - if (array_key_exists("feeds", $inR) || array_key_exists("groups", $inR)) { - $groupData = (array) Arsse::$db->tagSummarize(Arsse::$user->id); - if (array_key_exists("groups", $inR)) { - $out['groups'] = $this->getGroups($groupData); - } - if (array_key_exists("feeds", $inR)) { - $out['feeds'] = $this->getFeeds(); - } - $out['feeds_groups'] = $this->getRelationships($groupData); - } - if (array_key_exists("favicons", $inR)) { - # deal with favicons } // return the result return $this->formatResponse($out, $xml); @@ -86,6 +72,25 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { } } + protected function processRequest(array $out, array $G, array $P): array { + // add base metadata + $out['last_refreshed_on_time'] = Date::transform(Arsse::$db->subscriptionRefreshed(Arsse::$user->id), "unix"); + // handle each possible parameter + if (array_key_exists("feeds", $G) || array_key_exists("groups", $G)) { + if (array_key_exists("groups", $G)) { + $out['groups'] = $this->getGroups(); + } + if (array_key_exists("feeds", $G)) { + $out['feeds'] = $this->getFeeds(); + } + $out['feeds_groups'] = $this->getRelationships(); + } + if (array_key_exists("favicons", $G)) { + # deal with favicons + } + return $out; + } + protected function formatResponse(array $data, bool $xml): ResponseInterface { if ($xml) { throw \Exception("Not implemented yet"); @@ -120,31 +125,27 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { 'url' => $sub['url'], 'site_url' => $sub['source'], 'is_spark' => 0, - 'lat_updated_on_time' => Date::transform($sub['updated'], "unix"), + 'lat_updated_on_time' => Date::transform($sub['edited'], "unix", "sql"), ]; } return $out; } - protected function getGroups(array $data): array { + protected function getGroups(): array { $out = []; - $seen = []; - foreach ($data as $member) { - if (!($seen[$member['id']] ?? false)) { - $seen[$member['id']] = true; - $out[] = [ - 'id' => (int) $member['id'], - 'title' => $member['name'], - ]; - } + foreach (Arsse::$db->tagList(Arsse::$user->id) as $member) { + $out[] = [ + 'id' => (int) $member['id'], + 'title' => $member['name'], + ]; } return $out; } - protected function getRelationships(array $data): array { + protected function getRelationships(): array { $out = []; $sets = []; - foreach ($data as $member) { + foreach (Arsse::$db->tagSummarize(Arsse::$user->id) as $member) { if (!isset($sets[$member['id']])) { $sets[$member['id']] = []; } diff --git a/tests/cases/REST/Fever/TestAPI.php b/tests/cases/REST/Fever/TestAPI.php index c76d567..be34712 100644 --- a/tests/cases/REST/Fever/TestAPI.php +++ b/tests/cases/REST/Fever/TestAPI.php @@ -23,7 +23,6 @@ use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\ServerRequest; use Zend\Diactoros\Response\JsonResponse; use Zend\Diactoros\Response\EmptyResponse; -use Phake; /** @covers \JKingWeb\Arsse\REST\Fever\API */ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { @@ -66,12 +65,13 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { self::clearData(); self::setConf(); // create a mock user manager - Arsse::$user = Phake::mock(User::class); - Phake::when(Arsse::$user)->auth->thenReturn(true); + Arsse::$user = \Phake::mock(User::class); + \Phake::when(Arsse::$user)->auth->thenReturn(true); Arsse::$user->id = "john.doe@example.com"; // create a mock database interface - Arsse::$db = Phake::mock(Database::class); - Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(Transaction::class)); + Arsse::$db = \Phake::mock(Database::class); + \Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(Transaction::class)); + \Phake::when(Arsse::$db)->tokenLookup->thenReturn(['user' => "john.doe@example.com"]); // instantiate the handler $this->h = new API(); } @@ -89,6 +89,11 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { Arsse::$user->id = null; \Phake::when(Arsse::$db)->tokenLookup->thenThrow(new ExceptionInput("subjectMissing")); \Phake::when(Arsse::$db)->tokenLookup("fever.login", "validtoken")->thenReturn(['user' => "jane.doe@example.com"]); + // use a partial mock to test only the authentication process + $this->h = \Phake::partialMock(API::class); + \Phake::when($this->h)->processRequest->thenReturnCallback(function($out, $G, $P) { + return $out; + }); $act = $this->req($dataGet, $dataPost, "POST", null, "", $httpUser); $this->assertMessage($exp, $act); }