From 47e2d609bcac6de4893cc04559c0794642c30a80 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Tue, 13 Jun 2017 18:48:10 +0200 Subject: [PATCH] Changed RSS to Atom feed and improve paging --- app/config/security.yml | 1 + .../CoreBundle/Controller/RssController.php | 44 ++++++----- .../themes/common/Entry/entries.xml.twig | 76 +++++++++++-------- .../CoreBundle/Twig/WallabagExtension.php | 6 ++ .../Controller/RssControllerTest.php | 71 +++++++++-------- .../CoreBundle/Twig/WallabagExtensionTest.php | 25 ++++++ 6 files changed, 135 insertions(+), 88 deletions(-) diff --git a/app/config/security.yml b/app/config/security.yml index e14a0bd1..5f3bf0b6 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -62,6 +62,7 @@ security: - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: /tags/(.*).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/feed, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/settings, roles: ROLE_SUPER_ADMIN } - { path: ^/annotations, roles: ROLE_USER } diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/RssController.php index e84044b1..db0a8f9a 100644 --- a/src/Wallabag/CoreBundle/Controller/RssController.php +++ b/src/Wallabag/CoreBundle/Controller/RssController.php @@ -21,40 +21,46 @@ class RssController extends Controller /** * Shows unread entries for current user. * - * @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"}) + * @Route("/feed/{username}/{token}/unread/{page}", name="unread_rss", defaults={"page": 1}) * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") * + * @param User $user + * @param $page * @return \Symfony\Component\HttpFoundation\Response */ - public function showUnreadRSSAction(Request $request, User $user) + public function showUnreadRSSAction(User $user, $page) { - return $this->showEntries('unread', $user, $request->query->get('page', 1)); + return $this->showEntries('unread', $user, $page); } /** * Shows read entries for current user. * - * @Route("/{username}/{token}/archive.xml", name="archive_rss", defaults={"_format"="xml"}) + * @Route("/feed/{username}/{token}/archive/{page}", name="archive_rss", defaults={"page": 1}) * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") * + * @param User $user + * @param $page * @return \Symfony\Component\HttpFoundation\Response */ - public function showArchiveRSSAction(Request $request, User $user) + public function showArchiveRSSAction(User $user, $page) { - return $this->showEntries('archive', $user, $request->query->get('page', 1)); + return $this->showEntries('archive', $user, $page); } /** * Shows starred entries for current user. * - * @Route("/{username}/{token}/starred.xml", name="starred_rss", defaults={"_format"="xml"}) + * @Route("/feed/{username}/{token}/starred/{page}", name="starred_rss", defaults={"page": 1}) * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") * + * @param User $user + * @param $page * @return \Symfony\Component\HttpFoundation\Response */ - public function showStarredRSSAction(Request $request, User $user) + public function showStarredRSSAction(User $user, $page) { - return $this->showEntries('starred', $user, $request->query->get('page', 1)); + return $this->showEntries('starred', $user, $page); } /** @@ -179,19 +185,17 @@ class RssController extends Controller $entries->setCurrentPage((int) $page); } catch (OutOfRangeCurrentPageException $e) { if ($page > 1) { - return $this->redirect($url . '?page=' . $entries->getNbPages(), 302); + return $this->redirect($url.'/'.$entries->getNbPages()); } } - return $this->render( - '@WallabagCore/themes/common/Entry/entries.xml.twig', - [ - 'url_html' => $this->generateUrl($type, [], UrlGeneratorInterface::ABSOLUTE_URL), - 'type' => $type, - 'url' => $url, - 'entries' => $entries, - ], - new Response('', 200, ['Content-Type' => 'application/rss+xml']) - ); + return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [ + 'type' => $type, + 'url' => $url, + 'entries' => $entries, + 'user' => $user->getUsername(), + 'domainName' => $this->getParameter('domain_name'), + 'version' => $this->getParameter('wallabag_core.version'), + ]); } } diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig index d70aa5dc..0a0131cd 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig @@ -1,34 +1,46 @@ - - - wallabag - {{ type }} feed - {{ url_html }} - - {% if entries.hasPreviousPage -%} - - {% endif -%} - {% if entries.hasNextPage -%} - - {% endif -%} - - {{ "now"|date('D, d M Y H:i:s') }} - wallabag - wallabag {{ type }} elements - - {% for entry in entries %} - - - <![CDATA[{{ entry.title|e }}]]> - wallabag - {{ entry.url }} - {{ entry.url }} - {{ entry.createdAt|date('D, d M Y H:i:s') }} - - 0 -%}{{ 'entry.list.reading_time_minutes'|trans({'%readingTime%': entry.readingTime}) }}{%- else -%}{{ 'entry.list.reading_time_less_one_minute'|trans|raw }}{%- endif %}{{ entry.content|raw -}}]]> - - - + + wallabag — {{type}} feed + RSS feed for {{ type }} entries + {% if entries | length > 0 %} + {{ (entries | first).createdAt | date('c') }} {# Indicates the last time the feed was modified in a significant way. #} + {% endif %} + wallabag:{{ domainName | removeScheme | removeWww }}:{{ user }}:{{ type }} + + + {% if entries.hasPreviousPage %} + + {% endif -%} + {% if entries.hasNextPage %} + + {% endif -%} + + wallabag + + {{ user }} + + {{ asset('favicon.ico') }} + {{ asset('bundles/wallabagcore/themes/_global/img/logo-square.png') }} + {% for entry in entries %} + + <![CDATA[{{ entry.title|e }}]]> + + {{ entry.url }} + wallabag:{{ domainName | removeScheme | removeWww }}:{{ user }}:entry:{{ entry.id }} + {{ entry.updatedAt|date('c') }} + {{ entry.createdAt|date('c') }} + {% for tag in entry.tags %} + {% endfor %} - - - + {% for author in entry.publishedBy %} + + {{ author }} + + {% endfor %} + + 0 -%}{{ 'entry.list.reading_time_minutes'|trans({'%readingTime%': entry.readingTime}) }}{%- else -%}{{ 'entry.list.reading_time_less_one_minute'|trans|raw }}{%- endif %}{{ entry.content|raw -}}]]> + + + {% endfor %} + diff --git a/src/Wallabag/CoreBundle/Twig/WallabagExtension.php b/src/Wallabag/CoreBundle/Twig/WallabagExtension.php index 351172c4..530e0492 100644 --- a/src/Wallabag/CoreBundle/Twig/WallabagExtension.php +++ b/src/Wallabag/CoreBundle/Twig/WallabagExtension.php @@ -28,6 +28,7 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa { return [ new \Twig_SimpleFilter('removeWww', [$this, 'removeWww']), + new \Twig_SimpleFilter('removeScheme', [$this, 'removeScheme']), ]; } @@ -45,6 +46,11 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa return preg_replace('/^www\./i', '', $url); } + public function removeScheme($url) + { + return preg_replace('#^https?://#', '', $url); + } + /** * Return number of entries depending of the type (unread, archive, starred or all). * diff --git a/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php b/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php index 6167fe2d..0e4a5afa 100644 --- a/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php @@ -12,40 +12,39 @@ class RssControllerTest extends WallabagCoreTestCase $doc->loadXML($xml); $xpath = new \DOMXpath($doc); + $xpath->registerNamespace('a', 'http://www.w3.org/2005/Atom'); if (null === $nb) { - $this->assertGreaterThan(0, $xpath->query('//item')->length); + $this->assertGreaterThan(0, $xpath->query('//a:entry')->length); } else { - $this->assertSame($nb, $xpath->query('//item')->length); + $this->assertEquals($nb, $xpath->query('//a:entry')->length); } - $this->assertSame(1, $xpath->query('/rss')->length); - $this->assertSame(1, $xpath->query('/rss/channel')->length); + $this->assertEquals(1, $xpath->query('/a:feed')->length); - $this->assertSame(1, $xpath->query('/rss/channel/title')->length); - $this->assertSame('wallabag - ' . $type . ' feed', $xpath->query('/rss/channel/title')->item(0)->nodeValue); + $this->assertEquals(1, $xpath->query('/a:feed/a:title')->length); + $this->assertEquals('wallabag — '.$type.' feed', $xpath->query('/a:feed/a:title')->item(0)->nodeValue); - $this->assertSame(1, $xpath->query('/rss/channel/pubDate')->length); + $this->assertEquals(1, $xpath->query('/a:feed/a:updated')->length); - $this->assertSame(1, $xpath->query('/rss/channel/generator')->length); - $this->assertSame('wallabag', $xpath->query('/rss/channel/generator')->item(0)->nodeValue); + $this->assertEquals(1, $xpath->query('/a:feed/a:generator')->length); + $this->assertEquals('wallabag', $xpath->query('/a:feed/a:generator')->item(0)->nodeValue); - $this->assertSame(1, $xpath->query('/rss/channel/description')->length); - $this->assertSame('wallabag ' . $type . ' elements', $xpath->query('/rss/channel/description')->item(0)->nodeValue); + $this->assertEquals(1, $xpath->query('/a:feed/a:subtitle')->length); + $this->assertEquals('RSS feed for '.$type.' entries', $xpath->query('/a:feed/a:subtitle')->item(0)->nodeValue); - $this->assertSame(1, $xpath->query('/rss/channel/link[@rel="self"]')->length); - $this->assertContains($urlPagination . '.xml', $xpath->query('/rss/channel/link[@rel="self"]')->item(0)->getAttribute('href')); + $this->assertEquals(1, $xpath->query('/a:feed/a:link[@rel="self"]')->length); + $this->assertContains($type, $xpath->query('/a:feed/a:link[@rel="self"]')->item(0)->getAttribute('href')); - $this->assertSame(1, $xpath->query('/rss/channel/link[@rel="last"]')->length); - $this->assertContains($urlPagination . '.xml?page=', $xpath->query('/rss/channel/link[@rel="last"]')->item(0)->getAttribute('href')); + $this->assertEquals(1, $xpath->query('/a:feed/a:link[@rel="last"]')->length); - foreach ($xpath->query('//item') as $item) { - $this->assertSame(1, $xpath->query('title', $item)->length); - $this->assertSame(1, $xpath->query('source', $item)->length); - $this->assertSame(1, $xpath->query('link', $item)->length); - $this->assertSame(1, $xpath->query('guid', $item)->length); - $this->assertSame(1, $xpath->query('pubDate', $item)->length); - $this->assertSame(1, $xpath->query('description', $item)->length); + foreach ($xpath->query('//a:entry') as $item) { + $this->assertEquals(1, $xpath->query('a:title', $item)->length); + $this->assertEquals(1, $xpath->query('a:link[@rel="via"]', $item)->length); + $this->assertEquals(1, $xpath->query('a:link[@rel="alternate"]', $item)->length); + $this->assertEquals(1, $xpath->query('a:id', $item)->length); + $this->assertEquals(1, $xpath->query('a:published', $item)->length); + $this->assertEquals(1, $xpath->query('a:content', $item)->length); } } @@ -53,13 +52,13 @@ class RssControllerTest extends WallabagCoreTestCase { return [ [ - '/admin/YZIOAUZIAO/unread.xml', + '/feed/admin/YZIOAUZIAO/unread', ], [ - '/wallace/YZIOAUZIAO/starred.xml', + '/feed/wallace/YZIOAUZIAO/starred', ], [ - '/wallace/YZIOAUZIAO/archives.xml', + '/feed/wallace/YZIOAUZIAO/archives', ], ]; } @@ -90,7 +89,7 @@ class RssControllerTest extends WallabagCoreTestCase $em->persist($config); $em->flush(); - $client->request('GET', '/admin/SUPERTOKEN/unread.xml'); + $client->request('GET', '/feed/admin/SUPERTOKEN/unread'); $this->assertSame(200, $client->getResponse()->getStatusCode()); @@ -112,7 +111,7 @@ class RssControllerTest extends WallabagCoreTestCase $em->flush(); $client = $this->getClient(); - $client->request('GET', '/admin/SUPERTOKEN/starred.xml'); + $client->request('GET', '/feed/admin/SUPERTOKEN/starred'); $this->assertSame(200, $client->getResponse()->getStatusCode(), 1); @@ -134,7 +133,7 @@ class RssControllerTest extends WallabagCoreTestCase $em->flush(); $client = $this->getClient(); - $client->request('GET', '/admin/SUPERTOKEN/archive.xml'); + $client->request('GET', '/feed/admin/SUPERTOKEN/archive'); $this->assertSame(200, $client->getResponse()->getStatusCode()); @@ -157,16 +156,16 @@ class RssControllerTest extends WallabagCoreTestCase $client = $this->getClient(); - $client->request('GET', '/admin/SUPERTOKEN/unread.xml'); - $this->assertSame(200, $client->getResponse()->getStatusCode()); - $this->validateDom($client->getResponse()->getContent(), 'unread', 'unread'); + $client->request('GET', '/feed/admin/SUPERTOKEN/unread'); + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->validateDom($client->getResponse()->getContent(), 'unread'); - $client->request('GET', '/admin/SUPERTOKEN/unread.xml?page=2'); - $this->assertSame(200, $client->getResponse()->getStatusCode()); - $this->validateDom($client->getResponse()->getContent(), 'unread', 'unread'); + $client->request('GET', '/feed/admin/SUPERTOKEN/unread/2'); + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->validateDom($client->getResponse()->getContent(), 'unread'); - $client->request('GET', '/admin/SUPERTOKEN/unread.xml?page=3000'); - $this->assertSame(302, $client->getResponse()->getStatusCode()); + $client->request('GET', '/feed/admin/SUPERTOKEN/unread/3000'); + $this->assertEquals(302, $client->getResponse()->getStatusCode()); } public function testTags() diff --git a/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php b/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php index ceec4b37..4cb84ef1 100644 --- a/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php +++ b/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php @@ -30,4 +30,29 @@ class WallabagExtensionTest extends \PHPUnit_Framework_TestCase $this->assertSame('lemonde.fr', $extension->removeWww('lemonde.fr')); $this->assertSame('gist.github.com', $extension->removeWww('gist.github.com')); } + + public function testRemoveScheme() + { + $entryRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository') + ->disableOriginalConstructor() + ->getMock(); + + $tagRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\TagRepository') + ->disableOriginalConstructor() + ->getMock(); + + $tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface') + ->disableOriginalConstructor() + ->getMock(); + + $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface') + ->disableOriginalConstructor() + ->getMock(); + + $extension = new WallabagExtension($entryRepository, $tagRepository, $tokenStorage, 0, $translator); + + $this->assertEquals('lemonde.fr', $extension->removeScheme('lemonde.fr')); + $this->assertEquals('gist.github.com', $extension->removeScheme('gist.github.com')); + $this->assertEquals('gist.github.com', $extension->removeScheme('https://gist.github.com')); + } } -- 2.41.0