From 28f26524609338316cc6e51c743058e6e8c7b12b Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 8 Jun 2018 12:50:49 +0200 Subject: [PATCH] Add a page to update all thumbnails through AJAX requests in both templates --- application/PageBuilder.php | 28 ++++- application/Router.php | 12 +++ application/Updater.php | 25 ++++- application/config/ConfigManager.php | 7 -- assets/common/js/thumbnails-update.js | 51 +++++++++ assets/default/scss/shaarli.scss | 44 ++++++++ assets/vintage/css/shaarli.css | 40 +++++++ composer.lock | 142 +++++++++++++++++-------- index.php | 81 ++++++++------ tests/Updater/UpdaterTest.php | 40 ++++++- tests/utils/config/configJson.json.php | 12 +-- tpl/default/configure.html | 8 +- tpl/default/page.header.html | 14 +++ tpl/default/thumbnails.html | 48 +++++++++ tpl/vintage/configure.html | 10 +- tpl/vintage/thumbnails.html | 28 +++++ webpack.config.js | 2 + 17 files changed, 487 insertions(+), 105 deletions(-) create mode 100644 assets/common/js/thumbnails-update.js create mode 100644 tpl/default/thumbnails.html create mode 100644 tpl/vintage/thumbnails.html diff --git a/application/PageBuilder.php b/application/PageBuilder.php index 3dba7677..5da70811 100644 --- a/application/PageBuilder.php +++ b/application/PageBuilder.php @@ -21,11 +21,21 @@ class PageBuilder */ protected $conf; + /** + * @var array $_SESSION + */ + protected $session; + /** * @var LinkDB $linkDB instance. */ protected $linkDB; - + + /** + * @var null|string XSRF token + */ + protected $token; + /** @var bool $isLoggedIn Whether the user is logged in **/ protected $isLoggedIn = false; @@ -33,14 +43,17 @@ class PageBuilder * PageBuilder constructor. * $tpl is initialized at false for lazy loading. * - * @param ConfigManager $conf Configuration Manager instance (reference). - * @param LinkDB $linkDB instance. - * @param string $token Session token + * @param ConfigManager $conf Configuration Manager instance (reference). + * @param array $session $_SESSION array + * @param LinkDB $linkDB instance. + * @param string $token Session token + * @param bool $isLoggedIn */ - public function __construct(&$conf, $linkDB = null, $token = null, $isLoggedIn = false) + public function __construct(&$conf, $session, $linkDB = null, $token = null, $isLoggedIn = false) { $this->tpl = false; $this->conf = $conf; + $this->session = $session; $this->linkDB = $linkDB; $this->token = $token; $this->isLoggedIn = $isLoggedIn; @@ -110,6 +123,11 @@ private function initialize() $this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width')); $this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height')); + if (! empty($_SESSION['warnings'])) { + $this->tpl->assign('global_warnings', $_SESSION['warnings']); + unset($_SESSION['warnings']); + } + // To be removed with a proper theme configuration. $this->tpl->assign('conf', $this->conf); } diff --git a/application/Router.php b/application/Router.php index 4df0387c..bf86b884 100644 --- a/application/Router.php +++ b/application/Router.php @@ -7,6 +7,8 @@ */ class Router { + public static $AJAX_THUMB_UPDATE = 'ajax_thumb_update'; + public static $PAGE_LOGIN = 'login'; public static $PAGE_PICWALL = 'picwall'; @@ -47,6 +49,8 @@ class Router public static $PAGE_SAVE_PLUGINSADMIN = 'save_pluginadmin'; + public static $PAGE_THUMBS_UPDATE = 'thumbs_update'; + public static $GET_TOKEN = 'token'; /** @@ -101,6 +105,14 @@ public static function findPage($query, $get, $loggedIn) return self::$PAGE_FEED_RSS; } + if (startsWith($query, 'do='. self::$PAGE_THUMBS_UPDATE)) { + return self::$PAGE_THUMBS_UPDATE; + } + + if (startsWith($query, 'do='. self::$AJAX_THUMB_UPDATE)) { + return self::$AJAX_THUMB_UPDATE; + } + // At this point, only loggedin pages. if (!$loggedIn) { return self::$PAGE_LINKLIST; diff --git a/application/Updater.php b/application/Updater.php index 6fbe3e00..f6b9e205 100644 --- a/application/Updater.php +++ b/application/Updater.php @@ -30,6 +30,11 @@ class Updater */ protected $isLoggedIn; + /** + * @var array $_SESSION + */ + protected $session; + /** * @var ReflectionMethod[] List of current class methods. */ @@ -42,13 +47,17 @@ class Updater * @param LinkDB $linkDB LinkDB instance. * @param ConfigManager $conf Configuration Manager instance. * @param boolean $isLoggedIn True if the user is logged in. + * @param array $session $_SESSION (by reference) + * + * @throws ReflectionException */ - public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn) + public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn, &$session = []) { $this->doneUpdates = $doneUpdates; $this->linkDB = $linkDB; $this->conf = $conf; $this->isLoggedIn = $isLoggedIn; + $this->session = &$session; // Retrieve all update methods. $class = new ReflectionClass($this); @@ -488,11 +497,23 @@ public function updateMethodDownloadSizeAndTimeoutConf() */ public function updateMethodWebThumbnailer() { - $this->conf->set('thumbnails.enabled', $this->conf->get('thumbnail.enable_thumbnails', true)); + if ($this->conf->exists('thumbnails.enabled')) { + return true; + } + + $thumbnailsEnabled = $this->conf->get('thumbnail.enable_thumbnails', true); + $this->conf->set('thumbnails.enabled', $thumbnailsEnabled); $this->conf->set('thumbnails.width', 125); $this->conf->set('thumbnails.height', 90); $this->conf->remove('thumbnail'); $this->conf->write(true); + + if ($thumbnailsEnabled) { + $this->session['warnings'][] = t( + 'You have enabled thumbnails. Please synchonize them.' + ); + } + return true; } } diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php index faf25426..96e2e912 100644 --- a/application/config/ConfigManager.php +++ b/application/config/ConfigManager.php @@ -367,10 +367,6 @@ protected function setDefaultValues() $this->setEmpty('general.enabled_plugins', self::$DEFAULT_PLUGINS); $this->setEmpty('general.default_note_title', 'Note: '); - $this->setEmpty('thumbnails.enabled', true); - $this->setEmpty('thumbnails.width', 120); - $this->setEmpty('thumbnails.height', 120); - $this->setEmpty('updates.check_updates', false); $this->setEmpty('updates.check_updates_branch', 'stable'); $this->setEmpty('updates.check_updates_interval', 86400); @@ -385,9 +381,6 @@ protected function setDefaultValues() // default state of the 'remember me' checkbox of the login form $this->setEmpty('privacy.remember_user_default', true); - $this->setEmpty('thumbnail.enable_thumbnails', true); - $this->setEmpty('thumbnail.enable_localcache', true); - $this->setEmpty('redirector.url', ''); $this->setEmpty('redirector.encode_url', true); diff --git a/assets/common/js/thumbnails-update.js b/assets/common/js/thumbnails-update.js new file mode 100644 index 00000000..b66ca3ae --- /dev/null +++ b/assets/common/js/thumbnails-update.js @@ -0,0 +1,51 @@ +/** + * Script used in the thumbnails update page. + * + * It retrieves the list of link IDs to update, and execute AJAX requests + * to update their thumbnails, while updating the progress bar. + */ + +/** + * Update the thumbnail of the link with the current i index in ids. + * It contains a recursive call to retrieve the thumb of the next link when it succeed. + * It also update the progress bar and other visual feedback elements. + * + * @param {array} ids List of LinkID to update + * @param {int} i Current index in ids + * @param {object} elements List of DOM element to avoid retrieving them at each iteration + */ +function updateThumb(ids, i, elements) { + const xhr = new XMLHttpRequest(); + xhr.open('POST', '?do=ajax_thumb_update'); + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + xhr.responseType = 'json'; + xhr.onload = () => { + if (xhr.status !== 200) { + alert(`An error occurred. Return code: ${xhr.status}`); + } else { + const { response } = xhr; + i += 1; + elements.progressBar.style.width = `${(i * 100) / ids.length}%`; + elements.current.innerHTML = i; + elements.title.innerHTML = response.title; + if (response.thumbnail !== false) { + elements.thumbnail.innerHTML = ``; + } + if (i < ids.length) { + updateThumb(ids, i, elements); + } + } + }; + xhr.send(`id=${ids[i]}`); +} + +(() => { + const ids = document.getElementsByName('ids')[0].value.split(','); + const elements = { + progressBar: document.querySelector('.progressbar > div'), + current: document.querySelector('.progress-current'), + thumbnail: document.querySelector('.thumbnail-placeholder'), + title: document.querySelector('.thumbnail-link-title'), + }; + updateThumb(ids, 0, elements); +})(); diff --git a/assets/default/scss/shaarli.scss b/assets/default/scss/shaarli.scss index 425a0490..6a8a8bc7 100644 --- a/assets/default/scss/shaarli.scss +++ b/assets/default/scss/shaarli.scss @@ -146,6 +146,13 @@ body, background-color: $main-green; } +.pure-alert-warning { + a { + color: $warning-text; + font-weight: bold; + } +} + .page-single-alert { margin-top: 100px; } @@ -1547,3 +1554,40 @@ form { .pure-button-shaarli { background-color: $main-green; } + +.progressbar { + border-radius: 6px; + background-color: $main-green; + padding: 1px; + + > div { + border-radius: 10px; + background: repeating-linear-gradient( + -45deg, + $almost-white, + $almost-white 6px, + $background-color 6px, + $background-color 12px + ); + width: 0%; + height: 10px; + } +} + +.thumbnails-page-container { + .progress-counter { + padding: 10px 0 20px; + } + + .thumbnail-placeholder { + margin: 10px auto; + background-color: $light-grey; + } + + .thumbnail-link-title { + padding-bottom: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} diff --git a/assets/vintage/css/shaarli.css b/assets/vintage/css/shaarli.css index 05e2c17e..87c440c8 100644 --- a/assets/vintage/css/shaarli.css +++ b/assets/vintage/css/shaarli.css @@ -1210,3 +1210,43 @@ ul.errors { width: 13px; height: 13px; } + +.thumbnails-update-container { + padding: 20px 0; + width: 50%; + margin: auto; +} + +.thumbnails-update-container .thumbnail-placeholder { + background: grey; + margin: auto; +} + +.thumbnails-update-container .thumbnail-link-title { + width: 75%; + margin: auto; + + padding-bottom: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.progressbar { + border-radius: 6px; + background-color: #111; + padding: 1px; +} + +.progressbar > div { + border-radius: 10px; + background: repeating-linear-gradient( + -45deg, + #f5f5f5, + #f5f5f5 6px, + #d0d0d0 6px, + #d0d0d0 12px + ); + width: 0%; + height: 10px; +} diff --git a/composer.lock b/composer.lock index f97a688c..43c4ba68 100644 --- a/composer.lock +++ b/composer.lock @@ -551,12 +551,12 @@ "source": { "type": "git", "url": "https://github.com/pubsubhubbub/php-publisher.git", - "reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f" + "reference": "5008fc529b057251b48f4d17a10fdb20047ea8f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/0d224daebd504ab61c22fee4db58f8d1fc18945f", - "reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f", + "url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/5008fc529b057251b48f4d17a10fdb20047ea8f5", + "reference": "5008fc529b057251b48f4d17a10fdb20047ea8f5", "shasum": "" }, "require": { @@ -586,7 +586,7 @@ "publishers", "pubsubhubbub" ], - "time": "2017-10-08T10:59:41+00:00" + "time": "2018-05-22T11:56:26+00:00" }, { "name": "shaarli/netscape-bookmark-parser", @@ -2254,21 +2254,22 @@ }, { "name": "symfony/config", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "7c2a9d44f4433863e9bca682e7f03609234657f9" + "reference": "73e055cf2e6467715f187724a0347ea32079967c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/7c2a9d44f4433863e9bca682e7f03609234657f9", - "reference": "7c2a9d44f4433863e9bca682e7f03609234657f9", + "url": "https://api.github.com/repos/symfony/config/zipball/73e055cf2e6467715f187724a0347ea32079967c", + "reference": "73e055cf2e6467715f187724a0347ea32079967c", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0" + "symfony/filesystem": "~2.8|~3.0|~4.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/dependency-injection": "<3.3", @@ -2313,20 +2314,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-03-19T22:32:39+00:00" + "time": "2018-05-14T16:49:53+00:00" }, { "name": "symfony/console", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "5b1fdfa8eb93464bcc36c34da39cedffef822cdf" + "reference": "36f83f642443c46f3cf751d4d2ee5d047d757a27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/5b1fdfa8eb93464bcc36c34da39cedffef822cdf", - "reference": "5b1fdfa8eb93464bcc36c34da39cedffef822cdf", + "url": "https://api.github.com/repos/symfony/console/zipball/36f83f642443c46f3cf751d4d2ee5d047d757a27", + "reference": "36f83f642443c46f3cf751d4d2ee5d047d757a27", "shasum": "" }, "require": { @@ -2382,20 +2383,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-04-30T01:22:56+00:00" + "time": "2018-05-16T08:49:21+00:00" }, { "name": "symfony/debug", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f" + "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/1b95888cfd996484527cb41e8952d9a5eaf7454f", - "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f", + "url": "https://api.github.com/repos/symfony/debug/zipball/b28fd73fefbac341f673f5efd707d539d6a19f68", + "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68", "shasum": "" }, "require": { @@ -2438,20 +2439,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-04-30T16:53:52+00:00" + "time": "2018-05-16T14:03:39+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3" + "reference": "8a4672aca8db6d807905d695799ea7d83c8e5bba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54ff9d78b56429f9a1ac12e60bfb6d169c0468e3", - "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8a4672aca8db6d807905d695799ea7d83c8e5bba", + "reference": "8a4672aca8db6d807905d695799ea7d83c8e5bba", "shasum": "" }, "require": { @@ -2509,24 +2510,25 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2018-04-29T14:04:08+00:00" + "time": "2018-05-25T11:57:15+00:00" }, { "name": "symfony/filesystem", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541" + "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/253a4490b528597aa14d2bf5aeded6f5e5e4a541", - "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0", + "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { @@ -2558,20 +2560,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-02-22T10:48:49+00:00" + "time": "2018-05-16T08:49:21+00:00" }, { "name": "symfony/finder", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433" + "reference": "472a92f3df8b247b49ae364275fb32943b9656c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/bd14efe8b1fabc4de82bf50dce62f05f9a102433", - "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433", + "url": "https://api.github.com/repos/symfony/finder/zipball/472a92f3df8b247b49ae364275fb32943b9656c6", + "reference": "472a92f3df8b247b49ae364275fb32943b9656c6", "shasum": "" }, "require": { @@ -2607,7 +2609,62 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-04-04T05:07:11+00:00" + "time": "2018-05-16T08:49:21+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2018-04-30T19:57:29+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -2670,20 +2727,21 @@ }, { "name": "symfony/yaml", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "033cfa61ef06ee0847e056e530201842b6e926c3" + "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/033cfa61ef06ee0847e056e530201842b6e926c3", - "reference": "033cfa61ef06ee0847e056e530201842b6e926c3", + "url": "https://api.github.com/repos/symfony/yaml/zipball/c5010cc1692ce1fa328b1fb666961eb3d4a85bb0", + "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" @@ -2724,7 +2782,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-04-08T08:21:29+00:00" + "time": "2018-05-03T23:18:14+00:00" }, { "name": "theseer/fdomdocument", diff --git a/index.php b/index.php index 953f1085..d5a3e93d 100644 --- a/index.php +++ b/index.php @@ -514,7 +514,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, read_updates_file($conf->get('resource.updates')), $LINKSDB, $conf, - $loginManager->isLoggedIn() + $loginManager->isLoggedIn(), + $_SESSION ); try { $newUpdates = $updater->update(); @@ -529,7 +530,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, die($e->getMessage()); } - $PAGE = new PageBuilder($conf, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn()); + $PAGE = new PageBuilder($conf, $_SESSION, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn()); $PAGE->assign('linkcount', count($LINKSDB)); $PAGE->assign('privateLinkcount', count_private($LINKSDB)); $PAGE->assign('plugin_errors', $pluginManager->getErrors()); @@ -611,38 +612,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $links = $LINKSDB->filterSearch($_GET); $linksToDisplay = array(); - $thumbnailer = new Thumbnailer($conf); - - - $newThumbnailsCpt = 0; // Get only links which have a thumbnail. + // Note: we do not retrieve thumbnails here, the request is too heavy. foreach($links as $key => $link) { - // Not a note, - // and (never retrieved yet or no valid cache file) - if ($link['url'][0] != '?' - && (! isset($link['thumbnail']) || ($link['thumbnail'] !== false && ! is_file($link['thumbnail']))) - ) { - $item = $LINKSDB[$key]; - $item['thumbnail'] = $thumbnailer->get($link['url']); - $LINKSDB[$key] = $item; - $newThumbnailsCpt++; - } - if (isset($link['thumbnail']) && $link['thumbnail'] !== false) { $linksToDisplay[] = $link; // Add to array. } - - // If we retrieved new thumbnails, we update the database every 20 links. - // Downloading everything the first time may take a very long time - if ($newThumbnailsCpt == 20) { - $LINKSDB->save($conf->get('resource.page_cache')); - $newThumbnailsCpt = 0; - } - } - - if ($newThumbnailsCpt > 0) { - $LINKSDB->save($conf->get('resource.page_cache')); } $data = array( @@ -1036,7 +1012,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $conf->set('api.enabled', !empty($_POST['enableApi'])); $conf->set('api.secret', escape($_POST['apiSecret'])); $conf->set('translation.language', escape($_POST['language'])); - $conf->set('thumbnails.enabled', extension_loaded('gd') && !empty($_POST['enableThumbnails'])); + + $thumbnailsEnabled = extension_loaded('gd') && !empty($_POST['enableThumbnails']); + $conf->set('thumbnails.enabled', $thumbnailsEnabled); + + if (! $conf->get('thumbnails.enabled') && $thumbnailsEnabled) { + $_SESSION['warnings'][] = t( + 'You have enabled thumbnails. Please synchonize them.' + ); + } try { $conf->write($loginManager->isLoggedIn()); @@ -1521,6 +1505,43 @@ function($a, $b) { return $a['order'] - $b['order']; } exit; } + // -------- Thumbnails Update + if ($targetPage == Router::$PAGE_THUMBS_UPDATE) { + $ids = []; + foreach ($LINKSDB as $link) { + // A note or not HTTP(S) + if ($link['url'][0] === '?' || ! startsWith(strtolower($link['url']), 'http')) { + continue; + } + $ids[] = $link['id']; + } + $PAGE->assign('ids', $ids); + $PAGE->assign('pagetitle', t('Thumbnail update') .' - '. $conf->get('general.title', 'Shaarli')); + $PAGE->renderPage('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 (empty($LINKSDB[$id])) { + http_response_code(404); + exit; + } + $thumbnailer = new Thumbnailer($conf); + $link = $LINKSDB[$id]; + $link['thumbnail'] = $thumbnailer->get($link['url']); + $LINKSDB[$id] = $link; + $LINKSDB->save($conf->get('resource.page_cache')); + + echo json_encode($link); + exit; + } + // -------- Otherwise, simply display search form and links: showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); exit; @@ -1777,7 +1798,7 @@ function install($conf, $sessionManager, $loginManager) { exit; } - $PAGE = new PageBuilder($conf, null, $sessionManager->generateToken()); + $PAGE = new PageBuilder($conf, $_SESSION, null, $sessionManager->generateToken()); list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); $PAGE->assign('continents', $continents); $PAGE->assign('cities', $cities); diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php index 8b90fd5e..92ff5690 100644 --- a/tests/Updater/UpdaterTest.php +++ b/tests/Updater/UpdaterTest.php @@ -20,7 +20,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase /** * @var string Config file path (without extension). */ - protected static $configFile = 'tests/utils/config/configJson'; + protected static $configFile = 'sandbox/config'; /** * @var ConfigManager @@ -32,6 +32,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase */ public function setUp() { + copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php'); $this->conf = new ConfigManager(self::$configFile); } @@ -686,17 +687,48 @@ public function testUpdateMethodDownloadSizeAndTimeoutConfOnlyTimeout() } /** - * Test updateMethodAtomDefault with show_atom set to true. - * => nothing to do + * Test updateMethodWebThumbnailer with thumbnails enabled. */ public function testUpdateMethodWebThumbnailerEnabled() { + $this->conf->remove('thumbnails'); $this->conf->set('thumbnail.enable_thumbnails', true); - $updater = new Updater([], [], $this->conf, true); + $updater = new Updater([], [], $this->conf, true, $_SESSION); $this->assertTrue($updater->updateMethodWebThumbnailer()); $this->assertFalse($this->conf->exists('thumbnail')); $this->assertTrue($this->conf->get('thumbnails.enabled')); $this->assertEquals(125, $this->conf->get('thumbnails.width')); $this->assertEquals(90, $this->conf->get('thumbnails.height')); + $this->assertContains('You have enabled thumbnails', $_SESSION['warnings'][0]); + } + + /** + * Test updateMethodWebThumbnailer with thumbnails disabled. + */ + public function testUpdateMethodWebThumbnailerDisabled() + { + $this->conf->remove('thumbnails'); + $this->conf->set('thumbnail.enable_thumbnails', false); + $updater = new Updater([], [], $this->conf, true, $_SESSION); + $this->assertTrue($updater->updateMethodWebThumbnailer()); + $this->assertFalse($this->conf->exists('thumbnail')); + $this->assertFalse($this->conf->get('thumbnails.enabled')); + $this->assertEquals(125, $this->conf->get('thumbnails.width')); + $this->assertEquals(90, $this->conf->get('thumbnails.height')); + $this->assertTrue(empty($_SESSION['warnings'])); + } + + /** + * Test updateMethodWebThumbnailer with thumbnails disabled. + */ + public function testUpdateMethodWebThumbnailerNothingToDo() + { + $updater = new Updater([], [], $this->conf, true, $_SESSION); + $this->assertTrue($updater->updateMethodWebThumbnailer()); + $this->assertFalse($this->conf->exists('thumbnail')); + $this->assertTrue($this->conf->get('thumbnails.enabled')); + $this->assertEquals(90, $this->conf->get('thumbnails.width')); + $this->assertEquals(53, $this->conf->get('thumbnails.height')); + $this->assertTrue(empty($_SESSION['warnings'])); } } diff --git a/tests/utils/config/configJson.json.php b/tests/utils/config/configJson.json.php index 061d4c28..a656b67c 100644 --- a/tests/utils/config/configJson.json.php +++ b/tests/utils/config/configJson.json.php @@ -61,11 +61,6 @@ "dev": { "debug": true }, - "thumbnails": { - "enabled": true, - "width": 125, - "height": 90 - }, "updates": { "check_updates": false, "check_updates_branch": "stable", @@ -79,6 +74,11 @@ "language": "auto", "mode": "php", "extensions": [] + }, + "thumbnails": { + "enabled": true, + "width": 90, + "height": 53 } } -*/ ?> \ No newline at end of file +*/ ?> diff --git a/tpl/default/configure.html b/tpl/default/configure.html index 5695ae8e..dca9503b 100644 --- a/tpl/default/configure.html +++ b/tpl/default/configure.html @@ -248,12 +248,10 @@

