aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--application/front/controller/admin/ManageShaareController.php (renamed from application/front/controller/admin/PostBookmarkController.php)44
-rw-r--r--index.php10
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php47
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php361
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php315
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php155
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php282
-rw-r--r--tests/front/controller/admin/PostBookmarkControllerTest.php633
8 files changed, 1197 insertions, 650 deletions
diff --git a/application/front/controller/admin/PostBookmarkController.php b/application/front/controller/admin/ManageShaareController.php
index f3ee5dea..620bbc40 100644
--- a/application/front/controller/admin/PostBookmarkController.php
+++ b/application/front/controller/admin/ManageShaareController.php
@@ -16,7 +16,7 @@ use Slim\Http\Response;
16 * 16 *
17 * Slim controller used to handle Shaarli create or edit bookmarks. 17 * Slim controller used to handle Shaarli create or edit bookmarks.
18 */ 18 */
19class PostBookmarkController extends ShaarliAdminController 19class ManageShaareController extends ShaarliAdminController
20{ 20{
21 /** 21 /**
22 * GET /admin/add-shaare - Displays the form used to create a new bookmark from an URL 22 * GET /admin/add-shaare - Displays the form used to create a new bookmark from an URL
@@ -33,7 +33,7 @@ class PostBookmarkController extends ShaarliAdminController
33 33
34 /** 34 /**
35 * GET /admin/shaare - Displays the bookmark form for creation. 35 * GET /admin/shaare - Displays the bookmark form for creation.
36 * Note that if the URL is found in existing bookmarks, then it will be in edit mode. 36 * Note that if the URL is found in existing bookmarks, then it will be in edit mode.
37 */ 37 */
38 public function displayCreateForm(Request $request, Response $response): Response 38 public function displayCreateForm(Request $request, Response $response): Response
39 { 39 {
@@ -97,14 +97,17 @@ class PostBookmarkController extends ShaarliAdminController
97 */ 97 */
98 public function displayEditForm(Request $request, Response $response, array $args): Response 98 public function displayEditForm(Request $request, Response $response, array $args): Response
99 { 99 {
100 $id = $args['id']; 100 $id = $args['id'] ?? '';
101 try { 101 try {
102 if (false === ctype_digit($id)) { 102 if (false === ctype_digit($id)) {
103 throw new BookmarkNotFoundException(); 103 throw new BookmarkNotFoundException();
104 } 104 }
105 $bookmark = $this->container->bookmarkService->get($id); // Read database 105 $bookmark = $this->container->bookmarkService->get((int) $id); // Read database
106 } catch (BookmarkNotFoundException $e) { 106 } catch (BookmarkNotFoundException $e) {
107 $this->saveErrorMessage(t('Bookmark not found')); 107 $this->saveErrorMessage(sprintf(
108 t('Bookmark with identifier %s could not be found.'),
109 $id
110 ));
108 111
109 return $this->redirect($response, '/'); 112 return $this->redirect($response, '/');
110 } 113 }
@@ -177,10 +180,10 @@ class PostBookmarkController extends ShaarliAdminController
177 { 180 {
178 $this->checkToken($request); 181 $this->checkToken($request);
179 182
180 $ids = escape(trim($request->getParam('id'))); 183 $ids = escape(trim($request->getParam('id') ?? ''));
181 if (strpos($ids, ' ') !== false) { 184 if (empty($ids) || strpos($ids, ' ') !== false) {
182 // multiple, space-separated ids provided 185 // multiple, space-separated ids provided
183 $ids = array_values(array_filter(preg_split('/\s+/', $ids), 'strlen')); 186 $ids = array_values(array_filter(preg_split('/\s+/', $ids), 'ctype_digit'));
184 } else { 187 } else {
185 $ids = [$ids]; 188 $ids = [$ids];
186 } 189 }
@@ -193,16 +196,28 @@ class PostBookmarkController extends ShaarliAdminController
193 } 196 }
194 197
195 $formatter = $this->container->formatterFactory->getFormatter('raw'); 198 $formatter = $this->container->formatterFactory->getFormatter('raw');
199 $count = 0;
196 foreach ($ids as $id) { 200 foreach ($ids as $id) {
197 $id = (int) $id; 201 try {
198 // TODO: check if it exists 202 $bookmark = $this->container->bookmarkService->get((int) $id);
199 $bookmark = $this->container->bookmarkService->get($id); 203 } catch (BookmarkNotFoundException $e) {
204 $this->saveErrorMessage(sprintf(
205 t('Bookmark with identifier %s could not be found.'),
206 $id
207 ));
208
209 continue;
210 }
211
200 $data = $formatter->format($bookmark); 212 $data = $formatter->format($bookmark);
201 $this->container->pluginManager->executeHooks('delete_link', $data); 213 $this->container->pluginManager->executeHooks('delete_link', $data);
202 $this->container->bookmarkService->remove($bookmark, false); 214 $this->container->bookmarkService->remove($bookmark, false);
215 ++ $count;
203 } 216 }
204 217
205 $this->container->bookmarkService->save(); 218 if ($count > 0) {
219 $this->container->bookmarkService->save();
220 }
206 221
207 // If we are called from the bookmarklet, we must close the popup: 222 // If we are called from the bookmarklet, we must close the popup:
208 if ($request->getParam('source') === 'bookmarklet') { 223 if ($request->getParam('source') === 'bookmarklet') {
@@ -213,6 +228,11 @@ class PostBookmarkController extends ShaarliAdminController
213 return $this->redirect($response, '/'); 228 return $this->redirect($response, '/');
214 } 229 }
215 230
231 /**
232 * Helper function used to display the shaare form whether it's a new or existing bookmark.
233 *
234 * @param array $link data used in template, either from parameters or from the data store
235 */
216 protected function displayForm(array $link, bool $isNew, Request $request, Response $response): Response 236 protected function displayForm(array $link, bool $isNew, Request $request, Response $response): Response
217 { 237 {
218 $tags = $this->container->bookmarkService->bookmarksCountPerTag(); 238 $tags = $this->container->bookmarkService->bookmarksCountPerTag();
diff --git a/index.php b/index.php
index aa358da0..12c7a8f1 100644
--- a/index.php
+++ b/index.php
@@ -1159,11 +1159,11 @@ $app->group('', function () {
1159 $this->post('/admin/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:save'); 1159 $this->post('/admin/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:save');
1160 $this->get('/admin/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:index'); 1160 $this->get('/admin/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:index');
1161 $this->post('/admin/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:save'); 1161 $this->post('/admin/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:save');
1162 $this->get('/admin/add-shaare', '\Shaarli\Front\Controller\Admin\PostBookmarkController:addShaare'); 1162 $this->get('/admin/add-shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:addShaare');
1163 $this->get('/admin/shaare', '\Shaarli\Front\Controller\Admin\PostBookmarkController:displayCreateForm'); 1163 $this->get('/admin/shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:displayCreateForm');
1164 $this->get('/admin/shaare/{id:[0-9]+}', '\Shaarli\Front\Controller\Admin\PostBookmarkController:displayEditForm'); 1164 $this->get('/admin/shaare/{id:[0-9]+}', '\Shaarli\Front\Controller\Admin\ManageShaareController:displayEditForm');
1165 $this->post('/admin/shaare', '\Shaarli\Front\Controller\Admin\PostBookmarkController:save'); 1165 $this->post('/admin/shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:save');
1166 $this->get('/admin/shaare/delete', '\Shaarli\Front\Controller\Admin\PostBookmarkController:deleteBookmark'); 1166 $this->get('/admin/shaare/delete', '\Shaarli\Front\Controller\Admin\ManageShaareController:deleteBookmark');
1167 1167
1168 $this->get('/links-per-page', '\Shaarli\Front\Controller\Admin\SessionFilterController:linksPerPage'); 1168 $this->get('/links-per-page', '\Shaarli\Front\Controller\Admin\SessionFilterController:linksPerPage');
1169 $this->get('/visibility/{visibility}', '\Shaarli\Front\Controller\Admin\SessionFilterController:visibility'); 1169 $this->get('/visibility/{visibility}', '\Shaarli\Front\Controller\Admin\SessionFilterController:visibility');
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php b/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
new file mode 100644
index 00000000..7d5b752a
--- /dev/null
+++ b/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
@@ -0,0 +1,47 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
9use Shaarli\Front\Controller\Admin\ManageShaareController;
10use Shaarli\Http\HttpAccess;
11use Slim\Http\Request;
12use Slim\Http\Response;
13
14class AddShaareTest extends TestCase
15{
16 use FrontAdminControllerMockHelper;
17
18 /** @var ManageShaareController */
19 protected $controller;
20
21 public function setUp(): void
22 {
23 $this->createContainer();
24
25 $this->container->httpAccess = $this->createMock(HttpAccess::class);
26 $this->controller = new ManageShaareController($this->container);
27 }
28
29 /**
30 * Test displaying add link page
31 */
32 public function testAddShaare(): void
33 {
34 $assignedVariables = [];
35 $this->assignTemplateVars($assignedVariables);
36
37 $request = $this->createMock(Request::class);
38 $response = new Response();
39
40 $result = $this->controller->addShaare($request, $response);
41
42 static::assertSame(200, $result->getStatusCode());
43 static::assertSame('addlink', (string) $result->getBody());
44
45 static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']);
46 }
47}
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
new file mode 100644
index 00000000..caaf549d
--- /dev/null
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
@@ -0,0 +1,361 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Bookmark\Bookmark;
9use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
10use Shaarli\Formatter\BookmarkFormatter;
11use Shaarli\Formatter\FormatterFactory;
12use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
13use Shaarli\Front\Controller\Admin\ManageShaareController;
14use Shaarli\Http\HttpAccess;
15use Shaarli\Security\SessionManager;
16use Slim\Http\Request;
17use Slim\Http\Response;
18
19class DeleteBookmarkTest extends TestCase
20{
21 use FrontAdminControllerMockHelper;
22
23 /** @var ManageShaareController */
24 protected $controller;
25
26 public function setUp(): void
27 {
28 $this->createContainer();
29
30 $this->container->httpAccess = $this->createMock(HttpAccess::class);
31 $this->controller = new ManageShaareController($this->container);
32 }
33
34 /**
35 * Delete bookmark - Single bookmark with valid parameters
36 */
37 public function testDeleteSingleBookmark(): void
38 {
39 $parameters = ['id' => '123'];
40
41 $request = $this->createMock(Request::class);
42 $request
43 ->method('getParam')
44 ->willReturnCallback(function (string $key) use ($parameters): ?string {
45 return $parameters[$key] ?? null;
46 })
47 ;
48 $response = new Response();
49
50 $bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123');
51
52 $this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
53 $this->container->bookmarkService->expects(static::once())->method('remove')->with($bookmark, false);
54 $this->container->bookmarkService->expects(static::once())->method('save');
55 $this->container->formatterFactory = $this->createMock(FormatterFactory::class);
56 $this->container->formatterFactory
57 ->expects(static::once())
58 ->method('getFormatter')
59 ->with('raw')
60 ->willReturnCallback(function () use ($bookmark): BookmarkFormatter {
61 $formatter = $this->createMock(BookmarkFormatter::class);
62
63 $formatter->expects(static::once())->method('format')->with($bookmark);
64
65 return $formatter;
66 })
67 ;
68
69 // Make sure that PluginManager hook is triggered
70 $this->container->pluginManager
71 ->expects(static::once())
72 ->method('executeHooks')
73 ->with('delete_link')
74 ;
75
76 $result = $this->controller->deleteBookmark($request, $response);
77
78 static::assertSame(302, $result->getStatusCode());
79 static::assertSame(['/subfolder/'], $result->getHeader('location'));
80 }
81
82 /**
83 * Delete bookmark - Multiple bookmarks with valid parameters
84 */
85 public function testDeleteMultipleBookmarks(): void
86 {
87 $parameters = ['id' => '123 456 789'];
88
89 $request = $this->createMock(Request::class);
90 $request
91 ->method('getParam')
92 ->willReturnCallback(function (string $key) use ($parameters): ?string {
93 return $parameters[$key] ?? null;
94 })
95 ;
96 $response = new Response();
97
98 $bookmarks = [
99 (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123'),
100 (new Bookmark())->setId(456)->setUrl('http://domain.tld')->setTitle('Title 456'),
101 (new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789'),
102 ];
103
104 $this->container->bookmarkService
105 ->expects(static::exactly(3))
106 ->method('get')
107 ->withConsecutive([123], [456], [789])
108 ->willReturnOnConsecutiveCalls(...$bookmarks)
109 ;
110 $this->container->bookmarkService
111 ->expects(static::exactly(3))
112 ->method('remove')
113 ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
114 return [$bookmark, false];
115 }, $bookmarks))
116 ;
117 $this->container->bookmarkService->expects(static::once())->method('save');
118 $this->container->formatterFactory = $this->createMock(FormatterFactory::class);
119 $this->container->formatterFactory
120 ->expects(static::once())
121 ->method('getFormatter')
122 ->with('raw')
123 ->willReturnCallback(function () use ($bookmarks): BookmarkFormatter {
124 $formatter = $this->createMock(BookmarkFormatter::class);
125
126 $formatter
127 ->expects(static::exactly(3))
128 ->method('format')
129 ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
130 return [$bookmark];
131 }, $bookmarks))
132 ;
133
134 return $formatter;
135 })
136 ;
137
138 // Make sure that PluginManager hook is triggered
139 $this->container->pluginManager
140 ->expects(static::exactly(3))
141 ->method('executeHooks')
142 ->with('delete_link')
143 ;
144
145 $result = $this->controller->deleteBookmark($request, $response);
146
147 static::assertSame(302, $result->getStatusCode());
148 static::assertSame(['/subfolder/'], $result->getHeader('location'));
149 }
150
151 /**
152 * Delete bookmark - Single bookmark not found in the data store
153 */
154 public function testDeleteSingleBookmarkNotFound(): void
155 {
156 $parameters = ['id' => '123'];
157
158 $request = $this->createMock(Request::class);
159 $request
160 ->method('getParam')
161 ->willReturnCallback(function (string $key) use ($parameters): ?string {
162 return $parameters[$key] ?? null;
163 })
164 ;
165 $response = new Response();
166
167 $this->container->bookmarkService
168 ->expects(static::once())
169 ->method('get')
170 ->willThrowException(new BookmarkNotFoundException())
171 ;
172 $this->container->bookmarkService->expects(static::never())->method('remove');
173 $this->container->bookmarkService->expects(static::never())->method('save');
174 $this->container->formatterFactory = $this->createMock(FormatterFactory::class);
175 $this->container->formatterFactory
176 ->expects(static::once())
177 ->method('getFormatter')
178 ->with('raw')
179 ->willReturnCallback(function (): BookmarkFormatter {
180 $formatter = $this->createMock(BookmarkFormatter::class);
181
182 $formatter->expects(static::never())->method('format');
183
184 return $formatter;
185 })
186 ;
187 // Make sure that PluginManager hook is not triggered
188 $this->container->pluginManager
189 ->expects(static::never())
190 ->method('executeHooks')
191 ->with('delete_link')
192 ;
193
194 $result = $this->controller->deleteBookmark($request, $response);
195
196 static::assertSame(302, $result->getStatusCode());
197 static::assertSame(['/subfolder/'], $result->getHeader('location'));
198 }
199
200 /**
201 * Delete bookmark - Multiple bookmarks with one not found in the data store
202 */
203 public function testDeleteMultipleBookmarksOneNotFound(): void
204 {
205 $parameters = ['id' => '123 456 789'];
206
207 $request = $this->createMock(Request::class);
208 $request
209 ->method('getParam')
210 ->willReturnCallback(function (string $key) use ($parameters): ?string {
211 return $parameters[$key] ?? null;
212 })
213 ;
214 $response = new Response();
215
216 $bookmarks = [
217 (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123'),
218 (new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789'),
219 ];
220
221 $this->container->bookmarkService
222 ->expects(static::exactly(3))
223 ->method('get')
224 ->withConsecutive([123], [456], [789])
225 ->willReturnCallback(function (int $id) use ($bookmarks): Bookmark {
226 if ($id === 123) {
227 return $bookmarks[0];
228 }
229 if ($id === 789) {
230 return $bookmarks[1];
231 }
232 throw new BookmarkNotFoundException();
233 })
234 ;
235 $this->container->bookmarkService
236 ->expects(static::exactly(2))
237 ->method('remove')
238 ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
239 return [$bookmark, false];
240 }, $bookmarks))
241 ;
242 $this->container->bookmarkService->expects(static::once())->method('save');
243 $this->container->formatterFactory = $this->createMock(FormatterFactory::class);
244 $this->container->formatterFactory
245 ->expects(static::once())
246 ->method('getFormatter')
247 ->with('raw')
248 ->willReturnCallback(function () use ($bookmarks): BookmarkFormatter {
249 $formatter = $this->createMock(BookmarkFormatter::class);
250
251 $formatter
252 ->expects(static::exactly(2))
253 ->method('format')
254 ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
255 return [$bookmark];
256 }, $bookmarks))
257 ;
258
259 return $formatter;
260 })
261 ;
262
263 // Make sure that PluginManager hook is not triggered
264 $this->container->pluginManager
265 ->expects(static::exactly(2))
266 ->method('executeHooks')
267 ->with('delete_link')
268 ;
269
270 $this->container->sessionManager
271 ->expects(static::once())
272 ->method('setSessionParameter')
273 ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 456 could not be found.'])
274 ;
275
276 $result = $this->controller->deleteBookmark($request, $response);
277
278 static::assertSame(302, $result->getStatusCode());
279 static::assertSame(['/subfolder/'], $result->getHeader('location'));
280 }
281
282 /**
283 * Delete bookmark - Invalid ID
284 */
285 public function testDeleteInvalidId(): void
286 {
287 $parameters = ['id' => 'nope not an ID'];
288
289 $request = $this->createMock(Request::class);
290 $request
291 ->method('getParam')
292 ->willReturnCallback(function (string $key) use ($parameters): ?string {
293 return $parameters[$key] ?? null;
294 })
295 ;
296 $response = new Response();
297
298 $this->container->sessionManager
299 ->expects(static::once())
300 ->method('setSessionParameter')
301 ->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
302 ;
303
304 $result = $this->controller->deleteBookmark($request, $response);
305
306 static::assertSame(302, $result->getStatusCode());
307 static::assertSame(['/subfolder/'], $result->getHeader('location'));
308 }
309
310 /**
311 * Delete bookmark - Empty ID
312 */
313 public function testDeleteEmptyId(): void
314 {
315 $request = $this->createMock(Request::class);
316 $response = new Response();
317
318 $this->container->sessionManager
319 ->expects(static::once())
320 ->method('setSessionParameter')
321 ->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
322 ;
323
324 $result = $this->controller->deleteBookmark($request, $response);
325
326 static::assertSame(302, $result->getStatusCode());
327 static::assertSame(['/subfolder/'], $result->getHeader('location'));
328 }
329
330 /**
331 * Delete bookmark - from bookmarklet
332 */
333 public function testDeleteBookmarkFromBookmarklet(): void
334 {
335 $parameters = [
336 'id' => '123',
337 'source' => 'bookmarklet',
338 ];
339
340 $request = $this->createMock(Request::class);
341 $request
342 ->method('getParam')
343 ->willReturnCallback(function (string $key) use ($parameters): ?string {
344 return $parameters[$key] ?? null;
345 })
346 ;
347 $response = new Response();
348
349 $this->container->formatterFactory = $this->createMock(FormatterFactory::class);
350 $this->container->formatterFactory
351 ->expects(static::once())
352 ->method('getFormatter')
353 ->willReturn($this->createMock(BookmarkFormatter::class))
354 ;
355
356 $result = $this->controller->deleteBookmark($request, $response);
357
358 static::assertSame(200, $result->getStatusCode());
359 static::assertSame('<script>self.close();</script>', (string) $result->getBody('location'));
360 }
361}
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php
new file mode 100644
index 00000000..777583d5
--- /dev/null
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php
@@ -0,0 +1,315 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Bookmark\Bookmark;
9use Shaarli\Config\ConfigManager;
10use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
11use Shaarli\Front\Controller\Admin\ManageShaareController;
12use Shaarli\Http\HttpAccess;
13use Slim\Http\Request;
14use Slim\Http\Response;
15
16class DisplayCreateFormTest extends TestCase
17{
18 use FrontAdminControllerMockHelper;
19
20 /** @var ManageShaareController */
21 protected $controller;
22
23 public function setUp(): void
24 {
25 $this->createContainer();
26
27 $this->container->httpAccess = $this->createMock(HttpAccess::class);
28 $this->controller = new ManageShaareController($this->container);
29 }
30
31 /**
32 * Test displaying bookmark create form
33 * Ensure that every step of the standard workflow works properly.
34 */
35 public function testDisplayCreateFormWithUrl(): void
36 {
37 $this->container->environment = [
38 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc'
39 ];
40
41 $assignedVariables = [];
42 $this->assignTemplateVars($assignedVariables);
43
44 $url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
45 $expectedUrl = str_replace('&utm_ad=pay', '', $url);
46 $remoteTitle = 'Remote Title';
47 $remoteDesc = 'Sometimes the meta description is relevant.';
48 $remoteTags = 'abc def';
49
50 $request = $this->createMock(Request::class);
51 $request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string {
52 return $key === 'post' ? $url : null;
53 });
54 $response = new Response();
55
56 $this->container->httpAccess
57 ->expects(static::once())
58 ->method('getCurlDownloadCallback')
59 ->willReturnCallback(
60 function (&$charset, &$title, &$description, &$tags) use (
61 $remoteTitle,
62 $remoteDesc,
63 $remoteTags
64 ): callable {
65 return function () use (
66 &$charset,
67 &$title,
68 &$description,
69 &$tags,
70 $remoteTitle,
71 $remoteDesc,
72 $remoteTags
73 ): void {
74 $charset = 'ISO-8859-1';
75 $title = $remoteTitle;
76 $description = $remoteDesc;
77 $tags = $remoteTags;
78 };
79 }
80 )
81 ;
82 $this->container->httpAccess
83 ->expects(static::once())
84 ->method('getHttpResponse')
85 ->with($expectedUrl, 30, 4194304)
86 ->willReturnCallback(function($url, $timeout, $maxBytes, $callback): void {
87 $callback();
88 })
89 ;
90
91 $this->container->bookmarkService
92 ->expects(static::once())
93 ->method('bookmarksCountPerTag')
94 ->willReturn($tags = ['tag1' => 2, 'tag2' => 1])
95 ;
96
97 // Make sure that PluginManager hook is triggered
98 $this->container->pluginManager
99 ->expects(static::at(0))
100 ->method('executeHooks')
101 ->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array {
102 static::assertSame('render_editlink', $hook);
103 static::assertSame($remoteTitle, $data['link']['title']);
104 static::assertSame($remoteDesc, $data['link']['description']);
105
106 return $data;
107 })
108 ;
109
110 $result = $this->controller->displayCreateForm($request, $response);
111
112 static::assertSame(200, $result->getStatusCode());
113 static::assertSame('editlink', (string) $result->getBody());
114
115 static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
116
117 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
118 static::assertSame($remoteTitle, $assignedVariables['link']['title']);
119 static::assertSame($remoteDesc, $assignedVariables['link']['description']);
120 static::assertSame($remoteTags, $assignedVariables['link']['tags']);
121 static::assertFalse($assignedVariables['link']['private']);
122
123 static::assertTrue($assignedVariables['link_is_new']);
124 static::assertSame($referer, $assignedVariables['http_referer']);
125 static::assertSame($tags, $assignedVariables['tags']);
126 static::assertArrayHasKey('source', $assignedVariables);
127 static::assertArrayHasKey('default_private_links', $assignedVariables);
128 }
129
130 /**
131 * Test displaying bookmark create form
132 * Ensure all available query parameters are handled properly.
133 */
134 public function testDisplayCreateFormWithFullParameters(): void
135 {
136 $assignedVariables = [];
137 $this->assignTemplateVars($assignedVariables);
138
139 $parameters = [
140 'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash',
141 'title' => 'Provided Title',
142 'description' => 'Provided description.',
143 'tags' => 'abc def',
144 'private' => '1',
145 'source' => 'apps',
146 ];
147 $expectedUrl = str_replace('&utm_ad=pay', '', $parameters['post']);
148
149 $request = $this->createMock(Request::class);
150 $request
151 ->method('getParam')
152 ->willReturnCallback(function (string $key) use ($parameters): ?string {
153 return $parameters[$key] ?? null;
154 });
155 $response = new Response();
156
157 $result = $this->controller->displayCreateForm($request, $response);
158
159 static::assertSame(200, $result->getStatusCode());
160 static::assertSame('editlink', (string) $result->getBody());
161
162 static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
163
164 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
165 static::assertSame($parameters['title'], $assignedVariables['link']['title']);
166 static::assertSame($parameters['description'], $assignedVariables['link']['description']);
167 static::assertSame($parameters['tags'], $assignedVariables['link']['tags']);
168 static::assertTrue($assignedVariables['link']['private']);
169 static::assertTrue($assignedVariables['link_is_new']);
170 static::assertSame($parameters['source'], $assignedVariables['source']);
171 }
172
173 /**
174 * Test displaying bookmark create form
175 * Without any parameter.
176 */
177 public function testDisplayCreateFormEmpty(): void
178 {
179 $assignedVariables = [];
180 $this->assignTemplateVars($assignedVariables);
181
182 $request = $this->createMock(Request::class);
183 $response = new Response();
184
185 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
186 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
187
188 $result = $this->controller->displayCreateForm($request, $response);
189
190 static::assertSame(200, $result->getStatusCode());
191 static::assertSame('editlink', (string) $result->getBody());
192 static::assertSame('', $assignedVariables['link']['url']);
193 static::assertSame('Note: ', $assignedVariables['link']['title']);
194 static::assertSame('', $assignedVariables['link']['description']);
195 static::assertSame('', $assignedVariables['link']['tags']);
196 static::assertFalse($assignedVariables['link']['private']);
197 static::assertTrue($assignedVariables['link_is_new']);
198 }
199
200 /**
201 * Test displaying bookmark create form
202 * URL not using HTTP protocol: do not try to retrieve the title
203 */
204 public function testDisplayCreateFormNotHttp(): void
205 {
206 $assignedVariables = [];
207 $this->assignTemplateVars($assignedVariables);
208
209 $url = 'magnet://kubuntu.torrent';
210 $request = $this->createMock(Request::class);
211 $request
212 ->method('getParam')
213 ->willReturnCallback(function (string $key) use ($url): ?string {
214 return $key === 'post' ? $url : null;
215 });
216 $response = new Response();
217
218 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
219 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
220
221 $result = $this->controller->displayCreateForm($request, $response);
222
223 static::assertSame(200, $result->getStatusCode());
224 static::assertSame('editlink', (string) $result->getBody());
225 static::assertSame($url, $assignedVariables['link']['url']);
226 static::assertTrue($assignedVariables['link_is_new']);
227 }
228
229 /**
230 * Test displaying bookmark create form
231 * When markdown formatter is enabled, the no markdown tag should be added to existing tags.
232 */
233 public function testDisplayCreateFormWithMarkdownEnabled(): void
234 {
235 $assignedVariables = [];
236 $this->assignTemplateVars($assignedVariables);
237
238 $this->container->conf = $this->createMock(ConfigManager::class);
239 $this->container->conf
240 ->expects(static::atLeastOnce())
241 ->method('get')->willReturnCallback(function (string $key): ?string {
242 if ($key === 'formatter') {
243 return 'markdown';
244 }
245
246 return $key;
247 })
248 ;
249
250 $request = $this->createMock(Request::class);
251 $response = new Response();
252
253 $result = $this->controller->displayCreateForm($request, $response);
254
255 static::assertSame(200, $result->getStatusCode());
256 static::assertSame('editlink', (string) $result->getBody());
257 static::assertSame(['nomarkdown' => 1], $assignedVariables['tags']);
258 }
259
260 /**
261 * Test displaying bookmark create form
262 * When an existing URL is submitted, we want to edit the existing link.
263 */
264 public function testDisplayCreateFormWithExistingUrl(): void
265 {
266 $assignedVariables = [];
267 $this->assignTemplateVars($assignedVariables);
268
269 $url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
270 $expectedUrl = str_replace('&utm_ad=pay', '', $url);
271
272 $request = $this->createMock(Request::class);
273 $request
274 ->method('getParam')
275 ->willReturnCallback(function (string $key) use ($url): ?string {
276 return $key === 'post' ? $url : null;
277 });
278 $response = new Response();
279
280 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
281 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
282
283 $this->container->bookmarkService
284 ->expects(static::once())
285 ->method('findByUrl')
286 ->with($expectedUrl)
287 ->willReturn(
288 (new Bookmark())
289 ->setId($id = 23)
290 ->setUrl($expectedUrl)
291 ->setTitle($title = 'Bookmark Title')
292 ->setDescription($description = 'Bookmark description.')
293 ->setTags($tags = ['abc', 'def'])
294 ->setPrivate(true)
295 ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44'))
296 )
297 ;
298
299 $result = $this->controller->displayCreateForm($request, $response);
300
301 static::assertSame(200, $result->getStatusCode());
302 static::assertSame('editlink', (string) $result->getBody());
303
304 static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']);
305 static::assertFalse($assignedVariables['link_is_new']);
306
307 static::assertSame($id, $assignedVariables['link']['id']);
308 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
309 static::assertSame($title, $assignedVariables['link']['title']);
310 static::assertSame($description, $assignedVariables['link']['description']);
311 static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']);
312 static::assertTrue($assignedVariables['link']['private']);
313 static::assertSame($createdAt, $assignedVariables['link']['created']);
314 }
315}
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php
new file mode 100644
index 00000000..1a1cdcf3
--- /dev/null
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php
@@ -0,0 +1,155 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Bookmark\Bookmark;
9use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
10use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
11use Shaarli\Front\Controller\Admin\ManageShaareController;
12use Shaarli\Http\HttpAccess;
13use Shaarli\Security\SessionManager;
14use Slim\Http\Request;
15use Slim\Http\Response;
16
17class DisplayEditFormTest extends TestCase
18{
19 use FrontAdminControllerMockHelper;
20
21 /** @var ManageShaareController */
22 protected $controller;
23
24 public function setUp(): void
25 {
26 $this->createContainer();
27
28 $this->container->httpAccess = $this->createMock(HttpAccess::class);
29 $this->controller = new ManageShaareController($this->container);
30 }
31
32 /**
33 * Test displaying bookmark edit form
34 * When an existing ID is provided, ensure that default workflow works properly.
35 */
36 public function testDisplayEditFormDefault(): void
37 {
38 $assignedVariables = [];
39 $this->assignTemplateVars($assignedVariables);
40
41 $id = 11;
42
43 $request = $this->createMock(Request::class);
44 $response = new Response();
45
46 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
47 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
48
49 $this->container->bookmarkService
50 ->expects(static::once())
51 ->method('get')
52 ->with($id)
53 ->willReturn(
54 (new Bookmark())
55 ->setId($id)
56 ->setUrl($url = 'http://domain.tld')
57 ->setTitle($title = 'Bookmark Title')
58 ->setDescription($description = 'Bookmark description.')
59 ->setTags($tags = ['abc', 'def'])
60 ->setPrivate(true)
61 ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44'))
62 )
63 ;
64
65 $result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]);
66
67 static::assertSame(200, $result->getStatusCode());
68 static::assertSame('editlink', (string) $result->getBody());
69
70 static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']);
71 static::assertFalse($assignedVariables['link_is_new']);
72
73 static::assertSame($id, $assignedVariables['link']['id']);
74 static::assertSame($url, $assignedVariables['link']['url']);
75 static::assertSame($title, $assignedVariables['link']['title']);
76 static::assertSame($description, $assignedVariables['link']['description']);
77 static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']);
78 static::assertTrue($assignedVariables['link']['private']);
79 static::assertSame($createdAt, $assignedVariables['link']['created']);
80 }
81
82 /**
83 * Test displaying bookmark edit form
84 * Invalid ID provided.
85 */
86 public function testDisplayEditFormInvalidId(): void
87 {
88 $id = 'invalid';
89
90 $request = $this->createMock(Request::class);
91 $response = new Response();
92
93 $this->container->sessionManager
94 ->expects(static::once())
95 ->method('setSessionParameter')
96 ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier invalid could not be found.'])
97 ;
98
99 $result = $this->controller->displayEditForm($request, $response, ['id' => $id]);
100
101 static::assertSame(302, $result->getStatusCode());
102 static::assertSame(['/subfolder/'], $result->getHeader('location'));
103 }
104
105 /**
106 * Test displaying bookmark edit form
107 * ID not provided.
108 */
109 public function testDisplayEditFormIdNotProvided(): void
110 {
111 $request = $this->createMock(Request::class);
112 $response = new Response();
113
114 $this->container->sessionManager
115 ->expects(static::once())
116 ->method('setSessionParameter')
117 ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier could not be found.'])
118 ;
119
120 $result = $this->controller->displayEditForm($request, $response, []);
121
122 static::assertSame(302, $result->getStatusCode());
123 static::assertSame(['/subfolder/'], $result->getHeader('location'));
124 }
125
126 /**
127 * Test displaying bookmark edit form
128 * Bookmark not found.
129 */
130 public function testDisplayEditFormBookmarkNotFound(): void
131 {
132 $id = 123;
133
134 $request = $this->createMock(Request::class);
135 $response = new Response();
136
137 $this->container->bookmarkService
138 ->expects(static::once())
139 ->method('get')
140 ->with($id)
141 ->willThrowException(new BookmarkNotFoundException())
142 ;
143
144 $this->container->sessionManager
145 ->expects(static::once())
146 ->method('setSessionParameter')
147 ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 123 could not be found.'])
148 ;
149
150 $result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]);
151
152 static::assertSame(302, $result->getStatusCode());
153 static::assertSame(['/subfolder/'], $result->getHeader('location'));
154 }
155}
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
new file mode 100644
index 00000000..dabcd60d
--- /dev/null
+++ b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
@@ -0,0 +1,282 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Bookmark\Bookmark;
9use Shaarli\Config\ConfigManager;
10use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
11use Shaarli\Front\Controller\Admin\ManageShaareController;
12use Shaarli\Front\Exception\WrongTokenException;
13use Shaarli\Http\HttpAccess;
14use Shaarli\Security\SessionManager;
15use Shaarli\Thumbnailer;
16use Slim\Http\Request;
17use Slim\Http\Response;
18
19class SaveBookmarkTest extends TestCase
20{
21 use FrontAdminControllerMockHelper;
22
23 /** @var ManageShaareController */
24 protected $controller;
25
26 public function setUp(): void
27 {
28 $this->createContainer();
29
30 $this->container->httpAccess = $this->createMock(HttpAccess::class);
31 $this->controller = new ManageShaareController($this->container);
32 }
33
34 /**
35 * Test save a new bookmark
36 */
37 public function testSaveBookmark(): void
38 {
39 $id = 21;
40 $parameters = [
41 'lf_url' => 'http://url.tld/other?part=3#hash',
42 'lf_title' => 'Provided Title',
43 'lf_description' => 'Provided description.',
44 'lf_tags' => 'abc def',
45 'lf_private' => '1',
46 'returnurl' => 'http://shaarli.tld/subfolder/admin/add-shaare'
47 ];
48
49 $request = $this->createMock(Request::class);
50 $request
51 ->method('getParam')
52 ->willReturnCallback(function (string $key) use ($parameters): ?string {
53 return $parameters[$key] ?? null;
54 })
55 ;
56 $response = new Response();
57
58 $checkBookmark = function (Bookmark $bookmark) use ($parameters) {
59 static::assertSame($parameters['lf_url'], $bookmark->getUrl());
60 static::assertSame($parameters['lf_title'], $bookmark->getTitle());
61 static::assertSame($parameters['lf_description'], $bookmark->getDescription());
62 static::assertSame($parameters['lf_tags'], $bookmark->getTagsString());
63 static::assertTrue($bookmark->isPrivate());
64 };
65
66 $this->container->bookmarkService
67 ->expects(static::once())
68 ->method('addOrSet')
69 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
70 static::assertFalse($save);
71
72 $checkBookmark($bookmark);
73
74 $bookmark->setId($id);
75 })
76 ;
77 $this->container->bookmarkService
78 ->expects(static::once())
79 ->method('set')
80 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
81 static::assertTrue($save);
82
83 $checkBookmark($bookmark);
84
85 static::assertSame($id, $bookmark->getId());
86 })
87 ;
88
89 // Make sure that PluginManager hook is triggered
90 $this->container->pluginManager
91 ->expects(static::at(0))
92 ->method('executeHooks')
93 ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
94 static::assertSame('save_link', $hook);
95
96 static::assertSame($id, $data['id']);
97 static::assertSame($parameters['lf_url'], $data['url']);
98 static::assertSame($parameters['lf_title'], $data['title']);
99 static::assertSame($parameters['lf_description'], $data['description']);
100 static::assertSame($parameters['lf_tags'], $data['tags']);
101 static::assertTrue($data['private']);
102
103 return $data;
104 })
105 ;
106
107 $result = $this->controller->save($request, $response);
108
109 static::assertSame(302, $result->getStatusCode());
110 static::assertRegExp('@/subfolder/#[\w\-]{6}@', $result->getHeader('location')[0]);
111 }
112
113
114 /**
115 * Test save an existing bookmark
116 */
117 public function testSaveExistingBookmark(): void
118 {
119 $id = 21;
120 $parameters = [
121 'lf_id' => (string) $id,
122 'lf_url' => 'http://url.tld/other?part=3#hash',
123 'lf_title' => 'Provided Title',
124 'lf_description' => 'Provided description.',
125 'lf_tags' => 'abc def',
126 'lf_private' => '1',
127 'returnurl' => 'http://shaarli.tld/subfolder/?page=2'
128 ];
129
130 $request = $this->createMock(Request::class);
131 $request
132 ->method('getParam')
133 ->willReturnCallback(function (string $key) use ($parameters): ?string {
134 return $parameters[$key] ?? null;
135 })
136 ;
137 $response = new Response();
138
139 $checkBookmark = function (Bookmark $bookmark) use ($parameters, $id) {
140 static::assertSame($id, $bookmark->getId());
141 static::assertSame($parameters['lf_url'], $bookmark->getUrl());
142 static::assertSame($parameters['lf_title'], $bookmark->getTitle());
143 static::assertSame($parameters['lf_description'], $bookmark->getDescription());
144 static::assertSame($parameters['lf_tags'], $bookmark->getTagsString());
145 static::assertTrue($bookmark->isPrivate());
146 };
147
148 $this->container->bookmarkService->expects(static::atLeastOnce())->method('exists')->willReturn(true);
149 $this->container->bookmarkService
150 ->expects(static::once())
151 ->method('get')
152 ->willReturn((new Bookmark())->setId($id)->setUrl('http://other.url'))
153 ;
154 $this->container->bookmarkService
155 ->expects(static::once())
156 ->method('addOrSet')
157 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
158 static::assertFalse($save);
159
160 $checkBookmark($bookmark);
161 })
162 ;
163 $this->container->bookmarkService
164 ->expects(static::once())
165 ->method('set')
166 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
167 static::assertTrue($save);
168
169 $checkBookmark($bookmark);
170
171 static::assertSame($id, $bookmark->getId());
172 })
173 ;
174
175 // Make sure that PluginManager hook is triggered
176 $this->container->pluginManager
177 ->expects(static::at(0))
178 ->method('executeHooks')
179 ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
180 static::assertSame('save_link', $hook);
181
182 static::assertSame($id, $data['id']);
183 static::assertSame($parameters['lf_url'], $data['url']);
184 static::assertSame($parameters['lf_title'], $data['title']);
185 static::assertSame($parameters['lf_description'], $data['description']);
186 static::assertSame($parameters['lf_tags'], $data['tags']);
187 static::assertTrue($data['private']);
188
189 return $data;
190 })
191 ;
192
193 $result = $this->controller->save($request, $response);
194
195 static::assertSame(302, $result->getStatusCode());
196 static::assertRegExp('@/subfolder/\?page=2#[\w\-]{6}@', $result->getHeader('location')[0]);
197 }
198
199 /**
200 * Test save a bookmark - try to retrieve the thumbnail
201 */
202 public function testSaveBookmarkWithThumbnail(): void
203 {
204 $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash'];
205
206 $request = $this->createMock(Request::class);
207 $request
208 ->method('getParam')
209 ->willReturnCallback(function (string $key) use ($parameters): ?string {
210 return $parameters[$key] ?? null;
211 })
212 ;
213 $response = new Response();
214
215 $this->container->conf = $this->createMock(ConfigManager::class);
216 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
217 return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default;
218 });
219
220 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
221 $this->container->thumbnailer
222 ->expects(static::once())
223 ->method('get')
224 ->with($parameters['lf_url'])
225 ->willReturn($thumb = 'http://thumb.url')
226 ;
227
228 $this->container->bookmarkService
229 ->expects(static::once())
230 ->method('addOrSet')
231 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): void {
232 static::assertSame($thumb, $bookmark->getThumbnail());
233 })
234 ;
235
236 $result = $this->controller->save($request, $response);
237
238 static::assertSame(302, $result->getStatusCode());
239 }
240
241 /**
242 * Change the password with a wrong existing password
243 */
244 public function testSaveBookmarkFromBookmarklet(): void
245 {
246 $parameters = ['source' => 'bookmarklet'];
247
248 $request = $this->createMock(Request::class);
249 $request
250 ->method('getParam')
251 ->willReturnCallback(function (string $key) use ($parameters): ?string {
252 return $parameters[$key] ?? null;
253 })
254 ;
255 $response = new Response();
256
257 $result = $this->controller->save($request, $response);
258
259 static::assertSame(200, $result->getStatusCode());
260 static::assertSame('<script>self.close();</script>', (string) $result->getBody());
261 }
262
263 /**
264 * Change the password with a wrong existing password
265 */
266 public function testSaveBookmarkWrongToken(): void
267 {
268 $this->container->sessionManager = $this->createMock(SessionManager::class);
269 $this->container->sessionManager->method('checkToken')->willReturn(false);
270
271 $this->container->bookmarkService->expects(static::never())->method('addOrSet');
272 $this->container->bookmarkService->expects(static::never())->method('set');
273
274 $request = $this->createMock(Request::class);
275 $response = new Response();
276
277 $this->expectException(WrongTokenException::class);
278
279 $this->controller->save($request, $response);
280 }
281
282}
diff --git a/tests/front/controller/admin/PostBookmarkControllerTest.php b/tests/front/controller/admin/PostBookmarkControllerTest.php
deleted file mode 100644
index 8dcd1b50..00000000
--- a/tests/front/controller/admin/PostBookmarkControllerTest.php
+++ /dev/null
@@ -1,633 +0,0 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Bookmark\Bookmark;
9use Shaarli\Config\ConfigManager;
10use Shaarli\Front\Exception\WrongTokenException;
11use Shaarli\Http\HttpAccess;
12use Shaarli\Security\SessionManager;
13use Shaarli\Thumbnailer;
14use Slim\Http\Request;
15use Slim\Http\Response;
16
17class PostBookmarkControllerTest extends TestCase
18{
19 use FrontAdminControllerMockHelper;
20
21 /** @var PostBookmarkController */
22 protected $controller;
23
24 public function setUp(): void
25 {
26 $this->createContainer();
27
28 $this->container->httpAccess = $this->createMock(HttpAccess::class);
29 $this->controller = new PostBookmarkController($this->container);
30 }
31
32 /**
33 * Test displaying add link page
34 */
35 public function testAddShaare(): void
36 {
37 $assignedVariables = [];
38 $this->assignTemplateVars($assignedVariables);
39
40 $request = $this->createMock(Request::class);
41 $response = new Response();
42
43 $result = $this->controller->addShaare($request, $response);
44
45 static::assertSame(200, $result->getStatusCode());
46 static::assertSame('addlink', (string) $result->getBody());
47
48 static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']);
49 }
50
51 /**
52 * Test displaying bookmark create form
53 * Ensure that every step of the standard workflow works properly.
54 */
55 public function testDisplayCreateFormWithUrl(): void
56 {
57 $this->container->environment = [
58 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc'
59 ];
60
61 $assignedVariables = [];
62 $this->assignTemplateVars($assignedVariables);
63
64 $url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
65 $expectedUrl = str_replace('&utm_ad=pay', '', $url);
66 $remoteTitle = 'Remote Title';
67 $remoteDesc = 'Sometimes the meta description is relevant.';
68 $remoteTags = 'abc def';
69
70 $request = $this->createMock(Request::class);
71 $request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string {
72 return $key === 'post' ? $url : null;
73 });
74 $response = new Response();
75
76 $this->container->httpAccess
77 ->expects(static::once())
78 ->method('getCurlDownloadCallback')
79 ->willReturnCallback(
80 function (&$charset, &$title, &$description, &$tags) use (
81 $remoteTitle,
82 $remoteDesc,
83 $remoteTags
84 ): callable {
85 return function () use (
86 &$charset,
87 &$title,
88 &$description,
89 &$tags,
90 $remoteTitle,
91 $remoteDesc,
92 $remoteTags
93 ): void {
94 $charset = 'ISO-8859-1';
95 $title = $remoteTitle;
96 $description = $remoteDesc;
97 $tags = $remoteTags;
98 };
99 }
100 )
101 ;
102 $this->container->httpAccess
103 ->expects(static::once())
104 ->method('getHttpResponse')
105 ->with($expectedUrl, 30, 4194304)
106 ->willReturnCallback(function($url, $timeout, $maxBytes, $callback): void {
107 $callback();
108 })
109 ;
110
111 $this->container->bookmarkService
112 ->expects(static::once())
113 ->method('bookmarksCountPerTag')
114 ->willReturn($tags = ['tag1' => 2, 'tag2' => 1])
115 ;
116
117 // Make sure that PluginManager hook is triggered
118 $this->container->pluginManager
119 ->expects(static::at(0))
120 ->method('executeHooks')
121 ->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array {
122 static::assertSame('render_editlink', $hook);
123 static::assertSame($remoteTitle, $data['link']['title']);
124 static::assertSame($remoteDesc, $data['link']['description']);
125
126 return $data;
127 })
128 ;
129
130 $result = $this->controller->displayCreateForm($request, $response);
131
132 static::assertSame(200, $result->getStatusCode());
133 static::assertSame('editlink', (string) $result->getBody());
134
135 static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
136
137 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
138 static::assertSame($remoteTitle, $assignedVariables['link']['title']);
139 static::assertSame($remoteDesc, $assignedVariables['link']['description']);
140 static::assertSame($remoteTags, $assignedVariables['link']['tags']);
141 static::assertFalse($assignedVariables['link']['private']);
142
143 static::assertTrue($assignedVariables['link_is_new']);
144 static::assertSame($referer, $assignedVariables['http_referer']);
145 static::assertSame($tags, $assignedVariables['tags']);
146 static::assertArrayHasKey('source', $assignedVariables);
147 static::assertArrayHasKey('default_private_links', $assignedVariables);
148 }
149
150 /**
151 * Test displaying bookmark create form
152 * Ensure all available query parameters are handled properly.
153 */
154 public function testDisplayCreateFormWithFullParameters(): void
155 {
156 $assignedVariables = [];
157 $this->assignTemplateVars($assignedVariables);
158
159 $parameters = [
160 'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash',
161 'title' => 'Provided Title',
162 'description' => 'Provided description.',
163 'tags' => 'abc def',
164 'private' => '1',
165 'source' => 'apps',
166 ];
167 $expectedUrl = str_replace('&utm_ad=pay', '', $parameters['post']);
168
169 $request = $this->createMock(Request::class);
170 $request
171 ->method('getParam')
172 ->willReturnCallback(function (string $key) use ($parameters): ?string {
173 return $parameters[$key] ?? null;
174 });
175 $response = new Response();
176
177 $result = $this->controller->displayCreateForm($request, $response);
178
179 static::assertSame(200, $result->getStatusCode());
180 static::assertSame('editlink', (string) $result->getBody());
181
182 static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
183
184 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
185 static::assertSame($parameters['title'], $assignedVariables['link']['title']);
186 static::assertSame($parameters['description'], $assignedVariables['link']['description']);
187 static::assertSame($parameters['tags'], $assignedVariables['link']['tags']);
188 static::assertTrue($assignedVariables['link']['private']);
189 static::assertTrue($assignedVariables['link_is_new']);
190 static::assertSame($parameters['source'], $assignedVariables['source']);
191 }
192
193 /**
194 * Test displaying bookmark create form
195 * Without any parameter.
196 */
197 public function testDisplayCreateFormEmpty(): void
198 {
199 $assignedVariables = [];
200 $this->assignTemplateVars($assignedVariables);
201
202 $request = $this->createMock(Request::class);
203 $response = new Response();
204
205 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
206 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
207
208 $result = $this->controller->displayCreateForm($request, $response);
209
210 static::assertSame(200, $result->getStatusCode());
211 static::assertSame('editlink', (string) $result->getBody());
212 static::assertSame('', $assignedVariables['link']['url']);
213 static::assertSame('Note: ', $assignedVariables['link']['title']);
214 static::assertSame('', $assignedVariables['link']['description']);
215 static::assertSame('', $assignedVariables['link']['tags']);
216 static::assertFalse($assignedVariables['link']['private']);
217 static::assertTrue($assignedVariables['link_is_new']);
218 }
219
220 /**
221 * Test displaying bookmark create form
222 * URL not using HTTP protocol: do not try to retrieve the title
223 */
224 public function testDisplayCreateFormNotHttp(): void
225 {
226 $assignedVariables = [];
227 $this->assignTemplateVars($assignedVariables);
228
229 $url = 'magnet://kubuntu.torrent';
230 $request = $this->createMock(Request::class);
231 $request
232 ->method('getParam')
233 ->willReturnCallback(function (string $key) use ($url): ?string {
234 return $key === 'post' ? $url : null;
235 });
236 $response = new Response();
237
238 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
239 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
240
241 $result = $this->controller->displayCreateForm($request, $response);
242
243 static::assertSame(200, $result->getStatusCode());
244 static::assertSame('editlink', (string) $result->getBody());
245 static::assertSame($url, $assignedVariables['link']['url']);
246 static::assertTrue($assignedVariables['link_is_new']);
247 }
248
249 /**
250 * Test displaying bookmark create form
251 * When markdown formatter is enabled, the no markdown tag should be added to existing tags.
252 */
253 public function testDisplayCreateFormWithMarkdownEnabled(): void
254 {
255 $assignedVariables = [];
256 $this->assignTemplateVars($assignedVariables);
257
258 $this->container->conf = $this->createMock(ConfigManager::class);
259 $this->container->conf
260 ->expects(static::atLeastOnce())
261 ->method('get')->willReturnCallback(function (string $key): ?string {
262 if ($key === 'formatter') {
263 return 'markdown';
264 }
265
266 return $key;
267 })
268 ;
269
270 $request = $this->createMock(Request::class);
271 $response = new Response();
272
273 $result = $this->controller->displayCreateForm($request, $response);
274
275 static::assertSame(200, $result->getStatusCode());
276 static::assertSame('editlink', (string) $result->getBody());
277 static::assertSame(['nomarkdown' => 1], $assignedVariables['tags']);
278 }
279
280 /**
281 * Test displaying bookmark create form
282 * When an existing URL is submitted, we want to edit the existing link.
283 */
284 public function testDisplayCreateFormWithExistingUrl(): void
285 {
286 $assignedVariables = [];
287 $this->assignTemplateVars($assignedVariables);
288
289 $url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
290 $expectedUrl = str_replace('&utm_ad=pay', '', $url);
291
292 $request = $this->createMock(Request::class);
293 $request
294 ->method('getParam')
295 ->willReturnCallback(function (string $key) use ($url): ?string {
296 return $key === 'post' ? $url : null;
297 });
298 $response = new Response();
299
300 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
301 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
302
303 $this->container->bookmarkService
304 ->expects(static::once())
305 ->method('findByUrl')
306 ->with($expectedUrl)
307 ->willReturn(
308 (new Bookmark())
309 ->setId($id = 23)
310 ->setUrl($expectedUrl)
311 ->setTitle($title = 'Bookmark Title')
312 ->setDescription($description = 'Bookmark description.')
313 ->setTags($tags = ['abc', 'def'])
314 ->setPrivate(true)
315 ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44'))
316 )
317 ;
318
319 $result = $this->controller->displayCreateForm($request, $response);
320
321 static::assertSame(200, $result->getStatusCode());
322 static::assertSame('editlink', (string) $result->getBody());
323
324 static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']);
325 static::assertFalse($assignedVariables['link_is_new']);
326
327 static::assertSame($id, $assignedVariables['link']['id']);
328 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
329 static::assertSame($title, $assignedVariables['link']['title']);
330 static::assertSame($description, $assignedVariables['link']['description']);
331 static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']);
332 static::assertTrue($assignedVariables['link']['private']);
333 static::assertSame($createdAt, $assignedVariables['link']['created']);
334 }
335
336 /**
337 * Test displaying bookmark edit form
338 * When an existing ID is provided, ensure that default workflow works properly.
339 */
340 public function testDisplayEditFormDefault(): void
341 {
342 $assignedVariables = [];
343 $this->assignTemplateVars($assignedVariables);
344
345 $id = 11;
346
347 $request = $this->createMock(Request::class);
348 $response = new Response();
349
350 $this->container->httpAccess->expects(static::never())->method('getHttpResponse');
351 $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
352
353 $this->container->bookmarkService
354 ->expects(static::once())
355 ->method('get')
356 ->with($id)
357 ->willReturn(
358 (new Bookmark())
359 ->setId($id)
360 ->setUrl($url = 'http://domain.tld')
361 ->setTitle($title = 'Bookmark Title')
362 ->setDescription($description = 'Bookmark description.')
363 ->setTags($tags = ['abc', 'def'])
364 ->setPrivate(true)
365 ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44'))
366 )
367 ;
368
369 $result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]);
370
371 static::assertSame(200, $result->getStatusCode());
372 static::assertSame('editlink', (string) $result->getBody());
373
374 static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']);
375 static::assertFalse($assignedVariables['link_is_new']);
376
377 static::assertSame($id, $assignedVariables['link']['id']);
378 static::assertSame($url, $assignedVariables['link']['url']);
379 static::assertSame($title, $assignedVariables['link']['title']);
380 static::assertSame($description, $assignedVariables['link']['description']);
381 static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']);
382 static::assertTrue($assignedVariables['link']['private']);
383 static::assertSame($createdAt, $assignedVariables['link']['created']);
384 }
385
386 /**
387 * Test save a new bookmark
388 */
389 public function testSaveBookmark(): void
390 {
391 $id = 21;
392 $parameters = [
393 'lf_url' => 'http://url.tld/other?part=3#hash',
394 'lf_title' => 'Provided Title',
395 'lf_description' => 'Provided description.',
396 'lf_tags' => 'abc def',
397 'lf_private' => '1',
398 'returnurl' => 'http://shaarli.tld/subfolder/admin/add-shaare'
399 ];
400
401 $request = $this->createMock(Request::class);
402 $request
403 ->method('getParam')
404 ->willReturnCallback(function (string $key) use ($parameters): ?string {
405 return $parameters[$key] ?? null;
406 })
407 ;
408 $response = new Response();
409
410 $checkBookmark = function (Bookmark $bookmark) use ($parameters) {
411 static::assertSame($parameters['lf_url'], $bookmark->getUrl());
412 static::assertSame($parameters['lf_title'], $bookmark->getTitle());
413 static::assertSame($parameters['lf_description'], $bookmark->getDescription());
414 static::assertSame($parameters['lf_tags'], $bookmark->getTagsString());
415 static::assertTrue($bookmark->isPrivate());
416 };
417
418 $this->container->bookmarkService
419 ->expects(static::once())
420 ->method('addOrSet')
421 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
422 static::assertFalse($save);
423
424 $checkBookmark($bookmark);
425
426 $bookmark->setId($id);
427 })
428 ;
429 $this->container->bookmarkService
430 ->expects(static::once())
431 ->method('set')
432 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
433 static::assertTrue($save);
434
435 $checkBookmark($bookmark);
436
437 static::assertSame($id, $bookmark->getId());
438 })
439 ;
440
441 // Make sure that PluginManager hook is triggered
442 $this->container->pluginManager
443 ->expects(static::at(0))
444 ->method('executeHooks')
445 ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
446 static::assertSame('save_link', $hook);
447
448 static::assertSame($id, $data['id']);
449 static::assertSame($parameters['lf_url'], $data['url']);
450 static::assertSame($parameters['lf_title'], $data['title']);
451 static::assertSame($parameters['lf_description'], $data['description']);
452 static::assertSame($parameters['lf_tags'], $data['tags']);
453 static::assertTrue($data['private']);
454
455 return $data;
456 })
457 ;
458
459 $result = $this->controller->save($request, $response);
460
461 static::assertSame(302, $result->getStatusCode());
462 static::assertRegExp('@/subfolder/#[\w\-]{6}@', $result->getHeader('location')[0]);
463 }
464
465
466 /**
467 * Test save an existing bookmark
468 */
469 public function testSaveExistingBookmark(): void
470 {
471 $id = 21;
472 $parameters = [
473 'lf_id' => (string) $id,
474 'lf_url' => 'http://url.tld/other?part=3#hash',
475 'lf_title' => 'Provided Title',
476 'lf_description' => 'Provided description.',
477 'lf_tags' => 'abc def',
478 'lf_private' => '1',
479 'returnurl' => 'http://shaarli.tld/subfolder/?page=2'
480 ];
481
482 $request = $this->createMock(Request::class);
483 $request
484 ->method('getParam')
485 ->willReturnCallback(function (string $key) use ($parameters): ?string {
486 return $parameters[$key] ?? null;
487 })
488 ;
489 $response = new Response();
490
491 $checkBookmark = function (Bookmark $bookmark) use ($parameters, $id) {
492 static::assertSame($id, $bookmark->getId());
493 static::assertSame($parameters['lf_url'], $bookmark->getUrl());
494 static::assertSame($parameters['lf_title'], $bookmark->getTitle());
495 static::assertSame($parameters['lf_description'], $bookmark->getDescription());
496 static::assertSame($parameters['lf_tags'], $bookmark->getTagsString());
497 static::assertTrue($bookmark->isPrivate());
498 };
499
500 $this->container->bookmarkService->expects(static::atLeastOnce())->method('exists')->willReturn(true);
501 $this->container->bookmarkService
502 ->expects(static::once())
503 ->method('get')
504 ->willReturn((new Bookmark())->setId($id)->setUrl('http://other.url'))
505 ;
506 $this->container->bookmarkService
507 ->expects(static::once())
508 ->method('addOrSet')
509 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
510 static::assertFalse($save);
511
512 $checkBookmark($bookmark);
513 })
514 ;
515 $this->container->bookmarkService
516 ->expects(static::once())
517 ->method('set')
518 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void {
519 static::assertTrue($save);
520
521 $checkBookmark($bookmark);
522
523 static::assertSame($id, $bookmark->getId());
524 })
525 ;
526
527 // Make sure that PluginManager hook is triggered
528 $this->container->pluginManager
529 ->expects(static::at(0))
530 ->method('executeHooks')
531 ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
532 static::assertSame('save_link', $hook);
533
534 static::assertSame($id, $data['id']);
535 static::assertSame($parameters['lf_url'], $data['url']);
536 static::assertSame($parameters['lf_title'], $data['title']);
537 static::assertSame($parameters['lf_description'], $data['description']);
538 static::assertSame($parameters['lf_tags'], $data['tags']);
539 static::assertTrue($data['private']);
540
541 return $data;
542 })
543 ;
544
545 $result = $this->controller->save($request, $response);
546
547 static::assertSame(302, $result->getStatusCode());
548 static::assertRegExp('@/subfolder/\?page=2#[\w\-]{6}@', $result->getHeader('location')[0]);
549 }
550
551 /**
552 * Test save a bookmark - try to retrieve the thumbnail
553 */
554 public function testSaveBookmarkWithThumbnail(): void
555 {
556 $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash'];
557
558 $request = $this->createMock(Request::class);
559 $request
560 ->method('getParam')
561 ->willReturnCallback(function (string $key) use ($parameters): ?string {
562 return $parameters[$key] ?? null;
563 })
564 ;
565 $response = new Response();
566
567 $this->container->conf = $this->createMock(ConfigManager::class);
568 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
569 return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default;
570 });
571
572 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
573 $this->container->thumbnailer
574 ->expects(static::once())
575 ->method('get')
576 ->with($parameters['lf_url'])
577 ->willReturn($thumb = 'http://thumb.url')
578 ;
579
580 $this->container->bookmarkService
581 ->expects(static::once())
582 ->method('addOrSet')
583 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): void {
584 static::assertSame($thumb, $bookmark->getThumbnail());
585 })
586 ;
587
588 $result = $this->controller->save($request, $response);
589
590 static::assertSame(302, $result->getStatusCode());
591 }
592
593 /**
594 * Change the password with a wrong existing password
595 */
596 public function testSaveBookmarkFromBookmarklet(): void
597 {
598 $parameters = ['source' => 'bookmarklet'];
599
600 $request = $this->createMock(Request::class);
601 $request
602 ->method('getParam')
603 ->willReturnCallback(function (string $key) use ($parameters): ?string {
604 return $parameters[$key] ?? null;
605 })
606 ;
607 $response = new Response();
608
609 $result = $this->controller->save($request, $response);
610
611 static::assertSame(200, $result->getStatusCode());
612 static::assertSame('<script>self.close();</script>', (string) $result->getBody());
613 }
614
615 /**
616 * Change the password with a wrong existing password
617 */
618 public function testSaveBookmarkWrongToken(): void
619 {
620 $this->container->sessionManager = $this->createMock(SessionManager::class);
621 $this->container->sessionManager->method('checkToken')->willReturn(false);
622
623 $this->container->bookmarkService->expects(static::never())->method('addOrSet');
624 $this->container->bookmarkService->expects(static::never())->method('set');
625
626 $request = $this->createMock(Request::class);
627 $response = new Response();
628
629 $this->expectException(WrongTokenException::class);
630
631 $this->controller->save($request, $response);
632 }
633}