]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - tests/front/controller/visitor/BookmarkListControllerTest.php
5cbc8c732a76f8726564b3a85138cc9f2cd6473b
[github/shaarli/Shaarli.git] / tests / front / controller / visitor / BookmarkListControllerTest.php
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Shaarli\Front\Controller\Visitor;
6
7 use Shaarli\Bookmark\Bookmark;
8 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9 use Shaarli\Config\ConfigManager;
10 use Shaarli\Security\LoginManager;
11 use Shaarli\TestCase;
12 use Shaarli\Thumbnailer;
13 use Slim\Http\Request;
14 use Slim\Http\Response;
15
16 class BookmarkListControllerTest extends TestCase
17 {
18 use FrontControllerMockHelper;
19
20 /** @var BookmarkListController */
21 protected $controller;
22
23 public function setUp(): void
24 {
25 $this->createContainer();
26
27 $this->controller = new BookmarkListController($this->container);
28 }
29
30 /**
31 * Test rendering list of bookmarks with default parameters (first page).
32 */
33 public function testIndexDefaultFirstPage(): void
34 {
35 $assignedVariables = [];
36 $this->assignTemplateVars($assignedVariables);
37
38 $request = $this->createMock(Request::class);
39 $response = new Response();
40
41 $this->container->bookmarkService
42 ->expects(static::once())
43 ->method('search')
44 ->with(
45 ['searchtags' => '', 'searchterm' => ''],
46 null,
47 false,
48 false
49 )
50 ->willReturn([
51 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
52 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
53 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
54 ]
55 );
56
57 $this->container->sessionManager
58 ->method('getSessionParameter')
59 ->willReturnCallback(function (string $parameter, $default = null) {
60 if ('LINKS_PER_PAGE' === $parameter) {
61 return 2;
62 }
63
64 return $default;
65 })
66 ;
67
68 $result = $this->controller->index($request, $response);
69
70 static::assertSame(200, $result->getStatusCode());
71 static::assertSame('linklist', (string) $result->getBody());
72
73 static::assertSame('Shaarli', $assignedVariables['pagetitle']);
74 static::assertSame('?page=2', $assignedVariables['previous_page_url']);
75 static::assertSame('', $assignedVariables['next_page_url']);
76 static::assertSame(2, $assignedVariables['page_max']);
77 static::assertSame('', $assignedVariables['search_tags']);
78 static::assertSame(3, $assignedVariables['result_count']);
79 static::assertSame(1, $assignedVariables['page_current']);
80 static::assertSame('', $assignedVariables['search_term']);
81 static::assertNull($assignedVariables['visibility']);
82 static::assertCount(2, $assignedVariables['links']);
83
84 $link = $assignedVariables['links'][0];
85
86 static::assertSame(1, $link['id']);
87 static::assertSame('http://url1.tld', $link['url']);
88 static::assertSame('Title 1', $link['title']);
89
90 $link = $assignedVariables['links'][1];
91
92 static::assertSame(2, $link['id']);
93 static::assertSame('http://url2.tld', $link['url']);
94 static::assertSame('Title 2', $link['title']);
95 }
96
97 /**
98 * Test rendering list of bookmarks with default parameters (second page).
99 */
100 public function testIndexDefaultSecondPage(): void
101 {
102 $assignedVariables = [];
103 $this->assignTemplateVars($assignedVariables);
104
105 $request = $this->createMock(Request::class);
106 $request->method('getParam')->willReturnCallback(function (string $key) {
107 if ('page' === $key) {
108 return '2';
109 }
110
111 return null;
112 });
113 $response = new Response();
114
115 $this->container->bookmarkService
116 ->expects(static::once())
117 ->method('search')
118 ->with(
119 ['searchtags' => '', 'searchterm' => ''],
120 null,
121 false,
122 false
123 )
124 ->willReturn([
125 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
126 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
127 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
128 ])
129 ;
130
131 $this->container->sessionManager
132 ->method('getSessionParameter')
133 ->willReturnCallback(function (string $parameter, $default = null) {
134 if ('LINKS_PER_PAGE' === $parameter) {
135 return 2;
136 }
137
138 return $default;
139 })
140 ;
141
142 $result = $this->controller->index($request, $response);
143
144 static::assertSame(200, $result->getStatusCode());
145 static::assertSame('linklist', (string) $result->getBody());
146
147 static::assertSame('Shaarli', $assignedVariables['pagetitle']);
148 static::assertSame('', $assignedVariables['previous_page_url']);
149 static::assertSame('?page=1', $assignedVariables['next_page_url']);
150 static::assertSame(2, $assignedVariables['page_max']);
151 static::assertSame('', $assignedVariables['search_tags']);
152 static::assertSame(3, $assignedVariables['result_count']);
153 static::assertSame(2, $assignedVariables['page_current']);
154 static::assertSame('', $assignedVariables['search_term']);
155 static::assertNull($assignedVariables['visibility']);
156 static::assertCount(1, $assignedVariables['links']);
157
158 $link = $assignedVariables['links'][2];
159
160 static::assertSame(3, $link['id']);
161 static::assertSame('http://url3.tld', $link['url']);
162 static::assertSame('Title 3', $link['title']);
163 }
164
165 /**
166 * Test rendering list of bookmarks with filters.
167 */
168 public function testIndexDefaultWithFilters(): void
169 {
170 $assignedVariables = [];
171 $this->assignTemplateVars($assignedVariables);
172
173 $request = $this->createMock(Request::class);
174 $request->method('getParam')->willReturnCallback(function (string $key) {
175 if ('searchtags' === $key) {
176 return 'abc def';
177 }
178 if ('searchterm' === $key) {
179 return 'ghi jkl';
180 }
181
182 return null;
183 });
184 $response = new Response();
185
186 $this->container->sessionManager
187 ->method('getSessionParameter')
188 ->willReturnCallback(function (string $key, $default) {
189 if ('LINKS_PER_PAGE' === $key) {
190 return 2;
191 }
192 if ('visibility' === $key) {
193 return 'private';
194 }
195 if ('untaggedonly' === $key) {
196 return true;
197 }
198
199 return $default;
200 })
201 ;
202
203 $this->container->bookmarkService
204 ->expects(static::once())
205 ->method('search')
206 ->with(
207 ['searchtags' => 'abc def', 'searchterm' => 'ghi jkl'],
208 'private',
209 false,
210 true
211 )
212 ->willReturn([
213 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
214 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
215 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
216 ])
217 ;
218
219 $result = $this->controller->index($request, $response);
220
221 static::assertSame(200, $result->getStatusCode());
222 static::assertSame('linklist', (string) $result->getBody());
223
224 static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']);
225 static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc+def', $assignedVariables['previous_page_url']);
226 }
227
228 /**
229 * Test displaying a permalink with valid parameters
230 */
231 public function testPermalinkValid(): void
232 {
233 $hash = 'abcdef';
234
235 $assignedVariables = [];
236 $this->assignTemplateVars($assignedVariables);
237
238 $request = $this->createMock(Request::class);
239 $response = new Response();
240
241 $this->container->bookmarkService
242 ->expects(static::once())
243 ->method('findByHash')
244 ->with($hash)
245 ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
246 ;
247
248 $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
249
250 static::assertSame(200, $result->getStatusCode());
251 static::assertSame('linklist', (string) $result->getBody());
252
253 static::assertSame('Title 1 - Shaarli', $assignedVariables['pagetitle']);
254 static::assertCount(1, $assignedVariables['links']);
255
256 $link = $assignedVariables['links'][0];
257
258 static::assertSame(123, $link['id']);
259 static::assertSame('http://url1.tld', $link['url']);
260 static::assertSame('Title 1', $link['title']);
261 }
262
263 /**
264 * Test displaying a permalink with an unknown small hash : renders a 404 template error
265 */
266 public function testPermalinkNotFound(): void
267 {
268 $hash = 'abcdef';
269
270 $assignedVariables = [];
271 $this->assignTemplateVars($assignedVariables);
272
273 $request = $this->createMock(Request::class);
274 $response = new Response();
275
276 $this->container->bookmarkService
277 ->expects(static::once())
278 ->method('findByHash')
279 ->with($hash)
280 ->willThrowException(new BookmarkNotFoundException())
281 ;
282
283 $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
284
285 static::assertSame(200, $result->getStatusCode());
286 static::assertSame('404', (string) $result->getBody());
287
288 static::assertSame(
289 'The link you are trying to reach does not exist or has been deleted.',
290 $assignedVariables['error_message']
291 );
292 }
293
294 /**
295 * Test GET /shaare/{hash}?key={key} - Find a link by hash using a private link.
296 */
297 public function testPermalinkWithPrivateKey(): void
298 {
299 $hash = 'abcdef';
300 $privateKey = 'this is a private key';
301
302 $assignedVariables = [];
303 $this->assignTemplateVars($assignedVariables);
304
305 $request = $this->createMock(Request::class);
306 $request->method('getParam')->willReturnCallback(function (string $key, $default = null) use ($privateKey) {
307 return $key === 'key' ? $privateKey : $default;
308 });
309 $response = new Response();
310
311 $this->container->bookmarkService
312 ->expects(static::once())
313 ->method('findByHash')
314 ->with($hash, $privateKey)
315 ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
316 ;
317
318 $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
319
320 static::assertSame(200, $result->getStatusCode());
321 static::assertSame('linklist', (string) $result->getBody());
322 static::assertCount(1, $assignedVariables['links']);
323 }
324
325 /**
326 * Test getting link list with thumbnail updates.
327 * -> 2 thumbnails update, only 1 datastore write
328 */
329 public function testThumbnailUpdateFromLinkList(): void
330 {
331 $request = $this->createMock(Request::class);
332 $response = new Response();
333
334 $this->container->loginManager = $this->createMock(LoginManager::class);
335 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
336
337 $this->container->conf = $this->createMock(ConfigManager::class);
338 $this->container->conf
339 ->method('get')
340 ->willReturnCallback(function (string $key, $default) {
341 if ($key === 'thumbnails.mode') {
342 return Thumbnailer::MODE_ALL;
343 } elseif ($key === 'general.enable_async_metadata') {
344 return false;
345 }
346
347 return $default;
348 })
349 ;
350
351 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
352 $this->container->thumbnailer
353 ->expects(static::exactly(2))
354 ->method('get')
355 ->withConsecutive(['https://url2.tld'], ['https://url4.tld'])
356 ;
357
358 $this->container->bookmarkService
359 ->expects(static::once())
360 ->method('search')
361 ->willReturn([
362 (new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
363 $b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
364 (new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
365 $b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
366 (new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
367 ])
368 ;
369 $this->container->bookmarkService
370 ->expects(static::exactly(2))
371 ->method('set')
372 ->withConsecutive([$b1, false], [$b2, false])
373 ;
374 $this->container->bookmarkService->expects(static::once())->method('save');
375
376 $result = $this->controller->index($request, $response);
377
378 static::assertSame(200, $result->getStatusCode());
379 static::assertSame('linklist', (string) $result->getBody());
380 }
381
382 /**
383 * Test getting a permalink with thumbnail update.
384 */
385 public function testThumbnailUpdateFromPermalink(): void
386 {
387 $request = $this->createMock(Request::class);
388 $response = new Response();
389
390 $this->container->loginManager = $this->createMock(LoginManager::class);
391 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
392
393 $this->container->conf = $this->createMock(ConfigManager::class);
394 $this->container->conf
395 ->method('get')
396 ->willReturnCallback(function (string $key, $default) {
397 if ($key === 'thumbnails.mode') {
398 return Thumbnailer::MODE_ALL;
399 } elseif ($key === 'general.enable_async_metadata') {
400 return false;
401 }
402
403 return $default;
404 })
405 ;
406
407 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
408 $this->container->thumbnailer->expects(static::once())->method('get')->withConsecutive(['https://url.tld']);
409
410 $this->container->bookmarkService
411 ->expects(static::once())
412 ->method('findByHash')
413 ->willReturn($bookmark = (new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
414 ;
415 $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, true);
416 $this->container->bookmarkService->expects(static::never())->method('save');
417
418 $result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
419
420 static::assertSame(200, $result->getStatusCode());
421 static::assertSame('linklist', (string) $result->getBody());
422 }
423
424 /**
425 * Test getting a permalink with thumbnail update with async setting: no update should run.
426 */
427 public function testThumbnailUpdateFromPermalinkAsync(): void
428 {
429 $request = $this->createMock(Request::class);
430 $response = new Response();
431
432 $this->container->loginManager = $this->createMock(LoginManager::class);
433 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
434
435 $this->container->conf = $this->createMock(ConfigManager::class);
436 $this->container->conf
437 ->method('get')
438 ->willReturnCallback(function (string $key, $default) {
439 if ($key === 'thumbnails.mode') {
440 return Thumbnailer::MODE_ALL;
441 } elseif ($key === 'general.enable_async_metadata') {
442 return true;
443 }
444
445 return $default;
446 })
447 ;
448
449 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
450 $this->container->thumbnailer->expects(static::never())->method('get');
451
452 $this->container->bookmarkService
453 ->expects(static::once())
454 ->method('findByHash')
455 ->willReturn((new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
456 ;
457 $this->container->bookmarkService->expects(static::never())->method('set');
458 $this->container->bookmarkService->expects(static::never())->method('save');
459
460 $result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
461
462 static::assertSame(200, $result->getStatusCode());
463 }
464
465 /**
466 * Trigger legacy controller in link list controller: permalink
467 */
468 public function testLegacyControllerPermalink(): void
469 {
470 $hash = 'abcdef';
471 $this->container->environment['QUERY_STRING'] = $hash;
472
473 $request = $this->createMock(Request::class);
474 $response = new Response();
475
476 $result = $this->controller->index($request, $response);
477
478 static::assertSame(302, $result->getStatusCode());
479 static::assertSame('/subfolder/shaare/' . $hash, $result->getHeader('location')[0]);
480 }
481
482 /**
483 * Trigger legacy controller in link list controller: ?do= query parameter
484 */
485 public function testLegacyControllerDoPage(): void
486 {
487 $request = $this->createMock(Request::class);
488 $request->method('getQueryParam')->with('do')->willReturn('picwall');
489 $response = new Response();
490
491 $result = $this->controller->index($request, $response);
492
493 static::assertSame(302, $result->getStatusCode());
494 static::assertSame('/subfolder/picture-wall', $result->getHeader('location')[0]);
495 }
496
497 /**
498 * Trigger legacy controller in link list controller: ?do= query parameter with unknown legacy route
499 */
500 public function testLegacyControllerUnknownDoPage(): void
501 {
502 $request = $this->createMock(Request::class);
503 $request->method('getQueryParam')->with('do')->willReturn('nope');
504 $response = new Response();
505
506 $result = $this->controller->index($request, $response);
507
508 static::assertSame(200, $result->getStatusCode());
509 static::assertSame('linklist', (string) $result->getBody());
510 }
511
512 /**
513 * Trigger legacy controller in link list controller: other GET route (e.g. ?post)
514 */
515 public function testLegacyControllerGetParameter(): void
516 {
517 $request = $this->createMock(Request::class);
518 $request->method('getQueryParams')->willReturn(['post' => $url = 'http://url.tld']);
519 $response = new Response();
520
521 $this->container->loginManager = $this->createMock(LoginManager::class);
522 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
523
524 $result = $this->controller->index($request, $response);
525
526 static::assertSame(302, $result->getStatusCode());
527 static::assertSame(
528 '/subfolder/admin/shaare?post=' . urlencode($url),
529 $result->getHeader('location')[0]
530 );
531 }
532 }