{'Configure'|t}

diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html index 840e4352..fc03404e 100644 --- a/tpl/default/page.header.html +++ b/tpl/default/page.header.html @@ -171,4 +171,18 @@ {/if} +{if="!empty($global_warnings) && $is_logged_in"} +
+
+
+ {loop="global_warnings"} +

{$value}

+ {/loop} +
+
+ +
+
+{/if} +
diff --git a/tpl/default/thumbnails.html b/tpl/default/thumbnails.html new file mode 100644 index 00000000..a8cf904e --- /dev/null +++ b/tpl/default/thumbnails.html @@ -0,0 +1,48 @@ + + + + {include="includes"} + + +{include="page.header"} + +
+
+
+

{'Thumbnails update'|t}

+ +
+
+
+
+
+
+ +
+
+
+ + +
+
+
+
+
+ +
+
+
+
+ 0 / {$ids|count} +
+
+
+ + +
+
+ +{include="page.footer"} + + + diff --git a/tpl/vintage/configure.html b/tpl/vintage/configure.html index e47c71ad..fc3a563b 100644 --- a/tpl/vintage/configure.html +++ b/tpl/vintage/configure.html @@ -132,11 +132,13 @@ Enable thumbnails + {if="$thumbnails_enabled"}checked{/if} {if="!$gd_enabled"}disabled{/if}> diff --git a/tpl/vintage/thumbnails.html b/tpl/vintage/thumbnails.html new file mode 100644 index 00000000..79aebf8d --- /dev/null +++ b/tpl/vintage/thumbnails.html @@ -0,0 +1,28 @@ + + +{include="includes"} + + + +
+
+ + + +
+
+
+ +
+ 0 / {$ids|count} +
+
+ + + +{include="page.footer"} + + + diff --git a/webpack.config.js b/webpack.config.js index 1fc5d016..ed548c73 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -24,6 +24,7 @@ module.exports = [ { entry: { thumbnails: './assets/common/js/thumbnails.js', + thumbnails_update: './assets/common/js/thumbnails-update.js', pluginsadmin: './assets/default/js/plugins-admin.js', shaarli: [ './assets/default/js/base.js', @@ -97,6 +98,7 @@ module.exports = [ './assets/vintage/css/shaarli.css', ].concat(glob.sync('./assets/vintage/img/*')), thumbnails: './assets/common/js/thumbnails.js', + thumbnails_update: './assets/common/js/thumbnails-update.js', }, output: { filename: '[name].min.js',