aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--application/front/controllers/TagController.php48
-rw-r--r--index.php31
-rw-r--r--tests/front/controller/TagControllerTest.php82
-rw-r--r--tpl/default/linklist.html4
-rw-r--r--tpl/vintage/linklist.html2
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}
diff --git a/index.php b/index.php
index 04ec0d73..c0e0c66d 100644
--- a/index.php
+++ b/index.php
@@ -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"}