From c42a4a308fec6c4806c8fb14c7268b6a9b0dfbac Mon Sep 17 00:00:00 2001 From: Kevin Jiang Date: Sun, 21 Jul 2024 15:20:45 +1200 Subject: [PATCH 1/2] feat: Implement http status filtering in entries API --- src/Controller/Api/EntryRestController.php | 16 +++++++++++++++- src/Repository/EntryRepository.php | 7 ++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Controller/Api/EntryRestController.php b/src/Controller/Api/EntryRestController.php index b9fcffcd7..ca2ae0177 100644 --- a/src/Controller/Api/EntryRestController.php +++ b/src/Controller/Api/EntryRestController.php @@ -280,6 +280,18 @@ class EntryRestController extends WallabagRestController * example="example.com", * ) * ), + * @OA\Parameter( + * name="http_status", + * in="query", + * description="filter entries with matching http status code", + * required=false, + * @OA\Schema( + * type="integer", + * minimum=100, + * maximum=527, + * example="200", + * ) + * ), * @OA\Response( * response="200", * description="Returned when successful" @@ -306,6 +318,7 @@ class EntryRestController extends WallabagRestController $since = $request->query->get('since', 0); $detail = strtolower($request->query->get('detail', 'full')); $domainName = (null === $request->query->get('domain_name')) ? '' : (string) $request->query->get('domain_name'); + $httpStatus = (!\array_key_exists((int) $request->query->get('http_status'), Response::$statusTexts)) ? null : (int) $request->query->get('http_status'); try { /** @var Pagerfanta $pager */ @@ -320,7 +333,8 @@ class EntryRestController extends WallabagRestController $tags, $detail, $domainName, - $isNotParsed + $isNotParsed, + $httpStatus ); } catch (\Exception $e) { throw new BadRequestHttpException($e->getMessage()); diff --git a/src/Repository/EntryRepository.php b/src/Repository/EntryRepository.php index 521038e56..bd1a3837a 100644 --- a/src/Repository/EntryRepository.php +++ b/src/Repository/EntryRepository.php @@ -285,13 +285,14 @@ class EntryRepository extends ServiceEntityRepository * @param string $tags * @param string $detail 'metadata' or 'full'. Include content field if 'full' * @param string $domainName + * @param int $httpStatus * @param bool $isNotParsed * * @todo Breaking change: replace default detail=full by detail=metadata in a future version * * @return Pagerfanta */ - public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '', $detail = 'full', $domainName = '', $isNotParsed = null) + public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '', $detail = 'full', $domainName = '', $isNotParsed = null, $httpStatus = null) { if (!\in_array(strtolower($detail), ['full', 'metadata'], true)) { throw new \Exception('Detail "' . $detail . '" parameter is wrong, allowed: full or metadata'); @@ -350,6 +351,10 @@ class EntryRepository extends ServiceEntityRepository } } + if (\is_int($httpStatus)) { + $qb->andWhere('e.httpStatus = :httpStatus')->setParameter('httpStatus', $httpStatus); + } + if (\is_string($domainName) && '' !== $domainName) { $qb->andWhere('e.domainName = :domainName')->setParameter('domainName', $domainName); } From fc14f86ae4798ca67dd6330a4fac65d9ed780b91 Mon Sep 17 00:00:00 2001 From: Kevin Jiang Date: Sun, 21 Jul 2024 16:25:41 +1200 Subject: [PATCH 2/2] test: Add test for http_status filter --- fixtures/EntryFixtures.php | 15 +++++++ tests/Command/ExportCommandTest.php | 2 +- .../Api/EntryRestControllerTest.php | 45 +++++++++++++++++++ tests/Controller/EntryControllerTest.php | 24 +++++----- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/fixtures/EntryFixtures.php b/fixtures/EntryFixtures.php index 65ba832a8..22b797122 100644 --- a/fixtures/EntryFixtures.php +++ b/fixtures/EntryFixtures.php @@ -87,6 +87,17 @@ class EntryFixtures extends Fixture implements DependentFixtureInterface 'tags' => ['bar-tag'], 'is_not_parsed' => true, ], + 'entry7' => [ + 'user' => 'admin-user', + 'url' => 'http://0.0.0.0/entry7', + 'reading_time' => 12, + 'domain' => 'redirect.io', + 'mime' => 'text/html', + 'title' => 'test title entry7', + 'http_status' => '302', + 'content' => 'This is redirect/o/', + 'language' => 'de', + ], ]; foreach ($entries as $reference => $item) { @@ -133,6 +144,10 @@ class EntryFixtures extends Fixture implements DependentFixtureInterface $entry->setNotParsed($item['is_not_parsed']); } + if (isset($item['http_status'])) { + $entry->setHttpStatus($item['http_status']); + } + $manager->persist($entry); $this->addReference($reference, $entry); } diff --git a/tests/Command/ExportCommandTest.php b/tests/Command/ExportCommandTest.php index 7f39d95d2..67c11c4ef 100644 --- a/tests/Command/ExportCommandTest.php +++ b/tests/Command/ExportCommandTest.php @@ -47,7 +47,7 @@ class ExportCommandTest extends WallabagTestCase 'username' => 'admin', ]); - $this->assertStringContainsString('Exporting 5 entrie(s) for user admin...', $tester->getDisplay()); + $this->assertStringContainsString('Exporting 6 entrie(s) for user admin...', $tester->getDisplay()); $this->assertStringContainsString('Done', $tester->getDisplay()); $this->assertFileExists('admin-export.json'); } diff --git a/tests/Controller/Api/EntryRestControllerTest.php b/tests/Controller/Api/EntryRestControllerTest.php index 25ffe612b..2fa0c3399 100644 --- a/tests/Controller/Api/EntryRestControllerTest.php +++ b/tests/Controller/Api/EntryRestControllerTest.php @@ -170,6 +170,50 @@ class EntryRestControllerTest extends WallabagApiTestCase $this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type')); } + public function testGetEntriesByHttpStatusWithMatching() + { + $this->client->request('GET', '/api/entries?http_status=302'); + + $this->assertSame(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertGreaterThanOrEqual(1, \count($content)); + $this->assertNotEmpty($content['_embedded']['items']); + $this->assertSame(1, $content['total']); + $this->assertSame(1, $content['page']); + $this->assertGreaterThanOrEqual(1, $content['pages']); + + $this->assertSame('test title entry7', $content['_embedded']['items'][0]['title']); + $this->assertSame('302', $content['_embedded']['items'][0]['http_status']); + + $this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type')); + } + + public function testGetEntriesByHttpStatusNoMatching() + { + $this->client->request('GET', '/api/entries?http_status=404'); + + $this->assertSame(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertGreaterThanOrEqual(1, \count($content)); + $this->assertEmpty($content['_embedded']['items']); + $this->assertSame(0, $content['total']); + $this->assertSame(1, $content['page']); + $this->assertGreaterThanOrEqual(1, $content['pages']); + + $this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type')); + } + + public function testGetEntriesWithBadHttpStatusParam() + { + $this->client->request('GET', '/api/entries?http_status=10000'); + + $this->assertSame(200, $this->client->getResponse()->getStatusCode()); + } + public function testGetEntriesWithFullOptions() { $this->client->request('GET', '/api/entries', [ @@ -183,6 +227,7 @@ class EntryRestControllerTest extends WallabagApiTestCase 'since' => 1443274283, 'public' => 0, 'notParsed' => 0, + 'http_status' => 200, ]); $this->assertSame(200, $this->client->getResponse()->getStatusCode()); diff --git a/tests/Controller/EntryControllerTest.php b/tests/Controller/EntryControllerTest.php index 86d74a1d7..11b6cdce2 100644 --- a/tests/Controller/EntryControllerTest.php +++ b/tests/Controller/EntryControllerTest.php @@ -106,14 +106,14 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->request('GET', '/'); - $this->assertCount(4, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); // Good URL $client->request('GET', '/bookmarklet', ['url' => $this->url]); $this->assertSame(302, $client->getResponse()->getStatusCode()); $client->followRedirect(); $crawler = $client->request('GET', '/'); - $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(6, $crawler->filter($this->entryDataTestAttribute)); $em = $client->getContainer() ->get(EntityManagerInterface::class); @@ -803,7 +803,7 @@ class EntryControllerTest extends WallabagTestCase $client = $this->getTestClient(); $crawler = $client->request('GET', '/all/list'); - $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(6, $crawler->filter($this->entryDataTestAttribute)); $entry = new Entry($this->getLoggedInUser()); $entry->setUrl($this->url); @@ -812,7 +812,7 @@ class EntryControllerTest extends WallabagTestCase $this->getEntityManager()->flush(); $crawler = $client->request('GET', '/all/list'); - $this->assertCount(6, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(7, $crawler->filter($this->entryDataTestAttribute)); $form = $crawler->filter('button[id=submit-filter]')->form(); @@ -822,7 +822,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(6, $crawler->filter($this->entryDataTestAttribute)); } public function testFilterOnReadingTimeOnlyLower() @@ -867,7 +867,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(4, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); $entry = new Entry($this->getLoggedInUser()); $entry->setUrl($this->url); @@ -877,7 +877,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(6, $crawler->filter($this->entryDataTestAttribute)); } public function testFilterOnCreationDate() @@ -908,7 +908,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(4, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); $data = [ 'entry_filter[createdAt][left_date]' => $today->format('Y-m-d'), @@ -917,7 +917,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(4, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); $data = [ 'entry_filter[createdAt][left_date]' => '1970-01-01', @@ -1394,7 +1394,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(8, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(9, $crawler->filter($this->entryDataTestAttribute)); } public function testSearch() @@ -1418,7 +1418,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(4, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); // Add a check with useless spaces before and after the search term $crawler = $client->request('GET', '/unread/list'); @@ -1430,7 +1430,7 @@ class EntryControllerTest extends WallabagTestCase $crawler = $client->submit($form, $data); - $this->assertCount(4, $crawler->filter($this->entryDataTestAttribute)); + $this->assertCount(5, $crawler->filter($this->entryDataTestAttribute)); // Search on starred list $crawler = $client->request('GET', '/starred/list');