From 6132d64748dfc6806ed25f71d2e078a5ed29d071 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 27 Jun 2020 12:08:26 +0200 Subject: [PATCH] Process thumbnail synchronize page through Slim controllers --- application/Thumbnailer.php | 3 +- .../controller/admin/ConfigureController.php | 2 +- .../controller/admin/ThumbnailsController.php | 79 +++++++++ application/legacy/LegacyUpdater.php | 2 +- assets/common/js/thumbnails-update.js | 6 +- index.php | 35 +--- .../admin/ThumbnailsControllerTest.php | 154 ++++++++++++++++++ tpl/default/configure.html | 4 +- tpl/default/linklist.html | 2 +- tpl/default/picwall.html | 2 +- tpl/default/tools.html | 2 +- tpl/vintage/configure.html | 2 +- 12 files changed, 253 insertions(+), 40 deletions(-) create mode 100644 application/front/controller/admin/ThumbnailsController.php create mode 100644 tests/front/controller/admin/ThumbnailsControllerTest.php diff --git a/application/Thumbnailer.php b/application/Thumbnailer.php index 314baf0d..5aec23c8 100644 --- a/application/Thumbnailer.php +++ b/application/Thumbnailer.php @@ -4,7 +4,6 @@ namespace Shaarli; use Shaarli\Config\ConfigManager; use WebThumbnailer\Application\ConfigManager as WTConfigManager; -use WebThumbnailer\Exception\WebThumbnailerException; use WebThumbnailer\WebThumbnailer; /** @@ -90,7 +89,7 @@ class Thumbnailer try { return $this->wt->thumbnail($url); - } catch (WebThumbnailerException $e) { + } catch (\Throwable $e) { // Exceptions are only thrown in debug mode. error_log(get_class($e) . ': ' . $e->getMessage()); } diff --git a/application/front/controller/admin/ConfigureController.php b/application/front/controller/admin/ConfigureController.php index 44971c43..201a859b 100644 --- a/application/front/controller/admin/ConfigureController.php +++ b/application/front/controller/admin/ConfigureController.php @@ -99,7 +99,7 @@ class ConfigureController extends ShaarliAdminController ) { $this->saveWarningMessage(t( 'You have enabled or changed thumbnails mode. ' - .'Please synchronize them.' + .'Please synchronize them.' )); } $this->container->conf->set('thumbnails.mode', $thumbnailsMode); diff --git a/application/front/controller/admin/ThumbnailsController.php b/application/front/controller/admin/ThumbnailsController.php new file mode 100644 index 00000000..e5308510 --- /dev/null +++ b/application/front/controller/admin/ThumbnailsController.php @@ -0,0 +1,79 @@ +container->bookmarkService->search() as $bookmark) { + // A note or not HTTP(S) + if ($bookmark->isNote() || !startsWith(strtolower($bookmark->getUrl()), 'http')) { + continue; + } + + $ids[] = $bookmark->getId(); + } + + $this->assignView('ids', $ids); + $this->assignView( + 'pagetitle', + t('Thumbnails update') .' - '. $this->container->conf->get('general.title', 'Shaarli') + ); + + return $response->write($this->render('thumbnails')); + } + + /** + * PATCH /admin/shaare/{id}/thumbnail-update - Route for AJAX calls + */ + public function ajaxUpdate(Request $request, Response $response, array $args): Response + { + $id = $args['id'] ?? null; + + if (false === ctype_digit($id)) { + return $response->withStatus(400); + } + + try { + $bookmark = $this->container->bookmarkService->get($id); + } catch (BookmarkNotFoundException $e) { + return $response->withStatus(404); + } + + $bookmark->setThumbnail($this->container->thumbnailer->get($bookmark->getUrl())); + $this->container->bookmarkService->set($bookmark); + + return $response->withJson($this->container->formatterFactory->getFormatter('raw')->format($bookmark)); + } + + /** + * @param mixed[] $data Variables passed to the template engine + * + * @return mixed[] Template data after active plugins render_picwall hook execution. + */ + protected function executeHooks(array $data): array + { + $this->container->pluginManager->executeHooks( + 'render_tools', + $data + ); + + return $data; + } +} diff --git a/application/legacy/LegacyUpdater.php b/application/legacy/LegacyUpdater.php index 8d5cd071..cbf6890f 100644 --- a/application/legacy/LegacyUpdater.php +++ b/application/legacy/LegacyUpdater.php @@ -534,7 +534,7 @@ class LegacyUpdater if ($thumbnailsEnabled) { $this->session['warnings'][] = t( - 'You have enabled or changed thumbnails mode. Please synchronize them.' + 'You have enabled or changed thumbnails mode. Please synchronize them.' ); } diff --git a/assets/common/js/thumbnails-update.js b/assets/common/js/thumbnails-update.js index b37a32f3..3cd4c2a7 100644 --- a/assets/common/js/thumbnails-update.js +++ b/assets/common/js/thumbnails-update.js @@ -17,7 +17,7 @@ */ function updateThumb(basePath, ids, i, elements) { const xhr = new XMLHttpRequest(); - xhr.open('POST', `${basePath}/?do=ajax_thumb_update`); + xhr.open('PATCH', `${basePath}/admin/shaare/${ids[i]}/update-thumbnail`); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.responseType = 'json'; xhr.onload = () => { @@ -30,14 +30,14 @@ function updateThumb(basePath, ids, i, elements) { elements.current.innerHTML = i; elements.title.innerHTML = response.title; if (response.thumbnail !== false) { - elements.thumbnail.innerHTML = ``; + elements.thumbnail.innerHTML = ``; } if (i < ids.length) { updateThumb(basePath, ids, i, elements); } } }; - xhr.send(`id=${ids[i]}`); + xhr.send(); } (() => { diff --git a/index.php b/index.php index 9202cb84..a07de74d 100644 --- a/index.php +++ b/index.php @@ -603,38 +603,14 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM // -------- Thumbnails Update if ($targetPage == Router::$PAGE_THUMBS_UPDATE) { - $ids = []; - foreach ($bookmarkService->search() as $bookmark) { - // A note or not HTTP(S) - if ($bookmark->isNote() || ! startsWith(strtolower($bookmark->getUrl()), 'http')) { - continue; - } - $ids[] = $bookmark->getId(); - } - $PAGE->assign('ids', $ids); - $PAGE->assign('pagetitle', t('Thumbnails update') .' - '. $conf->get('general.title', 'Shaarli')); - $PAGE->renderPage('thumbnails'); + header('Location: ./admin/thumbnails'); exit; } // -------- Single Thumbnail Update if ($targetPage == Router::$AJAX_THUMB_UPDATE) { - if (! isset($_POST['id']) || ! ctype_digit($_POST['id'])) { - http_response_code(400); - exit; - } - $id = (int) $_POST['id']; - if (! $bookmarkService->exists($id)) { - http_response_code(404); - exit; - } - $thumbnailer = new Thumbnailer($conf); - $bookmark = $bookmarkService->get($id); - $bookmark->setThumbnail($thumbnailer->get($bookmark->getUrl())); - $bookmarkService->set($bookmark); - - $factory = new FormatterFactory($conf, $loginManager->isLoggedIn()); - echo json_encode($factory->getFormatter('raw')->format($bookmark)); + // This route is no longer supported in legacy mode + http_response_code(404); exit; } @@ -971,6 +947,10 @@ $app->group('', function () { $this->get('/admin/shaare/delete', '\Shaarli\Front\Controller\Admin\ManageShaareController:deleteBookmark'); $this->get('/admin/shaare/visibility', '\Shaarli\Front\Controller\Admin\ManageShaareController:changeVisibility'); $this->get('/admin/shaare/{id:[0-9]+}/pin', '\Shaarli\Front\Controller\Admin\ManageShaareController:pinBookmark'); + $this->patch( + '/admin/shaare/{id:[0-9]+}/update-thumbnail', + '\Shaarli\Front\Controller\Admin\ThumbnailsController:ajaxUpdate' + ); $this->get('/admin/export', '\Shaarli\Front\Controller\Admin\ExportController:index'); $this->post('/admin/export', '\Shaarli\Front\Controller\Admin\ExportController:export'); $this->get('/admin/import', '\Shaarli\Front\Controller\Admin\ImportController:index'); @@ -978,6 +958,7 @@ $app->group('', function () { $this->get('/admin/plugins', '\Shaarli\Front\Controller\Admin\PluginsController:index'); $this->post('/admin/plugins', '\Shaarli\Front\Controller\Admin\PluginsController:save'); $this->get('/admin/token', '\Shaarli\Front\Controller\Admin\TokenController:getToken'); + $this->get('/admin/thumbnails', '\Shaarli\Front\Controller\Admin\ThumbnailsController:index'); $this->get('/links-per-page', '\Shaarli\Front\Controller\Admin\SessionFilterController:linksPerPage'); $this->get('/visibility/{visibility}', '\Shaarli\Front\Controller\Admin\SessionFilterController:visibility'); diff --git a/tests/front/controller/admin/ThumbnailsControllerTest.php b/tests/front/controller/admin/ThumbnailsControllerTest.php new file mode 100644 index 00000000..0c0c8a83 --- /dev/null +++ b/tests/front/controller/admin/ThumbnailsControllerTest.php @@ -0,0 +1,154 @@ +createContainer(); + + $this->controller = new ThumbnailsController($this->container); + } + + /** + * Test displaying the thumbnails update page + * Note that only non-note and HTTP bookmarks should be returned. + */ + public function testIndex(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->willReturn([ + (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), + (new Bookmark())->setId(2)->setUrl('?abcdef')->setTitle('Note 1'), + (new Bookmark())->setId(3)->setUrl('http://url2.tld')->setTitle('Title 2'), + (new Bookmark())->setId(4)->setUrl('ftp://domain.tld', ['ftp'])->setTitle('FTP'), + ]) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('thumbnails', (string) $result->getBody()); + + static::assertSame('Thumbnails update - Shaarli', $assignedVariables['pagetitle']); + static::assertSame([1, 3], $assignedVariables['ids']); + } + + /** + * Test updating a bookmark thumbnail with valid parameters + */ + public function testAjaxUpdateValid(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $bookmark = (new Bookmark()) + ->setId($id = 123) + ->setUrl($url = 'http://url1.tld') + ->setTitle('Title 1') + ->setThumbnail(false) + ; + + $this->container->thumbnailer = $this->createMock(Thumbnailer::class); + $this->container->thumbnailer + ->expects(static::once()) + ->method('get') + ->with($url) + ->willReturn($thumb = 'http://img.tld/pic.png') + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willReturn($bookmark) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('set') + ->willReturnCallback(function (Bookmark $bookmark) use ($thumb) { + static::assertSame($thumb, $bookmark->getThumbnail()); + }) + ; + + $result = $this->controller->ajaxUpdate($request, $response, ['id' => (string) $id]); + + static::assertSame(200, $result->getStatusCode()); + + $payload = json_decode((string) $result->getBody(), true); + + static::assertSame($id, $payload['id']); + static::assertSame($url, $payload['url']); + static::assertSame($thumb, $payload['thumbnail']); + } + + /** + * Test updating a bookmark thumbnail - Invalid ID + */ + public function testAjaxUpdateInvalidId(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->ajaxUpdate($request, $response, ['id' => 'nope']); + + static::assertSame(400, $result->getStatusCode()); + } + + /** + * Test updating a bookmark thumbnail - No ID + */ + public function testAjaxUpdateNoId(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->ajaxUpdate($request, $response, []); + + static::assertSame(400, $result->getStatusCode()); + } + + /** + * Test updating a bookmark thumbnail with valid parameters + */ + public function testAjaxUpdateBookmarkNotFound(): void + { + $id = 123; + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willThrowException(new BookmarkNotFoundException()) + ; + + $result = $this->controller->ajaxUpdate($request, $response, ['id' => (string) $id]); + + static::assertSame(404, $result->getStatusCode()); + } +} diff --git a/tpl/default/configure.html b/tpl/default/configure.html index fa1f7aa6..bb2564af 100644 --- a/tpl/default/configure.html +++ b/tpl/default/configure.html @@ -35,7 +35,7 @@
@@ -289,7 +289,7 @@ {if="! $gd_enabled"} {'You need to enable the extension php-gd to use thumbnails.'|t} {elseif="$thumbnails_enabled"} - {'Synchronize thumbnails'|t} + {'Synchronize thumbnails'|t} {/if} diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html index b0a5fdf2..8c1c2036 100644 --- a/tpl/default/linklist.html +++ b/tpl/default/linklist.html @@ -140,7 +140,7 @@
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore} diff --git a/tpl/default/picwall.html b/tpl/default/picwall.html index 1e97b366..3b5fccc3 100644 --- a/tpl/default/picwall.html +++ b/tpl/default/picwall.html @@ -9,7 +9,7 @@ {if="count($linksToDisplay)===0 && $is_logged_in"}
- {'There is no cached thumbnail. Try to synchronize them.'|t} + {'There is no cached thumbnail. Try to synchronize them.'|t}
{/if} diff --git a/tpl/default/tools.html b/tpl/default/tools.html index 31f33a09..2cb08e38 100644 --- a/tpl/default/tools.html +++ b/tpl/default/tools.html @@ -47,7 +47,7 @@ {if="$thumbnails_enabled"} diff --git a/tpl/vintage/configure.html b/tpl/vintage/configure.html index d04c69a9..c5861aae 100644 --- a/tpl/vintage/configure.html +++ b/tpl/vintage/configure.html @@ -159,7 +159,7 @@ {if="! $gd_enabled"} {'You need to enable the extension php-gd to use thumbnails.'|t} {elseif="$thumbnails_enabled"} - {'Synchonize thumbnails'|t} + {'Synchonize thumbnails'|t} {/if} -- 2.41.0