]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Process thumbnail synchronize page through Slim controllers
authorArthurHoaro <arthur@hoa.ro>
Sat, 27 Jun 2020 10:08:26 +0000 (12:08 +0200)
committerArthurHoaro <arthur@hoa.ro>
Thu, 23 Jul 2020 19:19:21 +0000 (21:19 +0200)
12 files changed:
application/Thumbnailer.php
application/front/controller/admin/ConfigureController.php
application/front/controller/admin/ThumbnailsController.php [new file with mode: 0644]
application/legacy/LegacyUpdater.php
assets/common/js/thumbnails-update.js
index.php
tests/front/controller/admin/ThumbnailsControllerTest.php [new file with mode: 0644]
tpl/default/configure.html
tpl/default/linklist.html
tpl/default/picwall.html
tpl/default/tools.html
tpl/vintage/configure.html

index 314baf0df615c5e3edf15ec5e9b0e60eac61f792..5aec23c8d7b6bbf59305f3e651a689cd3d781a21 100644 (file)
@@ -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());
         }
index 44971c43f2ba1453dd9f61c78055d592084e0fcd..201a859bc5f27c6be4230a92012c7cce5bd41a21 100644 (file)
@@ -99,7 +99,7 @@ class ConfigureController extends ShaarliAdminController
         ) {
             $this->saveWarningMessage(t(
                 'You have enabled or changed thumbnails mode. '
-                .'<a href="./?do=thumbs_update">Please synchronize them</a>.'
+                .'<a href="'. $this->container->basePath .'/admin/thumbnails">Please synchronize them</a>.'
             ));
         }
         $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 (file)
index 0000000..e530851
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller\Admin;
+
+use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+/**
+ * Class ToolsController
+ *
+ * Slim controller used to handle thumbnails update.
+ */
+class ThumbnailsController extends ShaarliAdminController
+{
+    /**
+     * GET /admin/thumbnails - Display thumbnails update page
+     */
+    public function index(Request $request, Response $response): Response
+    {
+        $ids = [];
+        foreach ($this->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;
+    }
+}
index 8d5cd071392ddf14a3bd302f7f17bc7d8e37fb9b..cbf6890f42cfa7508e69628c847bd15d0dee18a1 100644 (file)
@@ -534,7 +534,7 @@ class LegacyUpdater
 
         if ($thumbnailsEnabled) {
             $this->session['warnings'][] = t(
-                'You have enabled or changed thumbnails mode. <a href="./?do=thumbs_update">Please synchronize them</a>.'
+                'You have enabled or changed thumbnails mode. <a href="./admin/thumbnails">Please synchronize them</a>.'
             );
         }
 
index b37a32f307e427f1a5941c994406b4945a7bd27f..3cd4c2a761f778989e682ee181421200abe012cc 100644 (file)
@@ -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 = `<img src="${response.thumbnail}">`;
+        elements.thumbnail.innerHTML = `<img src="${basePath}/${response.thumbnail}">`;
       }
       if (i < ids.length) {
         updateThumb(basePath, ids, i, elements);
       }
     }
   };
-  xhr.send(`id=${ids[i]}`);
+  xhr.send();
 }
 
 (() => {
index 9202cb84689badd4371e6f2f1e39d98cc6a4961f..a07de74d01508e6003d43b4cfd3de97fca8947f9 100644 (file)
--- 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 (file)
index 0000000..0c0c8a8
--- /dev/null
@@ -0,0 +1,154 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller\Admin;
+
+use PHPUnit\Framework\TestCase;
+use Shaarli\Bookmark\Bookmark;
+use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
+use Shaarli\Thumbnailer;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+class ThumbnailsControllerTest extends TestCase
+{
+    use FrontAdminControllerMockHelper;
+
+    /** @var ThumbnailsController */
+    protected $controller;
+
+    public function setUp(): void
+    {
+        $this->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());
+    }
+}
index fa1f7aa646d635d3deaa0e29b3be8ba01baaa910..bb2564afd3712dc1dbb989043c035711dc8ccc93 100644 (file)
@@ -35,7 +35,7 @@
           <div class="form-label">
             <label for="titleLink">
               <span class="label-name">{'Home link'|t}</span><br>
-              <span class="label-desc">{'Default value'|t}: {$base_path}</span>
+              <span class="label-desc">{'Default value'|t}: {$base_path}/</span>
             </label>
           </div>
         </div>
                 {if="! $gd_enabled"}
                   {'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t}
                 {elseif="$thumbnails_enabled"}
-                  <a href="{$base_path}/?do=thumbs_update">{'Synchronize thumbnails'|t}</a>
+                  <a href="{$base_path}/admin/thumbnails">{'Synchronize thumbnails'|t}</a>
                 {/if}
               </span>
             </label>
index b0a5fdf276f71e621c7cf184e91254a763f89e79..8c1c2036972f3aaf500c0e003a028b9033b47d8a 100644 (file)
                 <div class="thumbnail">
                   {ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
                   <a href="{$value.real_url}" aria-hidden="true" tabindex="-1">
-                  <img data-src="{$value.thumbnail}#" class="b-lazy"
+                  <img data-src="{$base_path}/{$value.thumbnail}#" class="b-lazy"
                     src=""
                     alt="" width="{$thumbnails_width}" height="{$thumbnails_height}" />
                   </a>
index 1e97b36634e371422d335781d0a56df01a0b4fd9..3b5fccc33175a590d673dc92f39b234d13f8a096 100644 (file)
@@ -9,7 +9,7 @@
 {if="count($linksToDisplay)===0 && $is_logged_in"}
   <div class="pure-g pure-alert pure-alert-warning page-single-alert">
     <div class="pure-u-1 center">
-      {'There is no cached thumbnail. Try to <a href="{$base_path}/do=thumbs_update">synchronize them</a>.'|t}
+      {'There is no cached thumbnail. Try to <a href="{$base_path}/admin/thumbnails">synchronize them</a>.'|t}
     </div>
   </div>
 {/if}
index 31f33a093c238478b2c28e68b0005645e4dee341..2cb08e387b468e8f2b39942a46ae0699abc98088 100644 (file)
@@ -47,7 +47,7 @@
 
     {if="$thumbnails_enabled"}
       <div class="tools-item">
-        <a href="{$base_path}/?do=thumbs_update" title="{'Synchronize all link thumbnails'|t}">
+        <a href="{$base_path}/admin/thumbnails" title="{'Synchronize all link thumbnails'|t}">
           <span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Synchronize thumbnails'|t}</span>
         </a>
       </div>
index d04c69a90a829e901c4d0f10567fd7a8bb3a4eff..c5861aaef21ab2f9c7e00d9d16f4c3113239a5c1 100644 (file)
             {if="! $gd_enabled"}
               {'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t}
             {elseif="$thumbnails_enabled"}
-              <a href="{$base_path}/?do=thumbs_update">{'Synchonize thumbnails'|t}</a>
+              <a href="{$base_path}/admin/thumbnails">{'Synchonize thumbnails'|t}</a>
             {/if}
           </label>
         </td>