diff options
author | Jeremy Benoist <jeremy.benoist@gmail.com> | 2017-06-10 13:11:08 +0200 |
---|---|---|
committer | Jeremy Benoist <jeremy.benoist@gmail.com> | 2017-06-21 11:44:35 +0200 |
commit | 18c38dffc67d04e59a9cc26b6910d9b9a4a49cd6 (patch) | |
tree | 31907aab65a3c505f66945ac58c355681bb6618d | |
parent | 25203e5081c8da21869db1d16610f83f888249b5 (diff) | |
download | wallabag-18c38dffc67d04e59a9cc26b6910d9b9a4a49cd6.tar.gz wallabag-18c38dffc67d04e59a9cc26b6910d9b9a4a49cd6.tar.zst wallabag-18c38dffc67d04e59a9cc26b6910d9b9a4a49cd6.zip |
Add RSS tags feeds
5 files changed, 117 insertions, 20 deletions
diff --git a/app/config/security.yml b/app/config/security.yml index ffb1d356..e14a0bd1 100644 --- a/app/config/security.yml +++ b/app/config/security.yml | |||
@@ -61,6 +61,7 @@ security: | |||
61 | - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } | 61 | - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } |
62 | - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } | 62 | - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } |
63 | - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 63 | - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
64 | - { path: /tags/(.*).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } | ||
64 | - { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 65 | - { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
65 | - { path: ^/settings, roles: ROLE_SUPER_ADMIN } | 66 | - { path: ^/settings, roles: ROLE_SUPER_ADMIN } |
66 | - { path: ^/annotations, roles: ROLE_USER } | 67 | - { path: ^/annotations, roles: ROLE_USER } |
diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/RssController.php index 5f7502fc..090eccab 100644 --- a/src/Wallabag/CoreBundle/Controller/RssController.php +++ b/src/Wallabag/CoreBundle/Controller/RssController.php | |||
@@ -3,13 +3,16 @@ | |||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Pagerfanta\Adapter\DoctrineORMAdapter; | 5 | use Pagerfanta\Adapter\DoctrineORMAdapter; |
6 | use Pagerfanta\Adapter\ArrayAdapter; | ||
6 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 7 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
7 | use Pagerfanta\Pagerfanta; | 8 | use Pagerfanta\Pagerfanta; |
8 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | 10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
10 | use Symfony\Component\HttpFoundation\Request; | 11 | use Symfony\Component\HttpFoundation\Request; |
12 | use Symfony\Component\HttpFoundation\Response; | ||
11 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 13 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
12 | use Wallabag\CoreBundle\Entity\Entry; | 14 | use Wallabag\CoreBundle\Entity\Entry; |
15 | use Wallabag\CoreBundle\Entity\Tag; | ||
13 | use Wallabag\UserBundle\Entity\User; | 16 | use Wallabag\UserBundle\Entity\User; |
14 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 17 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
15 | 18 | ||
@@ -31,7 +34,7 @@ class RssController extends Controller | |||
31 | /** | 34 | /** |
32 | * Shows read entries for current user. | 35 | * Shows read entries for current user. |
33 | * | 36 | * |
34 | * @Route("/{username}/{token}/archive.xml", name="archive_rss") | 37 | * @Route("/{username}/{token}/archive.xml", name="archive_rss", defaults={"_format"="xml"}) |
35 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 38 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") |
36 | * | 39 | * |
37 | * @return \Symfony\Component\HttpFoundation\Response | 40 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -44,7 +47,7 @@ class RssController extends Controller | |||
44 | /** | 47 | /** |
45 | * Shows starred entries for current user. | 48 | * Shows starred entries for current user. |
46 | * | 49 | * |
47 | * @Route("/{username}/{token}/starred.xml", name="starred_rss") | 50 | * @Route("/{username}/{token}/starred.xml", name="starred_rss", defaults={"_format"="xml"}) |
48 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 51 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") |
49 | * | 52 | * |
50 | * @return \Symfony\Component\HttpFoundation\Response | 53 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -55,6 +58,65 @@ class RssController extends Controller | |||
55 | } | 58 | } |
56 | 59 | ||
57 | /** | 60 | /** |
61 | * Shows entries associated to a tag for current user. | ||
62 | * | ||
63 | * @Route("/{username}/{token}/tags/{slug}.xml", name="tag_rss", defaults={"_format"="xml"}) | ||
64 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | ||
65 | * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) | ||
66 | * | ||
67 | * @return \Symfony\Component\HttpFoundation\Response | ||
68 | */ | ||
69 | public function showTagsAction(Request $request, User $user, Tag $tag) | ||
70 | { | ||
71 | $page = $request->query->get('page', 1); | ||
72 | |||
73 | $url = $this->generateUrl( | ||
74 | 'tag_rss', | ||
75 | [ | ||
76 | 'username' => $user->getUsername(), | ||
77 | 'token' => $user->getConfig()->getRssToken(), | ||
78 | 'slug' => $tag->getSlug(), | ||
79 | ], | ||
80 | UrlGeneratorInterface::ABSOLUTE_URL | ||
81 | ); | ||
82 | |||
83 | $entriesByTag = $this->get('wallabag_core.entry_repository')->findAllByTagId( | ||
84 | $user->getId(), | ||
85 | $tag->getId() | ||
86 | ); | ||
87 | |||
88 | $pagerAdapter = new ArrayAdapter($entriesByTag); | ||
89 | |||
90 | $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')->prepare( | ||
91 | $pagerAdapter, | ||
92 | $user | ||
93 | ); | ||
94 | |||
95 | if (null === $entries) { | ||
96 | throw $this->createNotFoundException('No entries found?'); | ||
97 | } | ||
98 | |||
99 | try { | ||
100 | $entries->setCurrentPage($page); | ||
101 | } catch (OutOfRangeCurrentPageException $e) { | ||
102 | if ($page > 1) { | ||
103 | return $this->redirect($url.'?page='.$entries->getNbPages(), 302); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | return $this->render( | ||
108 | '@WallabagCore/themes/common/Entry/entries.xml.twig', | ||
109 | [ | ||
110 | 'url_html' => $this->generateUrl('tag_entries', ['slug' => $tag->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL), | ||
111 | 'type' => 'tag ('.$tag->getLabel().')', | ||
112 | 'url' => $url, | ||
113 | 'entries' => $entries, | ||
114 | ], | ||
115 | new Response('', 200, ['Content-Type' => 'application/rss+xml']) | ||
116 | ); | ||
117 | } | ||
118 | |||
119 | /** | ||
58 | * Global method to retrieve entries depending on the given type | 120 | * Global method to retrieve entries depending on the given type |
59 | * It returns the response to be send. | 121 | * It returns the response to be send. |
60 | * | 122 | * |
@@ -108,10 +170,15 @@ class RssController extends Controller | |||
108 | } | 170 | } |
109 | } | 171 | } |
110 | 172 | ||
111 | return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [ | 173 | return $this->render( |
112 | 'type' => $type, | 174 | '@WallabagCore/themes/common/Entry/entries.xml.twig', |
113 | 'url' => $url, | 175 | [ |
114 | 'entries' => $entries, | 176 | 'url_html' => $this->generateUrl($type, [], UrlGeneratorInterface::ABSOLUTE_URL), |
115 | ]); | 177 | 'type' => $type, |
178 | 'url' => $url, | ||
179 | 'entries' => $entries, | ||
180 | ], | ||
181 | new Response('', 200, ['Content-Type' => 'application/rss+xml']) | ||
182 | ); | ||
116 | } | 183 | } |
117 | } | 184 | } |
diff --git a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php index df579ebd..231a0b52 100644 --- a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php +++ b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php | |||
@@ -4,6 +4,7 @@ namespace Wallabag\CoreBundle\Helper; | |||
4 | 4 | ||
5 | use Pagerfanta\Adapter\AdapterInterface; | 5 | use Pagerfanta\Adapter\AdapterInterface; |
6 | use Pagerfanta\Pagerfanta; | 6 | use Pagerfanta\Pagerfanta; |
7 | use Wallabag\UserBundle\Entity\User; | ||
7 | use Symfony\Component\Routing\Router; | 8 | use Symfony\Component\Routing\Router; |
8 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | 9 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; |
9 | 10 | ||
@@ -20,12 +21,15 @@ class PreparePagerForEntries | |||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * @param AdapterInterface $adapter | 23 | * @param AdapterInterface $adapter |
24 | * @param User $user If user isn't logged in, we can force it (like for rss) | ||
23 | * | 25 | * |
24 | * @return null|Pagerfanta | 26 | * @return null|Pagerfanta |
25 | */ | 27 | */ |
26 | public function prepare(AdapterInterface $adapter) | 28 | public function prepare(AdapterInterface $adapter, User $user = null) |
27 | { | 29 | { |
28 | $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; | 30 | if (null === $user) { |
31 | $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; | ||
32 | } | ||
29 | 33 | ||
30 | if (null === $user || !is_object($user)) { | 34 | if (null === $user || !is_object($user)) { |
31 | return; | 35 | return; |
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 12e8c79f..d70aa5dc 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,8 +1,8 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> |
2 | <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/"> | 2 | <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/"> |
3 | <channel> | 3 | <channel> |
4 | <title>wallabag — {{type}} feed</title> | 4 | <title>wallabag - {{ type }} feed</title> |
5 | <link>{{ url(type) }}</link> | 5 | <link>{{ url_html }}</link> |
6 | <link rel="self" href="{{ app.request.uri }}"/> | 6 | <link rel="self" href="{{ app.request.uri }}"/> |
7 | {% if entries.hasPreviousPage -%} | 7 | {% if entries.hasPreviousPage -%} |
8 | <link rel="previous" href="{{ url }}?page={{ entries.previousPage }}"/> | 8 | <link rel="previous" href="{{ url }}?page={{ entries.previousPage }}"/> |
@@ -13,7 +13,7 @@ | |||
13 | <link rel="last" href="{{ url }}?page={{ entries.nbPages }}"/> | 13 | <link rel="last" href="{{ url }}?page={{ entries.nbPages }}"/> |
14 | <pubDate>{{ "now"|date('D, d M Y H:i:s') }}</pubDate> | 14 | <pubDate>{{ "now"|date('D, d M Y H:i:s') }}</pubDate> |
15 | <generator>wallabag</generator> | 15 | <generator>wallabag</generator> |
16 | <description>wallabag {{type}} elements</description> | 16 | <description>wallabag {{ type }} elements</description> |
17 | 17 | ||
18 | {% for entry in entries %} | 18 | {% for entry in entries %} |
19 | 19 | ||
diff --git a/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php b/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php index 5a59654d..b46f3f9d 100644 --- a/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/RssControllerTest.php | |||
@@ -6,7 +6,7 @@ use Tests\Wallabag\CoreBundle\WallabagCoreTestCase; | |||
6 | 6 | ||
7 | class RssControllerTest extends WallabagCoreTestCase | 7 | class RssControllerTest extends WallabagCoreTestCase |
8 | { | 8 | { |
9 | public function validateDom($xml, $type, $nb = null) | 9 | public function validateDom($xml, $type, $urlPagination, $nb = null) |
10 | { | 10 | { |
11 | $doc = new \DOMDocument(); | 11 | $doc = new \DOMDocument(); |
12 | $doc->loadXML($xml); | 12 | $doc->loadXML($xml); |
@@ -34,10 +34,10 @@ class RssControllerTest extends WallabagCoreTestCase | |||
34 | $this->assertEquals('wallabag '.$type.' elements', $xpath->query('/rss/channel/description')->item(0)->nodeValue); | 34 | $this->assertEquals('wallabag '.$type.' elements', $xpath->query('/rss/channel/description')->item(0)->nodeValue); |
35 | 35 | ||
36 | $this->assertEquals(1, $xpath->query('/rss/channel/link[@rel="self"]')->length); | 36 | $this->assertEquals(1, $xpath->query('/rss/channel/link[@rel="self"]')->length); |
37 | $this->assertContains($type.'.xml', $xpath->query('/rss/channel/link[@rel="self"]')->item(0)->getAttribute('href')); | 37 | $this->assertContains($urlPagination.'.xml', $xpath->query('/rss/channel/link[@rel="self"]')->item(0)->getAttribute('href')); |
38 | 38 | ||
39 | $this->assertEquals(1, $xpath->query('/rss/channel/link[@rel="last"]')->length); | 39 | $this->assertEquals(1, $xpath->query('/rss/channel/link[@rel="last"]')->length); |
40 | $this->assertContains($type.'.xml?page=', $xpath->query('/rss/channel/link[@rel="last"]')->item(0)->getAttribute('href')); | 40 | $this->assertContains($urlPagination.'.xml?page=', $xpath->query('/rss/channel/link[@rel="last"]')->item(0)->getAttribute('href')); |
41 | 41 | ||
42 | foreach ($xpath->query('//item') as $item) { | 42 | foreach ($xpath->query('//item') as $item) { |
43 | $this->assertEquals(1, $xpath->query('title', $item)->length); | 43 | $this->assertEquals(1, $xpath->query('title', $item)->length); |
@@ -94,7 +94,7 @@ class RssControllerTest extends WallabagCoreTestCase | |||
94 | 94 | ||
95 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 95 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); |
96 | 96 | ||
97 | $this->validateDom($client->getResponse()->getContent(), 'unread', 2); | 97 | $this->validateDom($client->getResponse()->getContent(), 'unread', 'unread', 2); |
98 | } | 98 | } |
99 | 99 | ||
100 | public function testStarred() | 100 | public function testStarred() |
@@ -116,7 +116,7 @@ class RssControllerTest extends WallabagCoreTestCase | |||
116 | 116 | ||
117 | $this->assertEquals(200, $client->getResponse()->getStatusCode(), 1); | 117 | $this->assertEquals(200, $client->getResponse()->getStatusCode(), 1); |
118 | 118 | ||
119 | $this->validateDom($client->getResponse()->getContent(), 'starred'); | 119 | $this->validateDom($client->getResponse()->getContent(), 'starred', 'starred'); |
120 | } | 120 | } |
121 | 121 | ||
122 | public function testArchives() | 122 | public function testArchives() |
@@ -138,7 +138,7 @@ class RssControllerTest extends WallabagCoreTestCase | |||
138 | 138 | ||
139 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 139 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); |
140 | 140 | ||
141 | $this->validateDom($client->getResponse()->getContent(), 'archive'); | 141 | $this->validateDom($client->getResponse()->getContent(), 'archive', 'archive'); |
142 | } | 142 | } |
143 | 143 | ||
144 | public function testPagination() | 144 | public function testPagination() |
@@ -159,13 +159,38 @@ class RssControllerTest extends WallabagCoreTestCase | |||
159 | 159 | ||
160 | $client->request('GET', '/admin/SUPERTOKEN/unread.xml'); | 160 | $client->request('GET', '/admin/SUPERTOKEN/unread.xml'); |
161 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 161 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); |
162 | $this->validateDom($client->getResponse()->getContent(), 'unread'); | 162 | $this->validateDom($client->getResponse()->getContent(), 'unread', 'unread'); |
163 | 163 | ||
164 | $client->request('GET', '/admin/SUPERTOKEN/unread.xml?page=2'); | 164 | $client->request('GET', '/admin/SUPERTOKEN/unread.xml?page=2'); |
165 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 165 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); |
166 | $this->validateDom($client->getResponse()->getContent(), 'unread'); | 166 | $this->validateDom($client->getResponse()->getContent(), 'unread', 'unread'); |
167 | 167 | ||
168 | $client->request('GET', '/admin/SUPERTOKEN/unread.xml?page=3000'); | 168 | $client->request('GET', '/admin/SUPERTOKEN/unread.xml?page=3000'); |
169 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | 169 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); |
170 | } | 170 | } |
171 | |||
172 | public function testTags() | ||
173 | { | ||
174 | $client = $this->getClient(); | ||
175 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | ||
176 | $user = $em | ||
177 | ->getRepository('WallabagUserBundle:User') | ||
178 | ->findOneByUsername('admin'); | ||
179 | |||
180 | $config = $user->getConfig(); | ||
181 | $config->setRssToken('SUPERTOKEN'); | ||
182 | $config->setRssLimit(null); | ||
183 | $em->persist($config); | ||
184 | $em->flush(); | ||
185 | |||
186 | $client = $this->getClient(); | ||
187 | $client->request('GET', '/admin/SUPERTOKEN/tags/foo-bar.xml'); | ||
188 | |||
189 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||
190 | |||
191 | $this->validateDom($client->getResponse()->getContent(), 'tag (foo bar)', 'tags/foo-bar'); | ||
192 | |||
193 | $client->request('GET', '/admin/SUPERTOKEN/tags/foo-bar.xml?page=3000'); | ||
194 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||
195 | } | ||
171 | } | 196 | } |