diff options
-rw-r--r-- | application/front/controllers/TagController.php | 48 | ||||
-rw-r--r-- | index.php | 31 | ||||
-rw-r--r-- | tests/front/controller/TagControllerTest.php | 82 | ||||
-rw-r--r-- | tpl/default/linklist.html | 4 | ||||
-rw-r--r-- | tpl/vintage/linklist.html | 2 |
5 files changed, 135 insertions, 32 deletions
diff --git a/application/front/controllers/TagController.php b/application/front/controllers/TagController.php index 598275b0..a1d5ad5b 100644 --- a/application/front/controllers/TagController.php +++ b/application/front/controllers/TagController.php | |||
@@ -35,7 +35,7 @@ class TagController extends ShaarliController | |||
35 | return $response->withRedirect('./'); | 35 | return $response->withRedirect('./'); |
36 | } | 36 | } |
37 | 37 | ||
38 | $currentUrl = parse_url($this->container->environment['HTTP_REFERER']); | 38 | $currentUrl = parse_url($referer); |
39 | parse_str($currentUrl['query'] ?? '', $params); | 39 | parse_str($currentUrl['query'] ?? '', $params); |
40 | 40 | ||
41 | if (null === $newTag) { | 41 | if (null === $newTag) { |
@@ -71,4 +71,50 @@ class TagController extends ShaarliController | |||
71 | 71 | ||
72 | return $response->withRedirect(($currentUrl['path'] ?? './') .'?'. http_build_query($params)); | 72 | return $response->withRedirect(($currentUrl['path'] ?? './') .'?'. http_build_query($params)); |
73 | } | 73 | } |
74 | |||
75 | /** | ||
76 | * Remove a tag from the current search through an HTTP redirection. | ||
77 | * | ||
78 | * @param array $args Should contain `tag` key as tag to remove from current search | ||
79 | */ | ||
80 | public function removeTag(Request $request, Response $response, array $args): Response | ||
81 | { | ||
82 | $referer = $this->container->environment['HTTP_REFERER'] ?? null; | ||
83 | |||
84 | // If the referrer is not provided, we can update the search, so we failback on the bookmark list | ||
85 | if (empty($referer)) { | ||
86 | return $response->withRedirect('./'); | ||
87 | } | ||
88 | |||
89 | $tagToRemove = $args['tag'] ?? null; | ||
90 | $currentUrl = parse_url($referer); | ||
91 | parse_str($currentUrl['query'] ?? '', $params); | ||
92 | |||
93 | if (null === $tagToRemove) { | ||
94 | return $response->withRedirect(($currentUrl['path'] ?? './') .'?'. http_build_query($params)); | ||
95 | } | ||
96 | |||
97 | // Prevent redirection loop | ||
98 | if (isset($params['removetag'])) { | ||
99 | unset($params['removetag']); | ||
100 | } | ||
101 | |||
102 | if (isset($params['searchtags'])) { | ||
103 | $tags = explode(' ', $params['searchtags']); | ||
104 | // Remove value from array $tags. | ||
105 | $tags = array_diff($tags, [$tagToRemove]); | ||
106 | $params['searchtags'] = implode(' ', $tags); | ||
107 | |||
108 | if (empty($params['searchtags'])) { | ||
109 | unset($params['searchtags']); | ||
110 | } | ||
111 | |||
112 | // We also remove page (keeping the same page has no sense, since the results are different) | ||
113 | unset($params['page']); | ||
114 | } | ||
115 | |||
116 | $queryParams = count($params) > 0 ? '?' . http_build_query($params) : ''; | ||
117 | |||
118 | return $response->withRedirect(($currentUrl['path'] ?? './') . $queryParams); | ||
119 | } | ||
74 | } | 120 | } |
@@ -451,35 +451,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM | |||
451 | 451 | ||
452 | // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) | 452 | // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) |
453 | if (isset($_GET['removetag'])) { | 453 | if (isset($_GET['removetag'])) { |
454 | // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query. | 454 | header('Location: ./remove-tag/'. $_GET['removetag']); |
455 | if (empty($_SERVER['HTTP_REFERER'])) { | ||
456 | header('Location: ?'); | ||
457 | exit; | ||
458 | } | ||
459 | |||
460 | // In case browser does not send HTTP_REFERER | ||
461 | parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); | ||
462 | |||
463 | // Prevent redirection loop | ||
464 | if (isset($params['removetag'])) { | ||
465 | unset($params['removetag']); | ||
466 | } | ||
467 | |||
468 | if (isset($params['searchtags'])) { | ||
469 | $tags = explode(' ', $params['searchtags']); | ||
470 | // Remove value from array $tags. | ||
471 | $tags = array_diff($tags, array($_GET['removetag'])); | ||
472 | $params['searchtags'] = implode(' ', $tags); | ||
473 | |||
474 | if (empty($params['searchtags'])) { | ||
475 | unset($params['searchtags']); | ||
476 | } | ||
477 | |||
478 | // We also remove page (keeping the same page has no sense, since | ||
479 | // the results are different) | ||
480 | unset($params['page']); | ||
481 | } | ||
482 | header('Location: ?'.http_build_query($params)); | ||
483 | exit; | 455 | exit; |
484 | } | 456 | } |
485 | 457 | ||
@@ -1576,6 +1548,7 @@ $app->group('', function () { | |||
1576 | $this->get('/open-search', '\Shaarli\Front\Controller\OpenSearchController:index')->setName('opensearch'); | 1548 | $this->get('/open-search', '\Shaarli\Front\Controller\OpenSearchController:index')->setName('opensearch'); |
1577 | 1549 | ||
1578 | $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\TagController:addTag')->setName('add-tag'); | 1550 | $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\TagController:addTag')->setName('add-tag'); |
1551 | $this->get('/remove-tag/{tag}', '\Shaarli\Front\Controller\TagController:removeTag')->setName('remove-tag'); | ||
1579 | })->add('\Shaarli\Front\ShaarliMiddleware'); | 1552 | })->add('\Shaarli\Front\ShaarliMiddleware'); |
1580 | 1553 | ||
1581 | $response = $app->run(true); | 1554 | $response = $app->run(true); |
diff --git a/tests/front/controller/TagControllerTest.php b/tests/front/controller/TagControllerTest.php index 5eea537b..2184cb11 100644 --- a/tests/front/controller/TagControllerTest.php +++ b/tests/front/controller/TagControllerTest.php | |||
@@ -157,4 +157,86 @@ class TagControllerTest extends TestCase | |||
157 | static::assertSame(302, $result->getStatusCode()); | 157 | static::assertSame(302, $result->getStatusCode()); |
158 | static::assertSame(['./'], $result->getHeader('location')); | 158 | static::assertSame(['./'], $result->getHeader('location')); |
159 | } | 159 | } |
160 | |||
161 | public function testRemoveTagWithoutMatchingTag(): void | ||
162 | { | ||
163 | $this->createValidContainerMockSet(); | ||
164 | |||
165 | $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; | ||
166 | |||
167 | $request = $this->createMock(Request::class); | ||
168 | $response = new Response(); | ||
169 | |||
170 | $tags = ['tag' => 'abc']; | ||
171 | |||
172 | $result = $this->controller->removeTag($request, $response, $tags); | ||
173 | |||
174 | static::assertInstanceOf(Response::class, $result); | ||
175 | static::assertSame(302, $result->getStatusCode()); | ||
176 | static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); | ||
177 | } | ||
178 | |||
179 | public function testRemoveTagWithoutTagsearch(): void | ||
180 | { | ||
181 | $this->createValidContainerMockSet(); | ||
182 | |||
183 | $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; | ||
184 | |||
185 | $request = $this->createMock(Request::class); | ||
186 | $response = new Response(); | ||
187 | |||
188 | $tags = ['tag' => 'abc']; | ||
189 | |||
190 | $result = $this->controller->removeTag($request, $response, $tags); | ||
191 | |||
192 | static::assertInstanceOf(Response::class, $result); | ||
193 | static::assertSame(302, $result->getStatusCode()); | ||
194 | static::assertSame(['/controller/'], $result->getHeader('location')); | ||
195 | } | ||
196 | |||
197 | public function testRemoveTagWithoutReferer(): void | ||
198 | { | ||
199 | $this->createValidContainerMockSet(); | ||
200 | |||
201 | $request = $this->createMock(Request::class); | ||
202 | $response = new Response(); | ||
203 | |||
204 | $tags = ['tag' => 'abc']; | ||
205 | |||
206 | $result = $this->controller->removeTag($request, $response, $tags); | ||
207 | |||
208 | static::assertInstanceOf(Response::class, $result); | ||
209 | static::assertSame(302, $result->getStatusCode()); | ||
210 | static::assertSame(['./'], $result->getHeader('location')); | ||
211 | } | ||
212 | |||
213 | public function testRemoveTagWithoutTag(): void | ||
214 | { | ||
215 | $this->createValidContainerMockSet(); | ||
216 | |||
217 | $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc']; | ||
218 | |||
219 | $request = $this->createMock(Request::class); | ||
220 | $response = new Response(); | ||
221 | |||
222 | $result = $this->controller->removeTag($request, $response, []); | ||
223 | |||
224 | static::assertInstanceOf(Response::class, $result); | ||
225 | static::assertSame(302, $result->getStatusCode()); | ||
226 | static::assertSame(['/controller/?searchtag=abc'], $result->getHeader('location')); | ||
227 | } | ||
228 | |||
229 | public function testRemoveTagWithoutTagWithoutReferer(): void | ||
230 | { | ||
231 | $this->createValidContainerMockSet(); | ||
232 | |||
233 | $request = $this->createMock(Request::class); | ||
234 | $response = new Response(); | ||
235 | |||
236 | $result = $this->controller->removeTag($request, $response, []); | ||
237 | |||
238 | static::assertInstanceOf(Response::class, $result); | ||
239 | static::assertSame(302, $result->getStatusCode()); | ||
240 | static::assertSame(['./'], $result->getHeader('location')); | ||
241 | } | ||
160 | } | 242 | } |
diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html index d8a15823..e574a109 100644 --- a/tpl/default/linklist.html +++ b/tpl/default/linklist.html | |||
@@ -94,7 +94,9 @@ | |||
94 | {'tagged'|t} | 94 | {'tagged'|t} |
95 | {loop="$exploded_tags"} | 95 | {loop="$exploded_tags"} |
96 | <span class="label label-tag" title="{'Remove tag'|t}"> | 96 | <span class="label label-tag" title="{'Remove tag'|t}"> |
97 | <a href="?removetag={function="urlencode($value)"}" aria-label="{'Remove tag'|t}">{$value}<span class="remove"><i class="fa fa-times" aria-hidden="true"></i></span></a> | 97 | <a href="./remove-tag/{function="urlencode($value)"}" aria-label="{'Remove tag'|t}"> |
98 | {$value}<span class="remove"><i class="fa fa-times" aria-hidden="true"></i></span> | ||
99 | </a> | ||
98 | </span> | 100 | </span> |
99 | {/loop} | 101 | {/loop} |
100 | {/if} | 102 | {/if} |
diff --git a/tpl/vintage/linklist.html b/tpl/vintage/linklist.html index 8f1ded95..502abcf9 100644 --- a/tpl/vintage/linklist.html +++ b/tpl/vintage/linklist.html | |||
@@ -66,7 +66,7 @@ | |||
66 | tagged | 66 | tagged |
67 | {loop="$exploded_tags"} | 67 | {loop="$exploded_tags"} |
68 | <span class="linktag" title="Remove tag"> | 68 | <span class="linktag" title="Remove tag"> |
69 | <a href="?removetag={function="urlencode($value)"}">{$value} <span class="remove">x</span></a> | 69 | <a href="./remove-tag/{function="urlencode($value)"}">{$value} <span class="remove">x</span></a> |
70 | </span> | 70 | </span> |
71 | {/loop} | 71 | {/loop} |
72 | {elseif="$search_tags === false"} | 72 | {elseif="$search_tags === false"} |