]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Process main page (linklist) through Slim controller
authorArthurHoaro <arthur@hoa.ro>
Mon, 6 Jul 2020 06:04:35 +0000 (08:04 +0200)
committerArthurHoaro <arthur@hoa.ro>
Thu, 23 Jul 2020 19:19:21 +0000 (21:19 +0200)
Including a bunch of improvements on the container,
and helper used across new controllers.

44 files changed:
application/api/ApiMiddleware.php
application/bookmark/BookmarkFileService.php
application/container/ContainerBuilder.php
application/container/ShaarliContainer.php
application/front/ShaarliMiddleware.php
application/front/controller/admin/ConfigureController.php
application/front/controller/admin/ExportController.php
application/front/controller/admin/ImportController.php
application/front/controller/admin/ManageShaareController.php
application/front/controller/admin/ManageTagController.php
application/front/controller/admin/PasswordController.php
application/front/controller/admin/PluginsController.php
application/front/controller/admin/ThumbnailsController.php
application/front/controller/admin/ToolsController.php
application/front/controller/visitor/BookmarkListController.php [new file with mode: 0644]
application/front/controller/visitor/DailyController.php
application/front/controller/visitor/LoginController.php
application/front/controller/visitor/OpenSearchController.php
application/front/controller/visitor/PictureWallController.php
application/legacy/LegacyController.php [new file with mode: 0644]
application/legacy/LegacyRouter.php [moved from application/Router.php with 98% similarity]
application/legacy/UnknowLegacyRouteException.php [new file with mode: 0644]
application/render/PageBuilder.php
application/render/TemplatePage.php [new file with mode: 0644]
application/updater/Updater.php
doc/md/Plugin-System.md
index.php
plugins/addlink_toolbar/addlink_toolbar.php
plugins/demo_plugin/demo_plugin.php
plugins/isso/isso.php
plugins/playvideos/playvideos.php
plugins/pubsubhubbub/pubsubhubbub.php
plugins/qrcode/qrcode.php
tests/bookmark/BookmarkFileServiceTest.php
tests/front/ShaarliMiddlewareTest.php
tests/front/controller/visitor/BookmarkListControllerTest.php [new file with mode: 0644]
tests/legacy/LegacyControllerTest.php [new file with mode: 0644]
tests/legacy/LegacyRouterTest.php [moved from tests/RouterTest.php with 51% similarity]
tests/plugins/PluginAddlinkTest.php
tests/plugins/PluginPlayvideosTest.php
tests/plugins/PluginPubsubhubbubTest.php
tests/plugins/PluginQrcodeTest.php
tests/updater/UpdaterTest.php
tpl/default/linklist.html

index 4745ac94101db8efb3c83bc760dd154a3af0445e..09ce6445303bf5f9280e033c6004bf5e56f725c9 100644 (file)
@@ -71,7 +71,14 @@ class ApiMiddleware
             $response = $e->getApiResponse();
         }
 
-        return $response;
+        return $response
+            ->withHeader('Access-Control-Allow-Origin', '*')
+            ->withHeader(
+                'Access-Control-Allow-Headers',
+                'X-Requested-With, Content-Type, Accept, Origin, Authorization'
+            )
+            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
+        ;
     }
 
     /**
index 7439d8d8d830bf7de9e56d9c342085c923f894e5..3d15d4c921d71e7c3db2e174ce59d07e0a556b72 100644 (file)
@@ -93,7 +93,7 @@ class BookmarkFileService implements BookmarkServiceInterface
             throw new Exception('Not authorized');
         }
 
-        return $bookmark;
+        return $first;
     }
 
     /**
index ba91fe8b58e11a0f2c9972aeccc5c53d5b78d6cd..ccb87c3a22cc93060e1ec882385814be05c66f23 100644 (file)
@@ -18,6 +18,8 @@ use Shaarli\Render\PageCacheManager;
 use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
 use Shaarli\Thumbnailer;
+use Shaarli\Updater\Updater;
+use Shaarli\Updater\UpdaterUtils;
 
 /**
  * Class ContainerBuilder
@@ -128,6 +130,15 @@ class ContainerBuilder
             return new NetscapeBookmarkUtils($container->bookmarkService, $container->conf, $container->history);
         };
 
+        $container['updater'] = function (ShaarliContainer $container): Updater {
+            return new Updater(
+                UpdaterUtils::read_updates_file($container->conf->get('resource.updates')),
+                $container->bookmarkService,
+                $container->conf,
+                $container->loginManager->isLoggedIn()
+            );
+        };
+
         return $container;
     }
 }
index b08fa4cb9c286ae612bf425efb859b6af1ba473c..09e7d5b1ae78b029ea14f32d3bd568515d48484a 100644 (file)
@@ -17,15 +17,17 @@ use Shaarli\Render\PageCacheManager;
 use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
 use Shaarli\Thumbnailer;
+use Shaarli\Updater\Updater;
 use Slim\Container;
 
 /**
  * Extension of Slim container to document the injected objects.
  *
- * @property string                   $basePath        Shaarli's instance base path (e.g. `/shaarli/`)
+ * @property string                   $basePath             Shaarli's instance base path (e.g. `/shaarli/`)
  * @property BookmarkServiceInterface $bookmarkService
  * @property ConfigManager            $conf
- * @property mixed[]                  $environment     $_SERVER automatically injected by Slim
+ * @property mixed[]                  $environment          $_SERVER automatically injected by Slim
+ * @property callable                 $errorHandler         Overrides default Slim error display
  * @property FeedBuilder              $feedBuilder
  * @property FormatterFactory         $formatterFactory
  * @property History                  $history
@@ -37,6 +39,7 @@ use Slim\Container;
  * @property PluginManager            $pluginManager
  * @property SessionManager           $sessionManager
  * @property Thumbnailer              $thumbnailer
+ * @property Updater                  $updater
  */
 class ShaarliContainer extends Container
 {
index 7ad610c7db4984d6c8b923ac95c56b2351297627..baea6ef28396c7c517af1a8c4585c912538003c1 100644 (file)
@@ -25,6 +25,8 @@ class ShaarliMiddleware
 
     /**
      * Middleware execution:
+     *   - run updates
+     *   - if not logged in open shaarli, redirect to login
      *   - execute the controller
      *   - return the response
      *
@@ -36,27 +38,82 @@ class ShaarliMiddleware
      *
      * @return Response response.
      */
-    public function __invoke(Request $request, Response $response, callable $next)
+    public function __invoke(Request $request, Response $response, callable $next): Response
     {
         $this->container->basePath = rtrim($request->getUri()->getBasePath(), '/');
 
         try {
-            $response = $next($request, $response);
+            $this->runUpdates();
+            $this->checkOpenShaarli($request, $response, $next);
+
+            return $next($request, $response);
         } catch (ShaarliFrontException $e) {
+            // Possible functional error
+            $this->container->pageBuilder->reset();
             $this->container->pageBuilder->assign('message', $e->getMessage());
+
+            $response = $response->withStatus($e->getCode());
+
+            return $response->write($this->container->pageBuilder->render('error'));
+        } catch (UnauthorizedException $e) {
+            return $response->withRedirect($this->container->basePath . '/login');
+        } catch (\Throwable $e) {
+            // Unknown error encountered
+            $this->container->pageBuilder->reset();
             if ($this->container->conf->get('dev.debug', false)) {
+                $this->container->pageBuilder->assign('message', $e->getMessage());
                 $this->container->pageBuilder->assign(
                     'stacktrace',
-                    nl2br(get_class($this) .': '. $e->getTraceAsString())
+                    nl2br(get_class($e) .': '. PHP_EOL . $e->getTraceAsString())
                 );
+            } else {
+                $this->container->pageBuilder->assign('message', t('An unexpected error occurred.'));
             }
 
-            $response = $response->withStatus($e->getCode());
-            $response = $response->write($this->container->pageBuilder->render('error'));
-        } catch (UnauthorizedException $e) {
-            return $response->withRedirect($this->container->basePath . '/login');
+            $response = $response->withStatus(500);
+
+            return $response->write($this->container->pageBuilder->render('error'));
+        }
+    }
+
+    /**
+     * Run the updater for every requests processed while logged in.
+     */
+    protected function runUpdates(): void
+    {
+        if ($this->container->loginManager->isLoggedIn() !== true) {
+            return;
+        }
+
+        $newUpdates = $this->container->updater->update();
+        if (!empty($newUpdates)) {
+            $this->container->updater->writeUpdates(
+                $this->container->conf->get('resource.updates'),
+                $this->container->updater->getDoneUpdates()
+            );
+
+            $this->container->pageCacheManager->invalidateCaches();
+        }
+    }
+
+    /**
+     * Access is denied to most pages with `hide_public_links` + `force_login` settings.
+     */
+    protected function checkOpenShaarli(Request $request, Response $response, callable $next): bool
+    {
+        if (// if the user isn't logged in
+            !$this->container->loginManager->isLoggedIn()
+            // and Shaarli doesn't have public content...
+            && $this->container->conf->get('privacy.hide_public_links')
+            // and is configured to enforce the login
+            && $this->container->conf->get('privacy.force_login')
+            // and the current page isn't already the login page
+            // and the user is not requesting a feed (which would lead to a different content-type as expected)
+            && !in_array($next->getName(), ['login', 'atom', 'rss'], true)
+        ) {
+            throw new UnauthorizedException();
         }
 
-        return $response;
+        return true;
     }
 }
index 201a859bc5f27c6be4230a92012c7cce5bd41a21..865fc2b08c212f22b1d516e110dbf55a722a7657 100644 (file)
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Admin;
 
 use Shaarli\Languages;
+use Shaarli\Render\TemplatePage;
 use Shaarli\Render\ThemeUtils;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
@@ -52,7 +53,7 @@ class ConfigureController extends ShaarliAdminController
         $this->assignView('thumbnails_mode', $this->container->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE));
         $this->assignView('pagetitle', t('Configure') .' - '. $this->container->conf->get('general.title', 'Shaarli'));
 
-        return $response->write($this->render('configure'));
+        return $response->write($this->render(TemplatePage::CONFIGURE));
     }
 
     /**
index 7afbfc2389c3b07876a8886ef2397dcc72904e5e..2be957fae0f4ec8c62e506f7da8589fca1d70244 100644 (file)
@@ -6,6 +6,7 @@ namespace Shaarli\Front\Controller\Admin;
 
 use DateTime;
 use Shaarli\Bookmark\Bookmark;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -24,7 +25,7 @@ class ExportController extends ShaarliAdminController
     {
         $this->assignView('pagetitle', t('Export') .' - '. $this->container->conf->get('general.title', 'Shaarli'));
 
-        return $response->write($this->render('export'));
+        return $response->write($this->render(TemplatePage::EXPORT));
     }
 
     /**
@@ -74,6 +75,6 @@ class ExportController extends ShaarliAdminController
         $this->assignView('eol', PHP_EOL);
         $this->assignView('selection', $selection);
 
-        return $response->write($this->render('export.bookmarks'));
+        return $response->write($this->render(TemplatePage::NETSCAPE_EXPORT_BOOKMARKS));
     }
 }
index 8c5305b9f0939d333a2d65b97c0628958f861261..758d5ef9454a0514316c5beff78181f3146708d8 100644 (file)
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Admin;
 
 use Psr\Http\Message\UploadedFileInterface;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -39,7 +40,7 @@ class ImportController extends ShaarliAdminController
         );
         $this->assignView('pagetitle', t('Import') .' - '. $this->container->conf->get('general.title', 'Shaarli'));
 
-        return $response->write($this->render('import'));
+        return $response->write($this->render(TemplatePage::IMPORT));
     }
 
     /**
index bdfc5ca7fb7e12c535642e898ece83c67d08ac0c..3aa484239e71b62539157e20ba7b9f70b15e543c 100644 (file)
@@ -7,6 +7,7 @@ namespace Shaarli\Front\Controller\Admin;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Formatter\BookmarkMarkdownFormatter;
+use Shaarli\Render\TemplatePage;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -28,7 +29,7 @@ class ManageShaareController extends ShaarliAdminController
             t('Shaare a new link') .' - '. $this->container->conf->get('general.title', 'Shaarli')
         );
 
-        return $response->write($this->render('addlink'));
+        return $response->write($this->render(TemplatePage::ADDLINK));
     }
 
     /**
@@ -365,7 +366,7 @@ class ManageShaareController extends ShaarliAdminController
             $editLabel . t('Shaare') .' - '. $this->container->conf->get('general.title', 'Shaarli')
         );
 
-        return $response->write($this->render('editlink'));
+        return $response->write($this->render(TemplatePage::EDIT_LINK));
     }
 
     /**
index 7dab288a4e392a56e80189a43b76f62159e374ba..0380ef1f2c4166cd818e52b72d6be36279bfdecd 100644 (file)
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Admin;
 
 use Shaarli\Bookmark\BookmarkFilter;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -28,7 +29,7 @@ class ManageTagController extends ShaarliAdminController
             t('Manage tags') .' - '. $this->container->conf->get('general.title', 'Shaarli')
         );
 
-        return $response->write($this->render('changetag'));
+        return $response->write($this->render(TemplatePage::CHANGE_TAG));
     }
 
     /**
index bcce01a6fbd36cbe105607ac7e50c428eb1705b3..5ec0d24b2fac824ce8d88e852cf8d62bb6809971 100644 (file)
@@ -7,6 +7,7 @@ namespace Shaarli\Front\Controller\Admin;
 use Shaarli\Container\ShaarliContainer;
 use Shaarli\Front\Exception\OpenShaarliPasswordException;
 use Shaarli\Front\Exception\ShaarliFrontException;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Throwable;
@@ -33,7 +34,7 @@ class PasswordController extends ShaarliAdminController
      */
     public function index(Request $request, Response $response): Response
     {
-        return $response->write($this->render('changepassword'));
+        return $response->write($this->render(TemplatePage::CHANGE_PASSWORD));
     }
 
     /**
@@ -55,7 +56,7 @@ class PasswordController extends ShaarliAdminController
 
             return $response
                 ->withStatus(400)
-                ->write($this->render('changepassword'))
+                ->write($this->render(TemplatePage::CHANGE_PASSWORD))
             ;
         }
 
@@ -71,7 +72,7 @@ class PasswordController extends ShaarliAdminController
 
             return $response
                 ->withStatus(400)
-                ->write($this->render('changepassword'))
+                ->write($this->render(TemplatePage::CHANGE_PASSWORD))
             ;
         }
 
@@ -95,6 +96,6 @@ class PasswordController extends ShaarliAdminController
 
         $this->saveSuccessMessage(t('Your password has been changed'));
 
-        return $response->write($this->render('changepassword'));
+        return $response->write($this->render(TemplatePage::CHANGE_PASSWORD));
     }
 }
index d5ec91f04aa6bdaa2361fbd2dcff5913320da519..44025395e740e314682975fe41e6f91d8a560457 100644 (file)
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Admin;
 
 use Exception;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -44,7 +45,7 @@ class PluginsController extends ShaarliAdminController
             t('Plugin Administration') .' - '. $this->container->conf->get('general.title', 'Shaarli')
         );
 
-        return $response->write($this->render('pluginsadmin'));
+        return $response->write($this->render(TemplatePage::PLUGINS_ADMIN));
     }
 
     /**
index e53085105e15a0b69a8c0d2faec0f706757a8f74..81c87ed0369a4651abeeaa51ec7294159895decc 100644 (file)
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Admin;
 
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -36,7 +37,7 @@ class ThumbnailsController extends ShaarliAdminController
             t('Thumbnails update') .' - '. $this->container->conf->get('general.title', 'Shaarli')
         );
 
-        return $response->write($this->render('thumbnails'));
+        return $response->write($this->render(TemplatePage::THUMBNAILS));
     }
 
     /**
@@ -61,19 +62,4 @@ class ThumbnailsController extends ShaarliAdminController
 
         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 d087f2cd7c330a8855331d2561685ba03ee18fdf..a476e8983a4051748015e8ea5e44fb7ff5d15f8e 100644 (file)
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -29,7 +30,7 @@ class ToolsController extends ShaarliAdminController
 
         $this->assignView('pagetitle', t('Tools') .' - '. $this->container->conf->get('general.title', 'Shaarli'));
 
-        return $response->write($this->render('tools'));
+        return $response->write($this->render(TemplatePage::TOOLS));
     }
 
     /**
diff --git a/application/front/controller/visitor/BookmarkListController.php b/application/front/controller/visitor/BookmarkListController.php
new file mode 100644 (file)
index 0000000..a37a7f6
--- /dev/null
@@ -0,0 +1,248 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller\Visitor;
+
+use Shaarli\Bookmark\Bookmark;
+use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
+use Shaarli\Legacy\LegacyController;
+use Shaarli\Legacy\UnknowLegacyRouteException;
+use Shaarli\Render\TemplatePage;
+use Shaarli\Thumbnailer;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+/**
+ * Class BookmarkListController
+ *
+ * Slim controller used to render the bookmark list, the home page of Shaarli.
+ * It also displays permalinks, and process legacy routes based on GET parameters.
+ */
+class BookmarkListController extends ShaarliVisitorController
+{
+    /**
+     * GET / - Displays the bookmark list, with optional filter parameters.
+     */
+    public function index(Request $request, Response $response): Response
+    {
+        $legacyResponse = $this->processLegacyController($request, $response);
+        if (null !== $legacyResponse) {
+            return $legacyResponse;
+        }
+
+        $formatter = $this->container->formatterFactory->getFormatter();
+
+        $searchTags = escape(normalize_spaces($request->getParam('searchtags') ?? ''));
+        $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));;
+
+        // Filter bookmarks according search parameters.
+        $visibility = $this->container->sessionManager->getSessionParameter('visibility');
+        $search = [
+            'searchtags' => $searchTags,
+            'searchterm' => $searchTerm,
+        ];
+        $linksToDisplay = $this->container->bookmarkService->search(
+            $search,
+            $visibility,
+            false,
+            !!$this->container->sessionManager->getSessionParameter('untaggedonly')
+        ) ?? [];
+
+        // ---- Handle paging.
+        $keys = [];
+        foreach ($linksToDisplay as $key => $value) {
+            $keys[] = $key;
+        }
+
+        $linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
+
+        // Select articles according to paging.
+        $pageCount = (int) ceil(count($keys) / $linksPerPage) ?: 1;
+        $page = (int) $request->getParam('page') ?? 1;
+        $page = $page < 1 ? 1 : $page;
+        $page = $page > $pageCount ? $pageCount : $page;
+
+        // Start index.
+        $i = ($page - 1) * $linksPerPage;
+        $end = $i + $linksPerPage;
+
+        $linkDisp = [];
+        $save = false;
+        while ($i < $end && $i < count($keys)) {
+            $save = $this->updateThumbnail($linksToDisplay[$keys[$i]], false) || $save;
+            $link = $formatter->format($linksToDisplay[$keys[$i]]);
+
+            $linkDisp[$keys[$i]] = $link;
+            $i++;
+        }
+
+        if ($save) {
+            $this->container->bookmarkService->save();
+        }
+
+        // Compute paging navigation
+        $searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags);
+        $searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm);
+
+        $previous_page_url = '';
+        if ($i !== count($keys)) {
+            $previous_page_url = '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl;
+        }
+        $next_page_url = '';
+        if ($page > 1) {
+            $next_page_url = '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl;
+        }
+
+        // Fill all template fields.
+        $data = array_merge(
+            $this->initializeTemplateVars(),
+            [
+                'previous_page_url' => $previous_page_url,
+                'next_page_url' => $next_page_url,
+                'page_current' => $page,
+                'page_max' => $pageCount,
+                'result_count' => count($linksToDisplay),
+                'search_term' => $searchTerm,
+                'search_tags' => $searchTags,
+                'visibility' => $visibility,
+                'links' => $linkDisp,
+            ]
+        );
+
+        if (!empty($searchTerm) || !empty($searchTags)) {
+            $data['pagetitle'] = t('Search: ');
+            $data['pagetitle'] .= ! empty($searchTerm) ? $searchTerm . ' ' : '';
+            $bracketWrap = function ($tag) {
+                return '[' . $tag . ']';
+            };
+            $data['pagetitle'] .= ! empty($searchTags)
+                ? implode(' ', array_map($bracketWrap, preg_split('/\s+/', $searchTags))) . ' '
+                : '';
+            $data['pagetitle'] .= '- ';
+        }
+
+        $data['pagetitle'] = ($data['pagetitle'] ?? '') . $this->container->conf->get('general.title', 'Shaarli');
+
+        $this->executeHooks($data);
+        $this->assignAllView($data);
+
+        return $response->write($this->render(TemplatePage::LINKLIST));
+    }
+
+    /**
+     * GET /shaare/{hash} - Display a single shaare
+     */
+    public function permalink(Request $request, Response $response, array $args): Response
+    {
+        try {
+            $bookmark = $this->container->bookmarkService->findByHash($args['hash']);
+        } catch (BookmarkNotFoundException $e) {
+            $this->assignView('error_message', $e->getMessage());
+
+            return $response->write($this->render(TemplatePage::ERROR_404));
+        }
+
+        $this->updateThumbnail($bookmark);
+
+        $data = array_merge(
+            $this->initializeTemplateVars(),
+            [
+                'pagetitle' => $bookmark->getTitle() .' - '. $this->container->conf->get('general.title', 'Shaarli'),
+                'links' => [$this->container->formatterFactory->getFormatter()->format($bookmark)],
+            ]
+        );
+
+        $this->executeHooks($data);
+        $this->assignAllView($data);
+
+        return $response->write($this->render(TemplatePage::LINKLIST));
+    }
+
+    /**
+     * Update the thumbnail of a single bookmark if necessary.
+     */
+    protected function updateThumbnail(Bookmark $bookmark, bool $writeDatastore = true): bool
+    {
+        // Logged in, thumbnails enabled, not a note, is HTTP
+        // and (never retrieved yet or no valid cache file)
+        if ($this->container->loginManager->isLoggedIn()
+            && $this->container->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE
+            && false !== $bookmark->getThumbnail()
+            && !$bookmark->isNote()
+            && (null === $bookmark->getThumbnail() || !is_file($bookmark->getThumbnail()))
+            && startsWith(strtolower($bookmark->getUrl()), 'http')
+        ) {
+            $bookmark->setThumbnail($this->container->thumbnailer->get($bookmark->getUrl()));
+            $this->container->bookmarkService->set($bookmark, $writeDatastore);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param mixed[] $data Template vars to process in plugins, passed as reference.
+     */
+    protected function executeHooks(array &$data): void
+    {
+        $this->container->pluginManager->executeHooks(
+            'render_linklist',
+            $data,
+            ['loggedin' => $this->container->loginManager->isLoggedIn()]
+        );
+    }
+
+    /**
+     * @return string[] Default template variables without values.
+     */
+    protected function initializeTemplateVars(): array
+    {
+        return [
+            'previous_page_url' => '',
+            'next_page_url' => '',
+            'page_max' => '',
+            'search_tags' => '',
+            'result_count' => '',
+        ];
+    }
+
+    /**
+     * Process legacy routes if necessary. They used query parameters.
+     * If no legacy routes is passed, return null.
+     */
+    protected function processLegacyController(Request $request, Response $response): ?Response
+    {
+        // Legacy smallhash filter
+        $queryString = $this->container->environment['QUERY_STRING'] ?? null;
+        if (null !== $queryString && 1 === preg_match('/^([a-zA-Z0-9-_@]{6})($|&|#)/', $queryString, $match)) {
+            return $this->redirect($response, '/shaare/' . $match[1]);
+        }
+
+        // Legacy controllers (mostly used for redirections)
+        if (null !== $request->getQueryParam('do')) {
+            $legacyController = new LegacyController($this->container);
+
+            try {
+                return $legacyController->process($request, $response, $request->getQueryParam('do'));
+            } catch (UnknowLegacyRouteException $e) {
+                // We ignore legacy 404
+                return null;
+            }
+        }
+
+        // Legacy GET admin routes
+        $legacyGetRoutes = array_intersect(
+            LegacyController::LEGACY_GET_ROUTES,
+            array_keys($request->getQueryParams() ?? [])
+        );
+        if (1 === count($legacyGetRoutes)) {
+            $legacyController = new LegacyController($this->container);
+
+            return $legacyController->process($request, $response, $legacyGetRoutes[0]);
+        }
+
+        return null;
+    }
+}
index e5c9ddaca03927c970c1468fe540ad288ad5f187..05b4f095970dc4dc19770d28278568561f73855e 100644 (file)
@@ -7,6 +7,7 @@ namespace Shaarli\Front\Controller\Visitor;
 use DateTime;
 use DateTimeImmutable;
 use Shaarli\Bookmark\Bookmark;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -85,7 +86,7 @@ class DailyController extends ShaarliVisitorController
             t('Daily') .' - '. format_date($dayDate, false) . ' - ' . $mainTitle
         );
 
-        return $response->write($this->render('daily'));
+        return $response->write($this->render(TemplatePage::DAILY));
     }
 
     /**
@@ -152,7 +153,7 @@ class DailyController extends ShaarliVisitorController
         $this->assignView('hide_timestamps', $this->container->conf->get('privacy.hide_timestamps', false));
         $this->assignView('days', $dataPerDay);
 
-        $rssContent = $this->render('dailyrss');
+        $rssContent = $this->render(TemplatePage::DAILY_RSS);
 
         $cache->cache($rssContent);
 
index 0db1f4632f3b70f12d61c17e592acb561e1fed71..a257766fc61dd4c5f8b3ee434fe292234246fe99 100644 (file)
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Visitor;
 
 use Shaarli\Front\Exception\LoginBannedException;
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -41,6 +42,6 @@ class LoginController extends ShaarliVisitorController
             ->assignView('pagetitle', t('Login') .' - '. $this->container->conf->get('general.title', 'Shaarli'))
         ;
 
-        return $response->write($this->render('loginform'));
+        return $response->write($this->render(TemplatePage::LOGIN));
     }
 }
index 0fd68db66ac55ce0b2e69361afe3aa1038c3e23e..36d60acf12639ba8dbd2d75e5ba74c3af5338c60 100644 (file)
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
+use Shaarli\Render\TemplatePage;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -21,6 +22,6 @@ class OpenSearchController extends ShaarliVisitorController
 
         $this->assignView('serverurl', index_url($this->container->environment));
 
-        return $response->write($this->render('opensearch'));
+        return $response->write($this->render(TemplatePage::OPEN_SEARCH));
     }
 }
index 4e1dce8c9b31411cadcd0b1a4fe72ffb540c6e19..5ef2cb1714c68e0e9edb26dfa861985386ebac49 100644 (file)
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Visitor;
 
 use Shaarli\Front\Exception\ThumbnailsDisabledException;
+use Shaarli\Render\TemplatePage;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -46,7 +47,7 @@ class PictureWallController extends ShaarliVisitorController
             $this->assignView($key, $value);
         }
 
-        return $response->write($this->render('picwall'));
+        return $response->write($this->render(TemplatePage::PICTURE_WALL));
     }
 
     /**
diff --git a/application/legacy/LegacyController.php b/application/legacy/LegacyController.php
new file mode 100644 (file)
index 0000000..a97b07b
--- /dev/null
@@ -0,0 +1,130 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Legacy;
+
+use Shaarli\Feed\FeedBuilder;
+use Shaarli\Front\Controller\Visitor\ShaarliVisitorController;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+/**
+ * We use this to maintain legacy routes, and redirect requests to the corresponding Slim route.
+ * Only public routes, and both `?addlink` and `?post` were kept here.
+ * Other routes will just display the linklist.
+ *
+ * @deprecated
+ */
+class LegacyController extends ShaarliVisitorController
+{
+    /** @var string[] Both `?post` and `?addlink` do not use `?do=` format. */
+    public const LEGACY_GET_ROUTES = [
+        'post',
+        'addlink',
+    ];
+
+    /**
+     * This method will call `$action` method, which will redirect to corresponding Slim route.
+     */
+    public function process(Request $request, Response $response, string $action): Response
+    {
+        if (!method_exists($this, $action)) {
+            throw new UnknowLegacyRouteException();
+        }
+
+        return $this->{$action}($request, $response);
+    }
+
+    /** Legacy route: ?post= */
+    public function post(Request $request, Response $response): Response
+    {
+        $parameters = count($request->getQueryParams()) > 0 ? '?' . http_build_query($request->getQueryParams()) : '';
+
+        if (!$this->container->loginManager->isLoggedIn()) {
+            return $this->redirect($response, '/login' . $parameters);
+        }
+
+        return $this->redirect($response, '/admin/shaare' . $parameters);
+    }
+
+    /** Legacy route: ?addlink= */
+    protected function addlink(Request $request, Response $response): Response
+    {
+        if (!$this->container->loginManager->isLoggedIn()) {
+            return $this->redirect($response, '/login');
+        }
+
+        return $this->redirect($response, '/admin/add-shaare');
+    }
+
+    /** Legacy route: ?do=login */
+    protected function login(Request $request, Response $response): Response
+    {
+        return $this->redirect($response, '/login');
+    }
+
+    /** Legacy route: ?do=logout */
+    protected function logout(Request $request, Response $response): Response
+    {
+        return $this->redirect($response, '/logout');
+    }
+
+    /** Legacy route: ?do=picwall */
+    protected function picwall(Request $request, Response $response): Response
+    {
+        return $this->redirect($response, '/picture-wall');
+    }
+
+    /** Legacy route: ?do=tagcloud */
+    protected function tagcloud(Request $request, Response $response): Response
+    {
+        return $this->redirect($response, '/tags/cloud');
+    }
+
+    /** Legacy route: ?do=taglist */
+    protected function taglist(Request $request, Response $response): Response
+    {
+        return $this->redirect($response, '/tags/list');
+    }
+
+    /** Legacy route: ?do=daily */
+    protected function daily(Request $request, Response $response): Response
+    {
+        $dayParam = !empty($request->getParam('day')) ? '?day=' . escape($request->getParam('day')) : '';
+
+        return $this->redirect($response, '/daily' . $dayParam);
+    }
+
+    /** Legacy route: ?do=rss */
+    protected function rss(Request $request, Response $response): Response
+    {
+        return $this->feed($request, $response, FeedBuilder::$FEED_RSS);
+    }
+
+    /** Legacy route: ?do=atom */
+    protected function atom(Request $request, Response $response): Response
+    {
+        return $this->feed($request, $response, FeedBuilder::$FEED_ATOM);
+    }
+
+    /** Legacy route: ?do=opensearch */
+    protected function opensearch(Request $request, Response $response): Response
+    {
+        return $this->redirect($response, '/open-search');
+    }
+
+    /** Legacy route: ?do=dailyrss */
+    protected function dailyrss(Request $request, Response $response): Response
+    {
+        return $this->redirect($response, '/daily-rss');
+    }
+
+    /** Legacy route: ?do=feed */
+    protected function feed(Request $request, Response $response, string $feedType): Response
+    {
+        $parameters = count($request->getQueryParams()) > 0 ? '?' . http_build_query($request->getQueryParams()) : '';
+
+        return $this->redirect($response, '/feed/' . $feedType . $parameters);
+    }
+}
similarity index 98%
rename from application/Router.php
rename to application/legacy/LegacyRouter.php
index d7187487e6ff3a736e797623577af7bc9998ebf3..cea99154cd5885ad495156fd8cfcf68c746f89a5 100644 (file)
@@ -1,12 +1,15 @@
 <?php
-namespace Shaarli;
+
+namespace Shaarli\Legacy;
 
 /**
  * Class Router
  *
  * (only displayable pages here)
+ *
+ * @deprecated
  */
-class Router
+class LegacyRouter
 {
     public static $AJAX_THUMB_UPDATE = 'ajax_thumb_update';
 
diff --git a/application/legacy/UnknowLegacyRouteException.php b/application/legacy/UnknowLegacyRouteException.php
new file mode 100644 (file)
index 0000000..ae1518a
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Legacy;
+
+class UnknowLegacyRouteException extends \Exception
+{
+}
index 2779eb90ddcea62c0637f551f7caee319207d3bf..85e1d59df9fe4866a3df19144b193debfe1ee480 100644 (file)
@@ -69,6 +69,15 @@ class PageBuilder
         $this->isLoggedIn = $isLoggedIn;
     }
 
+    /**
+     * Reset current state of template rendering.
+     * Mostly useful for error handling. We remove everything, and display the error template.
+     */
+    public function reset(): void
+    {
+        $this->tpl = false;
+    }
+
     /**
      * Initialize all default tpl tags.
      */
diff --git a/application/render/TemplatePage.php b/application/render/TemplatePage.php
new file mode 100644 (file)
index 0000000..8af8228
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Render;
+
+interface TemplatePage
+{
+    public const ERROR_404 = '404';
+    public const ADDLINK = 'addlink';
+    public const CHANGE_PASSWORD = 'changepassword';
+    public const CHANGE_TAG = 'changetag';
+    public const CONFIGURE = 'configure';
+    public const DAILY = 'daily';
+    public const DAILY_RSS = 'dailyrss';
+    public const EDIT_LINK = 'editlink';
+    public const ERROR = 'error';
+    public const EXPORT = 'export';
+    public const NETSCAPE_EXPORT_BOOKMARKS = 'export.bookmarks';
+    public const FEED_ATOM = 'feed.atom';
+    public const FEED_RSS = 'feed.rss';
+    public const IMPORT = 'import';
+    public const INSTALL = 'install';
+    public const LINKLIST = 'linklist';
+    public const LOGIN = 'loginform';
+    public const OPEN_SEARCH = 'opensearch';
+    public const PICTURE_WALL = 'picwall';
+    public const PLUGINS_ADMIN = 'pluginsadmin';
+    public const TAG_CLOUD = 'tag.cloud';
+    public const TAG_LIST = 'tag.list';
+    public const THUMBNAILS = 'thumbnails';
+    public const TOOLS = 'tools';
+}
index 4bbcb9f270664a8e11266716548f502368765aec..f73a7452f65ea97966a0d3e908066e8be79b02cd 100644 (file)
@@ -21,7 +21,7 @@ class Updater
     /**
      * @var BookmarkServiceInterface instance.
      */
-    protected $linkServices;
+    protected $bookmarkService;
 
     /**
      * @var ConfigManager $conf Configuration Manager instance.
@@ -49,7 +49,7 @@ class Updater
     public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn)
     {
         $this->doneUpdates = $doneUpdates;
-        $this->linkServices = $linkDB;
+        $this->bookmarkService = $linkDB;
         $this->conf = $conf;
         $this->isLoggedIn = $isLoggedIn;
 
@@ -68,7 +68,7 @@ class Updater
      */
     public function update()
     {
-        $updatesRan = array();
+        $updatesRan = [];
 
         // If the user isn't logged in, exit without updating.
         if ($this->isLoggedIn !== true) {
@@ -112,6 +112,16 @@ class Updater
         return $this->doneUpdates;
     }
 
+    public function readUpdates(string $updatesFilepath): array
+    {
+        return UpdaterUtils::read_updates_file($updatesFilepath);
+    }
+
+    public function writeUpdates(string $updatesFilepath, array $updates): void
+    {
+        UpdaterUtils::write_updates_file($updatesFilepath, $updates);
+    }
+
     /**
      * With the Slim routing system, default header link should be `./` instead of `?`.
      * Otherwise you can not go back to the home page. Example: `/picture-wall` -> `/picture-wall?` instead of `/`.
@@ -127,4 +137,31 @@ class Updater
 
         return true;
     }
+
+    /**
+     * With the Slim routing system, note bookmarks URL formatted `?abcdef`
+     * should be replaced with `/shaare/abcdef`
+     */
+    public function updateMethodMigrateExistingNotesUrl(): bool
+    {
+        $updated = false;
+
+        foreach ($this->bookmarkService->search() as $bookmark) {
+            if ($bookmark->isNote()
+                && startsWith($bookmark->getUrl(), '?')
+                && 1 === preg_match('/^\?([a-zA-Z0-9-_@]{6})($|&|#)/', $bookmark->getUrl(), $match)
+            ) {
+                $updated = true;
+                $bookmark = $bookmark->setUrl('/shaare/' . $match[1]);
+
+                $this->bookmarkService->set($bookmark, false);
+            }
+        }
+
+        if ($updated) {
+            $this->bookmarkService->save();
+        }
+
+        return true;
+    }
 }
index d5b16e2d0d2a200129e709b80932ee3a3ceb7b4e..f264e8735d79042506678327f1ae4e503b2a5738 100644 (file)
@@ -131,7 +131,7 @@ If it's still not working, please [open an issue](https://github.com/shaarli/Sha
 | ------------- |:-------------:|
 | [render_header](#render_header) | Allow plugin to add content in page headers. |
 | [render_includes](#render_includes) | Allow plugin to include their own CSS files. |
-| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. | 
+| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. |
 | [render_linklist](#render_linklist) | It allows to add content at the begining and end of the page, after every link displayed and to alter link data. |
 | [render_editlink](#render_editlink) |  Allow to add fields in the form, or display elements. |
 | [render_tools](#render_tools) |  Allow to add content at the end of the page. |
@@ -515,7 +515,7 @@ Otherwise, you can use your own JS as long as this field is send by the form:
 
 ### Placeholder system
 
-In order to make plugins work with every custom themes, you need to add variable placeholder in your templates. 
+In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
 
 It's a RainTPL loop like this:
 
@@ -537,7 +537,7 @@ At the end of the menu:
 
 At the end of file, before clearing floating blocks:
 
-    {if="!empty($plugin_errors) && isLoggedIn()"}
+    {if="!empty($plugin_errors) && $is_logged_in"}
         <ul class="errors">
             {loop="plugin_errors"}
                 <li>{$value}</li>
index a07de74d01508e6003d43b4cfd3de97fca8947f9..2737c22cdfea7a2f8a4bc802daae77c4a2e0f171 100644 (file)
--- a/index.php
+++ b/index.php
@@ -61,30 +61,15 @@ require_once 'application/TimeZone.php';
 require_once 'application/Utils.php';
 
 use Shaarli\ApplicationUtils;
-use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
-use Shaarli\Bookmark\BookmarkFilter;
-use Shaarli\Bookmark\BookmarkServiceInterface;
-use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ContainerBuilder;
-use Shaarli\Feed\CachedPage;
-use Shaarli\Feed\FeedBuilder;
-use Shaarli\Formatter\BookmarkMarkdownFormatter;
-use Shaarli\Formatter\FormatterFactory;
 use Shaarli\History;
 use Shaarli\Languages;
-use Shaarli\Netscape\NetscapeBookmarkUtils;
 use Shaarli\Plugin\PluginManager;
 use Shaarli\Render\PageBuilder;
-use Shaarli\Render\PageCacheManager;
-use Shaarli\Render\ThemeUtils;
-use Shaarli\Router;
 use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
-use Shaarli\Thumbnailer;
-use Shaarli\Updater\Updater;
-use Shaarli\Updater\UpdaterUtils;
 use Slim\App;
 
 // Ensure the PHP version is supported
@@ -196,20 +181,6 @@ if (! is_file($conf->getConfigFileExt())) {
 
 $loginManager->checkLoginState($_COOKIE, $clientIpId);
 
-/**
- * Adapter function to ensure compatibility with third-party templates
- *
- * @see https://github.com/shaarli/Shaarli/pull/1086
- *
- * @return bool true when the user is logged in, false otherwise
- */
-function isLoggedIn()
-{
-    global $loginManager;
-    return $loginManager->isLoggedIn();
-}
-
-
 // ------------------------------------------------------------------------------------------
 // Process login form: Check if login/password is correct.
 if (isset($_POST['login'])) {
@@ -300,473 +271,6 @@ if (!isset($_SESSION['tokens'])) {
     $_SESSION['tokens']=array();  // Token are attached to the session.
 }
 
-/**
- * Renders the linklist
- *
- * @param pageBuilder              $PAGE          pageBuilder instance.
- * @param BookmarkServiceInterface $linkDb        instance.
- * @param ConfigManager            $conf          Configuration Manager instance.
- * @param PluginManager            $pluginManager Plugin Manager instance.
- */
-function showLinkList($PAGE, $linkDb, $conf, $pluginManager, $loginManager)
-{
-    buildLinkList($PAGE, $linkDb, $conf, $pluginManager, $loginManager);
-    $PAGE->renderPage('linklist');
-}
-
-/**
- * Render HTML page (according to URL parameters and user rights)
- *
- * @param ConfigManager            $conf           Configuration Manager instance.
- * @param PluginManager            $pluginManager  Plugin Manager instance,
- * @param BookmarkServiceInterface $bookmarkService
- * @param History                  $history        instance
- * @param SessionManager           $sessionManager SessionManager instance
- * @param LoginManager             $loginManager   LoginManager instance
- */
-function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionManager, $loginManager)
-{
-    $pageCacheManager = new PageCacheManager($conf->get('resource.page_cache'), $loginManager->isLoggedIn());
-    $updater = new Updater(
-        UpdaterUtils::read_updates_file($conf->get('resource.updates')),
-        $bookmarkService,
-        $conf,
-        $loginManager->isLoggedIn()
-    );
-    try {
-        $newUpdates = $updater->update();
-        if (! empty($newUpdates)) {
-            UpdaterUtils::write_updates_file(
-                $conf->get('resource.updates'),
-                $updater->getDoneUpdates()
-            );
-
-            $pageCacheManager->invalidateCaches();
-        }
-    } catch (Exception $e) {
-        die($e->getMessage());
-    }
-
-    $PAGE = new PageBuilder($conf, $_SESSION, $bookmarkService, $sessionManager->generateToken(), $loginManager->isLoggedIn());
-    $PAGE->assign('linkcount', $bookmarkService->count(BookmarkFilter::$ALL));
-    $PAGE->assign('privateLinkcount', $bookmarkService->count(BookmarkFilter::$PRIVATE));
-    $PAGE->assign('plugin_errors', $pluginManager->getErrors());
-
-    // Determine which page will be rendered.
-    $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : '';
-    $targetPage = Router::findPage($query, $_GET, $loginManager->isLoggedIn());
-
-    if (// if the user isn't logged in
-        !$loginManager->isLoggedIn() &&
-        // and Shaarli doesn't have public content...
-        $conf->get('privacy.hide_public_links') &&
-        // and is configured to enforce the login
-        $conf->get('privacy.force_login') &&
-        // and the current page isn't already the login page
-        $targetPage !== Router::$PAGE_LOGIN &&
-        // and the user is not requesting a feed (which would lead to a different content-type as expected)
-        $targetPage !== Router::$PAGE_FEED_ATOM &&
-        $targetPage !== Router::$PAGE_FEED_RSS
-    ) {
-        // force current page to be the login page
-        $targetPage = Router::$PAGE_LOGIN;
-    }
-
-    // Call plugin hooks for header, footer and includes, specifying which page will be rendered.
-    // Then assign generated data to RainTPL.
-    $common_hooks = array(
-        'includes',
-        'header',
-        'footer',
-    );
-
-    foreach ($common_hooks as $name) {
-        $plugin_data = array();
-        $pluginManager->executeHooks(
-            'render_' . $name,
-            $plugin_data,
-            array(
-                'target' => $targetPage,
-                'loggedin' => $loginManager->isLoggedIn()
-            )
-        );
-        $PAGE->assign('plugins_' . $name, $plugin_data);
-    }
-
-    // -------- Display login form.
-    if ($targetPage == Router::$PAGE_LOGIN) {
-        header('Location: ./login');
-        exit;
-    }
-    // -------- User wants to logout.
-    if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) {
-        header('Location: ./logout');
-        exit;
-    }
-
-    // -------- Picture wall
-    if ($targetPage == Router::$PAGE_PICWALL) {
-        header('Location: ./picture-wall');
-        exit;
-    }
-
-    // -------- Tag cloud
-    if ($targetPage == Router::$PAGE_TAGCLOUD) {
-        header('Location: ./tags/cloud');
-        exit;
-    }
-
-    // -------- Tag list
-    if ($targetPage == Router::$PAGE_TAGLIST) {
-        header('Location: ./tags/list');
-        exit;
-    }
-
-    // Daily page.
-    if ($targetPage == Router::$PAGE_DAILY) {
-        $dayParam = !empty($_GET['day']) ? '?day=' . escape($_GET['day']) : '';
-        header('Location: ./daily'. $dayParam);
-        exit;
-    }
-
-    // ATOM and RSS feed.
-    if ($targetPage == Router::$PAGE_FEED_ATOM || $targetPage == Router::$PAGE_FEED_RSS) {
-        $feedType = $targetPage == Router::$PAGE_FEED_RSS ? FeedBuilder::$FEED_RSS : FeedBuilder::$FEED_ATOM;
-
-        header('Location: ./feed/'. $feedType .'?'. http_build_query($_GET));
-        exit;
-    }
-
-    // Display opensearch plugin (XML)
-    if ($targetPage == Router::$PAGE_OPENSEARCH) {
-        header('Location: ./open-search');
-        exit;
-    }
-
-    // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...)
-    if (isset($_GET['addtag'])) {
-        header('Location: ./add-tag/'. $_GET['addtag']);
-        exit;
-    }
-
-    // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...)
-    if (isset($_GET['removetag'])) {
-        header('Location: ./remove-tag/'. $_GET['removetag']);
-        exit;
-    }
-
-    // -------- User wants to change the number of bookmarks per page (linksperpage=...)
-    if (isset($_GET['linksperpage'])) {
-        header('Location: ./links-per-page?nb='. $_GET['linksperpage']);
-        exit;
-    }
-
-    // -------- User wants to see only private bookmarks (toggle)
-    if (isset($_GET['visibility'])) {
-        header('Location: ./visibility/'. $_GET['visibility']);
-        exit;
-    }
-
-    // -------- User wants to see only untagged bookmarks (toggle)
-    if (isset($_GET['untaggedonly'])) {
-        header('Location: ./untagged-only');
-        exit;
-    }
-
-    // -------- Handle other actions allowed for non-logged in users:
-    if (!$loginManager->isLoggedIn()) {
-        // User tries to post new link but is not logged in:
-        // Show login screen, then redirect to ?post=...
-        if (isset($_GET['post'])) {
-            header( // Redirect to login page, then back to post link.
-                'Location: ./login?post='.urlencode($_GET['post']).
-                (!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').
-                (!empty($_GET['description'])?'&description='.urlencode($_GET['description']):'').
-                (!empty($_GET['tags'])?'&tags='.urlencode($_GET['tags']):'').
-                (!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')
-            );
-            exit;
-        }
-
-        showLinkList($PAGE, $bookmarkService, $conf, $pluginManager, $loginManager);
-        if (isset($_GET['edit_link'])) {
-            header('Location: ./login?edit_link='. escape($_GET['edit_link']));
-            exit;
-        }
-
-        exit; // Never remove this one! All operations below are reserved for logged in user.
-    }
-
-    // -------- All other functions are reserved for the registered user:
-
-    // TODO: Remove legacy admin route redirections. We'll only keep public URL.
-
-    // -------- Display the Tools menu if requested (import/export/bookmarklet...)
-    if ($targetPage == Router::$PAGE_TOOLS) {
-        header('Location: ./admin/tools');
-        exit;
-    }
-
-    // -------- User wants to change his/her password.
-    if ($targetPage == Router::$PAGE_CHANGEPASSWORD) {
-        header('Location: ./admin/password');
-        exit;
-    }
-
-    // -------- User wants to change configuration
-    if ($targetPage == Router::$PAGE_CONFIGURE) {
-        header('Location: ./admin/configure');
-        exit;
-    }
-
-    // -------- User wants to rename a tag or delete it
-    if ($targetPage == Router::$PAGE_CHANGETAG) {
-        header('Location: ./admin/tags');
-        exit;
-    }
-
-    // -------- User wants to add a link without using the bookmarklet: Show form.
-    if ($targetPage == Router::$PAGE_ADDLINK) {
-        header('Location: ./admin/shaare');
-        exit;
-    }
-
-    // -------- User clicked the "Save" button when editing a link: Save link to database.
-    if (isset($_POST['save_edit'])) {
-        // This route is no longer supported in legacy mode
-        header('Location: ./');
-        exit;
-    }
-
-    // -------- User clicked the "Delete" button when editing a link: Delete link from database.
-    if ($targetPage == Router::$PAGE_DELETELINK) {
-        $ids = $_GET['lf_linkdate'] ?? '';
-        $token = $_GET['token'] ?? '';
-
-        header('Location: ./admin/shaare/delete?id=' . $ids . '&token=' . $token);
-        exit;
-    }
-
-    // -------- User clicked either "Set public" or "Set private" bulk operation
-    if ($targetPage == Router::$PAGE_CHANGE_VISIBILITY) {
-        header('Location: ./admin/shaare/visibility?id=' . $_GET['token']);
-        exit;
-    }
-
-    // -------- User clicked the "EDIT" button on a link: Display link edit form.
-    if (isset($_GET['edit_link'])) {
-        $id = (int) escape($_GET['edit_link']);
-        header('Location: ./admin/shaare/' . $id);
-        exit;
-    }
-
-    // -------- User want to post a new link: Display link edit form.
-    if (isset($_GET['post'])) {
-        header('Location: ./admin/shaare?' . http_build_query($_GET));
-        exit;
-    }
-
-    if ($targetPage == Router::$PAGE_PINLINK) {
-        // This route is no longer supported in legacy mode
-        header('Location: ./');
-        exit;
-    }
-
-    if ($targetPage == Router::$PAGE_EXPORT) {
-        header('Location: ./admin/export');
-        exit;
-    }
-
-    if ($targetPage == Router::$PAGE_IMPORT) {
-        header('Location: ./admin/import');
-        exit;
-    }
-
-    // Plugin administration page
-    if ($targetPage == Router::$PAGE_PLUGINSADMIN) {
-        header('Location: ./admin/plugins');
-        exit;
-    }
-
-    // Plugin administration form action
-    if ($targetPage == Router::$PAGE_SAVE_PLUGINSADMIN) {
-        // This route is no longer supported in legacy mode
-        header('Location: ./admin/plugins');
-        exit;
-    }
-
-    // Get a fresh token
-    if ($targetPage == Router::$GET_TOKEN) {
-        header('Location: ./admin/token');
-        exit;
-    }
-
-    // -------- Thumbnails Update
-    if ($targetPage == Router::$PAGE_THUMBS_UPDATE) {
-        header('Location: ./admin/thumbnails');
-        exit;
-    }
-
-    // -------- Single Thumbnail Update
-    if ($targetPage == Router::$AJAX_THUMB_UPDATE) {
-        // This route is no longer supported in legacy mode
-        http_response_code(404);
-        exit;
-    }
-
-    // -------- Otherwise, simply display search form and bookmarks:
-    showLinkList($PAGE, $bookmarkService, $conf, $pluginManager, $loginManager);
-    exit;
-}
-
-/**
- * Template for the list of bookmarks (<div id="linklist">)
- * This function fills all the necessary fields in the $PAGE for the template 'linklist.html'
- *
- * @param pageBuilder              $PAGE          pageBuilder instance.
- * @param BookmarkServiceInterface $linkDb        LinkDB instance.
- * @param ConfigManager            $conf          Configuration Manager instance.
- * @param PluginManager            $pluginManager Plugin Manager instance.
- * @param LoginManager             $loginManager  LoginManager instance
- */
-function buildLinkList($PAGE, $linkDb, $conf, $pluginManager, $loginManager)
-{
-    $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
-    $formatter = $factory->getFormatter();
-
-    // Used in templates
-    if (isset($_GET['searchtags'])) {
-        if (! empty($_GET['searchtags'])) {
-            $searchtags = escape(normalize_spaces($_GET['searchtags']));
-        } else {
-            $searchtags = false;
-        }
-    } else {
-        $searchtags = '';
-    }
-    $searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : '';
-
-    // Smallhash filter
-    if (! empty($_SERVER['QUERY_STRING'])
-        && preg_match('/^[a-zA-Z0-9-_@]{6}($|&|#)/', $_SERVER['QUERY_STRING'])) {
-        try {
-            $linksToDisplay = $linkDb->findByHash($_SERVER['QUERY_STRING']);
-        } catch (BookmarkNotFoundException $e) {
-            $PAGE->render404($e->getMessage());
-            exit;
-        }
-    } else {
-        // Filter bookmarks according search parameters.
-        $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : null;
-        $request = [
-            'searchtags' => $searchtags,
-            'searchterm' => $searchterm,
-        ];
-        $linksToDisplay = $linkDb->search($request, $visibility, false, !empty($_SESSION['untaggedonly']));
-    }
-
-    // ---- Handle paging.
-    $keys = array();
-    foreach ($linksToDisplay as $key => $value) {
-        $keys[] = $key;
-    }
-
-    // Select articles according to paging.
-    $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']);
-    $pagecount = $pagecount == 0 ? 1 : $pagecount;
-    $page= empty($_GET['page']) ? 1 : intval($_GET['page']);
-    $page = $page < 1 ? 1 : $page;
-    $page = $page > $pagecount ? $pagecount : $page;
-    // Start index.
-    $i = ($page-1) * $_SESSION['LINKS_PER_PAGE'];
-    $end = $i + $_SESSION['LINKS_PER_PAGE'];
-
-    $thumbnailsEnabled = $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE;
-    if ($thumbnailsEnabled) {
-        $thumbnailer = new Thumbnailer($conf);
-    }
-
-    $linkDisp = array();
-    while ($i<$end && $i<count($keys)) {
-        $link = $formatter->format($linksToDisplay[$keys[$i]]);
-
-        // Logged in, thumbnails enabled, not a note,
-        // and (never retrieved yet or no valid cache file)
-        if ($loginManager->isLoggedIn()
-            && $thumbnailsEnabled
-            && !$linksToDisplay[$keys[$i]]->isNote()
-            && $linksToDisplay[$keys[$i]]->getThumbnail() !== false
-            && ! is_file($linksToDisplay[$keys[$i]]->getThumbnail())
-        ) {
-            $linksToDisplay[$keys[$i]]->setThumbnail($thumbnailer->get($link['url']));
-            $linkDb->set($linksToDisplay[$keys[$i]], false);
-            $updateDB = true;
-            $link['thumbnail'] = $linksToDisplay[$keys[$i]]->getThumbnail();
-        }
-
-        // Check for both signs of a note: starting with ? and 7 chars long.
-//        if ($link['url'][0] === '?' && strlen($link['url']) === 7) {
-//            $link['url'] = index_url($_SERVER) . $link['url'];
-//        }
-
-        $linkDisp[$keys[$i]] = $link;
-        $i++;
-    }
-
-    // If we retrieved new thumbnails, we update the database.
-    if (!empty($updateDB)) {
-        $linkDb->save();
-    }
-
-    // Compute paging navigation
-    $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags);
-    $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
-    $previous_page_url = '';
-    if ($i != count($keys)) {
-        $previous_page_url = '?page=' . ($page+1) . $searchtermUrl . $searchtagsUrl;
-    }
-    $next_page_url='';
-    if ($page>1) {
-        $next_page_url = '?page=' . ($page-1) . $searchtermUrl . $searchtagsUrl;
-    }
-
-    // Fill all template fields.
-    $data = array(
-        'previous_page_url' => $previous_page_url,
-        'next_page_url' => $next_page_url,
-        'page_current' => $page,
-        'page_max' => $pagecount,
-        'result_count' => count($linksToDisplay),
-        'search_term' => $searchterm,
-        'search_tags' => $searchtags,
-        'visibility' => ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '',
-        'links' => $linkDisp,
-    );
-
-    // If there is only a single link, we change on-the-fly the title of the page.
-    if (count($linksToDisplay) == 1) {
-        $data['pagetitle'] = $linksToDisplay[$keys[0]]->getTitle() .' - '. $conf->get('general.title');
-    } elseif (! empty($searchterm) || ! empty($searchtags)) {
-        $data['pagetitle'] = t('Search: ');
-        $data['pagetitle'] .= ! empty($searchterm) ? $searchterm .' ' : '';
-        $bracketWrap = function ($tag) {
-            return '['. $tag .']';
-        };
-        $data['pagetitle'] .= ! empty($searchtags)
-            ? implode(' ', array_map($bracketWrap, preg_split('/\s+/', $searchtags))).' '
-            : '';
-        $data['pagetitle'] .= '- '. $conf->get('general.title');
-    }
-
-    $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => $loginManager->isLoggedIn()));
-
-    foreach ($data as $key => $value) {
-        $PAGE->assign($key, $value);
-    }
-
-    return;
-}
-
 /**
  * Installation
  * This function should NEVER be called if the file data/config.php exists.
@@ -882,19 +386,6 @@ if (!isset($_SESSION['LINKS_PER_PAGE'])) {
     $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20);
 }
 
-try {
-    $history = new History($conf->get('resource.history'));
-} catch (Exception $e) {
-    die($e->getMessage());
-}
-
-$linkDb = new BookmarkFileService($conf, $history, $loginManager->isLoggedIn());
-
-if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) {
-    header('Location: ./daily-rss');
-    exit;
-}
-
 $containerBuilder = new ContainerBuilder($conf, $sessionManager, $loginManager);
 $container = $containerBuilder->build();
 $app = new App($container);
@@ -918,13 +409,15 @@ $app->group('/api/v1', function () {
 
 $app->group('', function () {
     /* -- PUBLIC --*/
-    $this->get('/login', '\Shaarli\Front\Controller\Visitor\LoginController:index');
+    $this->get('/', '\Shaarli\Front\Controller\Visitor\BookmarkListController:index');
+    $this->get('/shaare/{hash}', '\Shaarli\Front\Controller\Visitor\BookmarkListController:permalink');
+    $this->get('/login', '\Shaarli\Front\Controller\Visitor\LoginController:index')->setName('login');
     $this->get('/picture-wall', '\Shaarli\Front\Controller\Visitor\PictureWallController:index');
     $this->get('/tags/cloud', '\Shaarli\Front\Controller\Visitor\TagCloudController:cloud');
     $this->get('/tags/list', '\Shaarli\Front\Controller\Visitor\TagCloudController:list');
     $this->get('/daily', '\Shaarli\Front\Controller\Visitor\DailyController:index');
-    $this->get('/daily-rss', '\Shaarli\Front\Controller\Visitor\DailyController:rss');
-    $this->get('/feed/atom', '\Shaarli\Front\Controller\Visitor\FeedController:atom');
+    $this->get('/daily-rss', '\Shaarli\Front\Controller\Visitor\DailyController:rss')->setName('rss');
+    $this->get('/feed/atom', '\Shaarli\Front\Controller\Visitor\FeedController:atom')->setName('atom');
     $this->get('/feed/rss', '\Shaarli\Front\Controller\Visitor\FeedController:rss');
     $this->get('/open-search', '\Shaarli\Front\Controller\Visitor\OpenSearchController:index');
 
@@ -967,19 +460,4 @@ $app->group('', function () {
 
 $response = $app->run(true);
 
-// Hack to make Slim and Shaarli router work together:
-// If a Slim route isn't found and NOT API call, we call renderPage().
-if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], '/api/v1') === false) {
-    // We use UTF-8 for proper international characters handling.
-    header('Content-Type: text/html; charset=utf-8');
-    renderPage($conf, $pluginManager, $linkDb, $history, $sessionManager, $loginManager);
-} else {
-    $response = $response
-        ->withHeader('Access-Control-Allow-Origin', '*')
-        ->withHeader(
-            'Access-Control-Allow-Headers',
-            'X-Requested-With, Content-Type, Accept, Origin, Authorization'
-        )
-        ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
-    $app->respond($response);
-}
+$app->respond($response);
index 8bf4ed46d6cd5afded8fd8d551361b0e93bcef76..c3e7abaf5388bf4fe557b03a0412a67e3778c782 100644 (file)
@@ -5,7 +5,7 @@
  * Adds the addlink input on the linklist page.
  */
 
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 /**
  * When linklist is displayed, add play videos to header's toolbar.
@@ -16,7 +16,7 @@ use Shaarli\Router;
  */
 function hook_addlink_toolbar_render_header($data)
 {
-    if ($data['_PAGE_'] == Router::$PAGE_LINKLIST && $data['_LOGGEDIN_'] === true) {
+    if ($data['_PAGE_'] == TemplatePage::LINKLIST && $data['_LOGGEDIN_'] === true) {
         $form = array(
             'attr' => array(
                 'method' => 'GET',
index 8ae1b47969e15dafa1b142c68e98aaf19d8813b4..dd73d6a2129acd2be76a612a8b3c379f7e5bcd3f 100644 (file)
@@ -16,7 +16,7 @@
 
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 /**
  * In the footer hook, there is a working example of a translation extension for Shaarli.
@@ -74,7 +74,7 @@ function demo_plugin_init($conf)
 function hook_demo_plugin_render_header($data)
 {
     // Only execute when linklist is rendered.
-    if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
+    if ($data['_PAGE_'] == TemplatePage::LINKLIST) {
         // If loggedin
         if ($data['_LOGGEDIN_'] === true) {
             /*
@@ -441,9 +441,9 @@ function hook_demo_plugin_delete_link($data)
 function hook_demo_plugin_render_feed($data)
 {
     foreach ($data['links'] as &$link) {
-        if ($data['_PAGE_'] == Router::$PAGE_FEED_ATOM) {
+        if ($data['_PAGE_'] == TemplatePage::FEED_ATOM) {
             $link['description'] .= ' - ATOM Feed' ;
-        } elseif ($data['_PAGE_'] == Router::$PAGE_FEED_RSS) {
+        } elseif ($data['_PAGE_'] == TemplatePage::FEED_RSS) {
             $link['description'] .= ' - RSS Feed';
         }
     }
index dab75dd55c5c0b06789da06e688664ef97256b54..16edd9a61e44236b53832ce150a3e1b938c5a4fe 100644 (file)
@@ -6,7 +6,7 @@
 
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 /**
  * Display an error everywhere if the plugin is enabled without configuration.
@@ -76,7 +76,7 @@ function hook_isso_render_linklist($data, $conf)
  */
 function hook_isso_render_includes($data)
 {
-    if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
+    if ($data['_PAGE_'] == TemplatePage::LINKLIST) {
         $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/isso/isso.css';
     }
 
index 0341ed593abd19cb0afb5db4a092e4bb34944dd6..91a9c1e554c58437c5862adfd605019865096be7 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 /**
  * When linklist is displayed, add play videos to header's toolbar.
@@ -18,7 +18,7 @@ use Shaarli\Router;
  */
 function hook_playvideos_render_header($data)
 {
-    if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
+    if ($data['_PAGE_'] == TemplatePage::LINKLIST) {
         $playvideo = array(
             'attr' => array(
                 'href' => '#',
@@ -42,7 +42,7 @@ function hook_playvideos_render_header($data)
  */
 function hook_playvideos_render_footer($data)
 {
-    if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
+    if ($data['_PAGE_'] == TemplatePage::LINKLIST) {
         $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/jquery-1.11.2.min.js';
         $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/youtube_playlist.js';
     }
index 170f34949eb0e7dfadcf099f5014568888b2a7ba..8fe6799ce6d00933445a9b7b7f1652dc13387af8 100644 (file)
@@ -13,7 +13,7 @@ use pubsubhubbub\publisher\Publisher;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Feed\FeedBuilder;
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 /**
  * Plugin init function - set the hub to the default appspot one.
@@ -41,7 +41,7 @@ function pubsubhubbub_init($conf)
  */
 function hook_pubsubhubbub_render_feed($data, $conf)
 {
-    $feedType = $data['_PAGE_'] == Router::$PAGE_FEED_RSS ? FeedBuilder::$FEED_RSS : FeedBuilder::$FEED_ATOM;
+    $feedType = $data['_PAGE_'] == TemplatePage::FEED_RSS ? FeedBuilder::$FEED_RSS : FeedBuilder::$FEED_ATOM;
     $template = file_get_contents(PluginManager::$PLUGINS_PATH . '/pubsubhubbub/hub.'. $feedType .'.xml');
     $data['feed_plugins_header'][] = sprintf($template, $conf->get('plugins.PUBSUBHUB_URL'));
 
index c1d237d5d664532a6912e5ee5ba34c80ce59ddea..2ec0cb6576d859c3723f96d39cd8f9165c8cfd5e 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 /**
  * Add qrcode icon to link_plugin when rendering linklist.
@@ -40,7 +40,7 @@ function hook_qrcode_render_linklist($data)
  */
 function hook_qrcode_render_footer($data)
 {
-    if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
+    if ($data['_PAGE_'] == TemplatePage::LINKLIST) {
         $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/qrcode/shaarli-qrcode.js';
     }
 
@@ -56,7 +56,7 @@ function hook_qrcode_render_footer($data)
  */
 function hook_qrcode_render_includes($data)
 {
-    if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
+    if ($data['_PAGE_'] == TemplatePage::LINKLIST) {
         $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.css';
     }
 
index 5adc26aad445efe897615679aab55d461a2dc9ee..b19c82501897dd3af46ae17e4a6c674aabc0cc9c 100644 (file)
@@ -892,35 +892,35 @@ class BookmarkFileServiceTest extends TestCase
     public function testFilterHashValid()
     {
         $request = smallHash('20150310_114651');
-        $this->assertEquals(
-            1,
-            count($this->publicLinkDB->findByHash($request))
+        $this->assertSame(
+            $request,
+            $this->publicLinkDB->findByHash($request)->getShortUrl()
         );
         $request = smallHash('20150310_114633' . 8);
-        $this->assertEquals(
-            1,
-            count($this->publicLinkDB->findByHash($request))
+        $this->assertSame(
+            $request,
+            $this->publicLinkDB->findByHash($request)->getShortUrl()
         );
     }
 
     /**
      * Test filterHash() with an invalid smallhash.
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterHashInValid1()
     {
+        $this->expectException(BookmarkNotFoundException::class);
+
         $request = 'blabla';
         $this->publicLinkDB->findByHash($request);
     }
 
     /**
      * Test filterHash() with an empty smallhash.
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterHashInValid()
     {
+        $this->expectException(BookmarkNotFoundException::class);
+
         $this->publicLinkDB->findByHash('');
     }
 
index 57be10026a90795308776e8e37e13b03795c768b..81ea134409ffdd8e9f03d4dff90da8c4f1bebde6 100644 (file)
@@ -8,7 +8,11 @@ use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ShaarliContainer;
 use Shaarli\Front\Exception\LoginBannedException;
+use Shaarli\Front\Exception\UnauthorizedException;
 use Shaarli\Render\PageBuilder;
+use Shaarli\Render\PageCacheManager;
+use Shaarli\Security\LoginManager;
+use Shaarli\Updater\Updater;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\Uri;
@@ -24,9 +28,16 @@ class ShaarliMiddlewareTest extends TestCase
     public function setUp(): void
     {
         $this->container = $this->createMock(ShaarliContainer::class);
+
+        $this->container->conf = $this->createMock(ConfigManager::class);
+        $this->container->loginManager = $this->createMock(LoginManager::class);
+
         $this->middleware = new ShaarliMiddleware($this->container);
     }
 
+    /**
+     * Test middleware execution with valid controller call
+     */
     public function testMiddlewareExecution(): void
     {
         $request = $this->createMock(Request::class);
@@ -49,7 +60,10 @@ class ShaarliMiddlewareTest extends TestCase
         static::assertSame(418, $result->getStatusCode());
     }
 
-    public function testMiddlewareExecutionWithException(): void
+    /**
+     * Test middleware execution with controller throwing a known front exception
+     */
+    public function testMiddlewareExecutionWithFrontException(): void
     {
         $request = $this->createMock(Request::class);
         $request->method('getUri')->willReturnCallback(function (): Uri {
@@ -58,7 +72,7 @@ class ShaarliMiddlewareTest extends TestCase
 
             return $uri;
         });
-        
+
         $response = new Response();
         $controller = function (): void {
             $exception = new LoginBannedException();
@@ -72,9 +86,6 @@ class ShaarliMiddlewareTest extends TestCase
         });
         $this->container->pageBuilder = $pageBuilder;
 
-        $conf = $this->createMock(ConfigManager::class);
-        $this->container->conf = $conf;
-
         /** @var Response $result */
         $result = $this->middleware->__invoke($request, $response, $controller);
 
@@ -82,4 +93,113 @@ class ShaarliMiddlewareTest extends TestCase
         static::assertSame(401, $result->getStatusCode());
         static::assertContains('error', (string) $result->getBody());
     }
+
+    /**
+     * Test middleware execution with controller throwing a not authorized exception
+     */
+    public function testMiddlewareExecutionWithUnauthorizedException(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+        $controller = function (): void {
+            throw new UnauthorizedException();
+        };
+
+        /** @var Response $result */
+        $result = $this->middleware->__invoke($request, $response, $controller);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Test middleware execution with controller throwing a not authorized exception
+     */
+    public function testMiddlewareExecutionWithServerExceptionWith(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+        $controller = function (): void {
+            throw new \Exception();
+        };
+
+        $parameters = [];
+        $this->container->pageBuilder = $this->createMock(PageBuilder::class);
+        $this->container->pageBuilder->method('render')->willReturnCallback(function (string $message): string {
+            return $message;
+        });
+        $this->container->pageBuilder
+            ->method('assign')
+            ->willReturnCallback(function (string $key, string $value) use (&$parameters): void {
+                $parameters[$key] = $value;
+            })
+        ;
+
+        /** @var Response $result */
+        $result = $this->middleware->__invoke($request, $response, $controller);
+
+        static::assertSame(500, $result->getStatusCode());
+        static::assertContains('error', (string) $result->getBody());
+        static::assertSame('An unexpected error occurred.', $parameters['message']);
+    }
+
+    public function testMiddlewareExecutionWithUpdates(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+        $controller = function (Request $request, Response $response): Response {
+            return $response->withStatus(418); // I'm a tea pot
+        };
+
+        $this->container->loginManager = $this->createMock(LoginManager::class);
+        $this->container->loginManager->method('isLoggedIn')->willReturn(true);
+
+        $this->container->conf = $this->createMock(ConfigManager::class);
+        $this->container->conf->method('get')->willReturnCallback(function (string $key): string {
+            return $key;
+        });
+
+        $this->container->pageCacheManager = $this->createMock(PageCacheManager::class);
+        $this->container->pageCacheManager->expects(static::once())->method('invalidateCaches');
+
+        $this->container->updater = $this->createMock(Updater::class);
+        $this->container->updater
+            ->expects(static::once())
+            ->method('update')
+            ->willReturn(['update123'])
+        ;
+        $this->container->updater->method('getDoneUpdates')->willReturn($updates = ['update123', 'other']);
+        $this->container->updater
+            ->expects(static::once())
+            ->method('writeUpdates')
+            ->with('resource.updates', $updates)
+        ;
+
+        /** @var Response $result */
+        $result = $this->middleware->__invoke($request, $response, $controller);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(418, $result->getStatusCode());
+    }
 }
diff --git a/tests/front/controller/visitor/BookmarkListControllerTest.php b/tests/front/controller/visitor/BookmarkListControllerTest.php
new file mode 100644 (file)
index 0000000..5daaa2c
--- /dev/null
@@ -0,0 +1,448 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller\Visitor;
+
+use PHPUnit\Framework\TestCase;
+use Shaarli\Bookmark\Bookmark;
+use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
+use Shaarli\Config\ConfigManager;
+use Shaarli\Security\LoginManager;
+use Shaarli\Thumbnailer;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+class BookmarkListControllerTest extends TestCase
+{
+    use FrontControllerMockHelper;
+
+    /** @var BookmarkListController */
+    protected $controller;
+
+    public function setUp(): void
+    {
+        $this->createContainer();
+
+        $this->controller = new BookmarkListController($this->container);
+    }
+
+    /**
+     * Test rendering list of bookmarks with default parameters (first page).
+     */
+    public function testIndexDefaultFirstPage(): void
+    {
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->bookmarkService
+            ->expects(static::once())
+            ->method('search')
+            ->with(
+                ['searchtags' => '', 'searchterm' => ''],
+                null,
+                false,
+                false
+            )
+            ->willReturn([
+                (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
+                (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
+                (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
+            ]
+        );
+
+        $this->container->sessionManager
+            ->method('getSessionParameter')
+            ->willReturnCallback(function (string $parameter, $default = null) {
+                if ('LINKS_PER_PAGE' === $parameter) {
+                    return 2;
+                }
+
+                return $default;
+            })
+        ;
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('linklist', (string) $result->getBody());
+
+        static::assertSame('Shaarli', $assignedVariables['pagetitle']);
+        static::assertSame('?page=2', $assignedVariables['previous_page_url']);
+        static::assertSame('', $assignedVariables['next_page_url']);
+        static::assertSame(2, $assignedVariables['page_max']);
+        static::assertSame('', $assignedVariables['search_tags']);
+        static::assertSame(3, $assignedVariables['result_count']);
+        static::assertSame(1, $assignedVariables['page_current']);
+        static::assertSame('', $assignedVariables['search_term']);
+        static::assertNull($assignedVariables['visibility']);
+        static::assertCount(2, $assignedVariables['links']);
+
+        $link = $assignedVariables['links'][0];
+
+        static::assertSame(1, $link['id']);
+        static::assertSame('http://url1.tld', $link['url']);
+        static::assertSame('Title 1', $link['title']);
+
+        $link = $assignedVariables['links'][1];
+
+        static::assertSame(2, $link['id']);
+        static::assertSame('http://url2.tld', $link['url']);
+        static::assertSame('Title 2', $link['title']);
+    }
+
+    /**
+     * Test rendering list of bookmarks with default parameters (second page).
+     */
+    public function testIndexDefaultSecondPage(): void
+    {
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $request = $this->createMock(Request::class);
+        $request->method('getParam')->willReturnCallback(function (string $key) {
+            if ('page' === $key) {
+                return '2';
+            }
+
+            return null;
+        });
+        $response = new Response();
+
+        $this->container->bookmarkService
+            ->expects(static::once())
+            ->method('search')
+            ->with(
+                ['searchtags' => '', 'searchterm' => ''],
+                null,
+                false,
+                false
+            )
+            ->willReturn([
+                (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
+                (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
+                (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
+            ])
+        ;
+
+        $this->container->sessionManager
+            ->method('getSessionParameter')
+            ->willReturnCallback(function (string $parameter, $default = null) {
+                if ('LINKS_PER_PAGE' === $parameter) {
+                    return 2;
+                }
+
+                return $default;
+            })
+        ;
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('linklist', (string) $result->getBody());
+
+        static::assertSame('Shaarli', $assignedVariables['pagetitle']);
+        static::assertSame('', $assignedVariables['previous_page_url']);
+        static::assertSame('?page=1', $assignedVariables['next_page_url']);
+        static::assertSame(2, $assignedVariables['page_max']);
+        static::assertSame('', $assignedVariables['search_tags']);
+        static::assertSame(3, $assignedVariables['result_count']);
+        static::assertSame(2, $assignedVariables['page_current']);
+        static::assertSame('', $assignedVariables['search_term']);
+        static::assertNull($assignedVariables['visibility']);
+        static::assertCount(1, $assignedVariables['links']);
+
+        $link = $assignedVariables['links'][2];
+
+        static::assertSame(3, $link['id']);
+        static::assertSame('http://url3.tld', $link['url']);
+        static::assertSame('Title 3', $link['title']);
+    }
+
+    /**
+     * Test rendering list of bookmarks with filters.
+     */
+    public function testIndexDefaultWithFilters(): void
+    {
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $request = $this->createMock(Request::class);
+        $request->method('getParam')->willReturnCallback(function (string $key) {
+            if ('searchtags' === $key) {
+                return 'abc def';
+            }
+            if ('searchterm' === $key) {
+                return 'ghi jkl';
+            }
+
+            return null;
+        });
+        $response = new Response();
+
+        $this->container->sessionManager
+            ->method('getSessionParameter')
+            ->willReturnCallback(function (string $key, $default) {
+                if ('LINKS_PER_PAGE' === $key) {
+                    return 2;
+                }
+                if ('visibility' === $key) {
+                    return 'private';
+                }
+                if ('untaggedonly' === $key) {
+                    return true;
+                }
+
+                return $default;
+            })
+        ;
+
+        $this->container->bookmarkService
+            ->expects(static::once())
+            ->method('search')
+            ->with(
+                ['searchtags' => 'abc def', 'searchterm' => 'ghi jkl'],
+                'private',
+                false,
+                true
+            )
+            ->willReturn([
+                (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
+                (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
+                (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
+            ])
+        ;
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('linklist', (string) $result->getBody());
+
+        static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']);
+        static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc+def', $assignedVariables['previous_page_url']);
+    }
+
+    /**
+     * Test displaying a permalink with valid parameters
+     */
+    public function testPermalinkValid(): void
+    {
+        $hash = 'abcdef';
+
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->bookmarkService
+            ->expects(static::once())
+            ->method('findByHash')
+            ->with($hash)
+            ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
+        ;
+
+        $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('linklist', (string) $result->getBody());
+
+        static::assertSame('Title 1 - Shaarli', $assignedVariables['pagetitle']);
+        static::assertCount(1, $assignedVariables['links']);
+
+        $link = $assignedVariables['links'][0];
+
+        static::assertSame(123, $link['id']);
+        static::assertSame('http://url1.tld', $link['url']);
+        static::assertSame('Title 1', $link['title']);
+    }
+
+    /**
+     * Test displaying a permalink with an unknown small hash : renders a 404 template error
+     */
+    public function testPermalinkNotFound(): void
+    {
+        $hash = 'abcdef';
+
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->bookmarkService
+            ->expects(static::once())
+            ->method('findByHash')
+            ->with($hash)
+            ->willThrowException(new BookmarkNotFoundException())
+        ;
+
+        $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('404', (string) $result->getBody());
+
+        static::assertSame(
+            'The link you are trying to reach does not exist or has been deleted.',
+            $assignedVariables['error_message']
+        );
+    }
+
+    /**
+     * Test getting link list with thumbnail updates.
+     *   -> 2 thumbnails update, only 1 datastore write
+     */
+    public function testThumbnailUpdateFromLinkList(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->loginManager = $this->createMock(LoginManager::class);
+        $this->container->loginManager->method('isLoggedIn')->willReturn(true);
+
+        $this->container->conf = $this->createMock(ConfigManager::class);
+        $this->container->conf
+            ->method('get')
+            ->willReturnCallback(function (string $key, $default) {
+                return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default;
+            })
+        ;
+
+        $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
+        $this->container->thumbnailer
+            ->expects(static::exactly(2))
+            ->method('get')
+            ->withConsecutive(['https://url2.tld'], ['https://url4.tld'])
+        ;
+
+        $this->container->bookmarkService
+            ->expects(static::once())
+            ->method('search')
+            ->willReturn([
+                (new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
+                $b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
+                (new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
+                $b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
+                (new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
+            ])
+        ;
+        $this->container->bookmarkService
+            ->expects(static::exactly(2))
+            ->method('set')
+            ->withConsecutive([$b1, false], [$b2, false])
+        ;
+        $this->container->bookmarkService->expects(static::once())->method('save');
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('linklist', (string) $result->getBody());
+    }
+
+    /**
+     * Test getting a permalink with thumbnail update.
+     */
+    public function testThumbnailUpdateFromPermalink(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->loginManager = $this->createMock(LoginManager::class);
+        $this->container->loginManager->method('isLoggedIn')->willReturn(true);
+
+        $this->container->conf = $this->createMock(ConfigManager::class);
+        $this->container->conf
+            ->method('get')
+            ->willReturnCallback(function (string $key, $default) {
+                return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default;
+            })
+        ;
+
+        $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
+        $this->container->thumbnailer->expects(static::once())->method('get')->withConsecutive(['https://url.tld']);
+
+        $this->container->bookmarkService
+            ->expects(static::once())
+            ->method('findByHash')
+            ->willReturn($bookmark = (new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
+        ;
+        $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, true);
+        $this->container->bookmarkService->expects(static::never())->method('save');
+
+        $result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('linklist', (string) $result->getBody());
+    }
+
+    /**
+     * Trigger legacy controller in link list controller: permalink
+     */
+    public function testLegacyControllerPermalink(): void
+    {
+        $hash = 'abcdef';
+        $this->container->environment['QUERY_STRING'] = $hash;
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/shaare/' . $hash, $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Trigger legacy controller in link list controller: ?do= query parameter
+     */
+    public function testLegacyControllerDoPage(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getQueryParam')->with('do')->willReturn('picwall');
+        $response = new Response();
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/picture-wall', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Trigger legacy controller in link list controller: ?do= query parameter with unknown legacy route
+     */
+    public function testLegacyControllerUnknownDoPage(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getQueryParam')->with('do')->willReturn('nope');
+        $response = new Response();
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame('linklist', (string) $result->getBody());
+    }
+
+    /**
+     * Trigger legacy controller in link list controller: other GET route (e.g. ?post)
+     */
+    public function testLegacyControllerGetParameter(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getQueryParams')->willReturn(['post' => $url = 'http://url.tld']);
+        $response = new Response();
+
+        $this->container->loginManager = $this->createMock(LoginManager::class);
+        $this->container->loginManager->method('isLoggedIn')->willReturn(true);
+
+        $result = $this->controller->index($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(
+            '/subfolder/admin/shaare?post=' . urlencode($url),
+            $result->getHeader('location')[0]
+        );
+    }
+}
diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
new file mode 100644 (file)
index 0000000..ff4520a
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Legacy;
+
+use PHPUnit\Framework\TestCase;
+use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+class LegacyControllerTest extends TestCase
+{
+    use FrontControllerMockHelper;
+
+    /** @var LegacyController */
+    protected $controller;
+
+    public function setUp(): void
+    {
+        $this->createContainer();
+
+        $this->controller = new LegacyController($this->container);
+    }
+
+    /**
+     * @dataProvider getProcessProvider
+     */
+    public function testProcess(string $legacyRoute, array $queryParameters, string $slimRoute, bool $isLoggedIn): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getQueryParams')->willReturn($queryParameters);
+        $request
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) use ($queryParameters): ?string {
+                return $queryParameters[$key] ?? null;
+            })
+        ;
+        $response = new Response();
+
+        $this->container->loginManager->method('isLoggedIn')->willReturn($isLoggedIn);
+
+        $result = $this->controller->process($request, $response, $legacyRoute);
+
+        static::assertSame('/subfolder' . $slimRoute, $result->getHeader('location')[0]);
+    }
+
+    public function testProcessNotFound(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->expectException(UnknowLegacyRouteException::class);
+
+        $this->controller->process($request, $response, 'nope');
+    }
+
+    /**
+     * @return array[] Parameters:
+     *                   - string legacyRoute
+     *                   - array  queryParameters
+     *                   - string slimRoute
+     *                   - bool   isLoggedIn
+     */
+    public function getProcessProvider(): array
+    {
+        return [
+            ['post', [], '/admin/shaare', true],
+            ['post', [], '/login', false],
+            ['post', ['title' => 'test'], '/admin/shaare?title=test', true],
+            ['post', ['title' => 'test'], '/login?title=test', false],
+            ['addlink', [], '/admin/add-shaare', true],
+            ['addlink', [], '/login', false],
+            ['login', [], '/login', true],
+            ['login', [], '/login', false],
+            ['logout', [], '/logout', true],
+            ['logout', [], '/logout', false],
+            ['picwall', [], '/picture-wall', false],
+            ['picwall', [], '/picture-wall', true],
+            ['tagcloud', [], '/tags/cloud', false],
+            ['tagcloud', [], '/tags/cloud', true],
+            ['taglist', [], '/tags/list', false],
+            ['taglist', [], '/tags/list', true],
+            ['daily', [], '/daily', false],
+            ['daily', [], '/daily', true],
+            ['daily', ['day' => '123456789', 'discard' => '1'], '/daily?day=123456789', false],
+            ['rss', [], '/feed/rss', false],
+            ['rss', [], '/feed/rss', true],
+            ['rss', ['search' => 'filter123', 'other' => 'param'], '/feed/rss?search=filter123&other=param', false],
+            ['atom', [], '/feed/atom', false],
+            ['atom', [], '/feed/atom', true],
+            ['atom', ['search' => 'filter123', 'other' => 'param'], '/feed/atom?search=filter123&other=param', false],
+            ['opensearch', [], '/open-search', false],
+            ['opensearch', [], '/open-search', true],
+            ['dailyrss', [], '/daily-rss', false],
+            ['dailyrss', [], '/daily-rss', true],
+        ];
+    }
+}
similarity index 51%
rename from tests/RouterTest.php
rename to tests/legacy/LegacyRouterTest.php
index 0cd49bb8fb2ea6951018e818bc3b8a9907c242d7..c2019ca7f3fc8e0563a909e542360c9bc717966a 100644 (file)
@@ -1,10 +1,13 @@
 <?php
-namespace Shaarli;
+
+namespace Shaarli\Legacy;
+
+use PHPUnit\Framework\TestCase;
 
 /**
  * Unit tests for Router
  */
-class RouterTest extends \PHPUnit\Framework\TestCase
+class LegacyRouterTest extends TestCase
 {
     /**
      * Test findPage: login page output.
@@ -15,18 +18,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageLoginValid()
     {
         $this->assertEquals(
-            Router::$PAGE_LOGIN,
-            Router::findPage('do=login', array(), false)
+            LegacyRouter::$PAGE_LOGIN,
+            LegacyRouter::findPage('do=login', array(), false)
         );
 
         $this->assertEquals(
-            Router::$PAGE_LOGIN,
-            Router::findPage('do=login', array(), 1)
+            LegacyRouter::$PAGE_LOGIN,
+            LegacyRouter::findPage('do=login', array(), 1)
         );
 
         $this->assertEquals(
-            Router::$PAGE_LOGIN,
-            Router::findPage('do=login&stuff', array(), false)
+            LegacyRouter::$PAGE_LOGIN,
+            LegacyRouter::findPage('do=login&stuff', array(), false)
         );
     }
 
@@ -39,13 +42,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageLoginInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_LOGIN,
-            Router::findPage('do=login', array(), true)
+            LegacyRouter::$PAGE_LOGIN,
+            LegacyRouter::findPage('do=login', array(), true)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_LOGIN,
-            Router::findPage('do=other', array(), false)
+            LegacyRouter::$PAGE_LOGIN,
+            LegacyRouter::findPage('do=other', array(), false)
         );
     }
 
@@ -58,13 +61,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPagePicwallValid()
     {
         $this->assertEquals(
-            Router::$PAGE_PICWALL,
-            Router::findPage('do=picwall', array(), false)
+            LegacyRouter::$PAGE_PICWALL,
+            LegacyRouter::findPage('do=picwall', array(), false)
         );
 
         $this->assertEquals(
-            Router::$PAGE_PICWALL,
-            Router::findPage('do=picwall', array(), true)
+            LegacyRouter::$PAGE_PICWALL,
+            LegacyRouter::findPage('do=picwall', array(), true)
         );
     }
 
@@ -77,13 +80,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPagePicwallInvalid()
     {
         $this->assertEquals(
-            Router::$PAGE_PICWALL,
-            Router::findPage('do=picwall&stuff', array(), false)
+            LegacyRouter::$PAGE_PICWALL,
+            LegacyRouter::findPage('do=picwall&stuff', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_PICWALL,
-            Router::findPage('do=other', array(), false)
+            LegacyRouter::$PAGE_PICWALL,
+            LegacyRouter::findPage('do=other', array(), false)
         );
     }
 
@@ -96,18 +99,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageTagcloudValid()
     {
         $this->assertEquals(
-            Router::$PAGE_TAGCLOUD,
-            Router::findPage('do=tagcloud', array(), false)
+            LegacyRouter::$PAGE_TAGCLOUD,
+            LegacyRouter::findPage('do=tagcloud', array(), false)
         );
 
         $this->assertEquals(
-            Router::$PAGE_TAGCLOUD,
-            Router::findPage('do=tagcloud', array(), true)
+            LegacyRouter::$PAGE_TAGCLOUD,
+            LegacyRouter::findPage('do=tagcloud', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_TAGCLOUD,
-            Router::findPage('do=tagcloud&stuff', array(), false)
+            LegacyRouter::$PAGE_TAGCLOUD,
+            LegacyRouter::findPage('do=tagcloud&stuff', array(), false)
         );
     }
 
@@ -120,8 +123,8 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageTagcloudInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_TAGCLOUD,
-            Router::findPage('do=other', array(), false)
+            LegacyRouter::$PAGE_TAGCLOUD,
+            LegacyRouter::findPage('do=other', array(), false)
         );
     }
 
@@ -134,23 +137,23 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageLinklistValid()
     {
         $this->assertEquals(
-            Router::$PAGE_LINKLIST,
-            Router::findPage('', array(), true)
+            LegacyRouter::$PAGE_LINKLIST,
+            LegacyRouter::findPage('', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_LINKLIST,
-            Router::findPage('whatever', array(), true)
+            LegacyRouter::$PAGE_LINKLIST,
+            LegacyRouter::findPage('whatever', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_LINKLIST,
-            Router::findPage('whatever', array(), false)
+            LegacyRouter::$PAGE_LINKLIST,
+            LegacyRouter::findPage('whatever', array(), false)
         );
 
         $this->assertEquals(
-            Router::$PAGE_LINKLIST,
-            Router::findPage('do=tools', array(), false)
+            LegacyRouter::$PAGE_LINKLIST,
+            LegacyRouter::findPage('do=tools', array(), false)
         );
     }
 
@@ -163,13 +166,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageToolsValid()
     {
         $this->assertEquals(
-            Router::$PAGE_TOOLS,
-            Router::findPage('do=tools', array(), true)
+            LegacyRouter::$PAGE_TOOLS,
+            LegacyRouter::findPage('do=tools', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_TOOLS,
-            Router::findPage('do=tools&stuff', array(), true)
+            LegacyRouter::$PAGE_TOOLS,
+            LegacyRouter::findPage('do=tools&stuff', array(), true)
         );
     }
 
@@ -182,18 +185,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageToolsInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_TOOLS,
-            Router::findPage('do=tools', array(), 1)
+            LegacyRouter::$PAGE_TOOLS,
+            LegacyRouter::findPage('do=tools', array(), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_TOOLS,
-            Router::findPage('do=tools', array(), false)
+            LegacyRouter::$PAGE_TOOLS,
+            LegacyRouter::findPage('do=tools', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_TOOLS,
-            Router::findPage('do=other', array(), true)
+            LegacyRouter::$PAGE_TOOLS,
+            LegacyRouter::findPage('do=other', array(), true)
         );
     }
 
@@ -206,12 +209,12 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageChangepasswdValid()
     {
         $this->assertEquals(
-            Router::$PAGE_CHANGEPASSWORD,
-            Router::findPage('do=changepasswd', array(), true)
+            LegacyRouter::$PAGE_CHANGEPASSWORD,
+            LegacyRouter::findPage('do=changepasswd', array(), true)
         );
         $this->assertEquals(
-            Router::$PAGE_CHANGEPASSWORD,
-            Router::findPage('do=changepasswd&stuff', array(), true)
+            LegacyRouter::$PAGE_CHANGEPASSWORD,
+            LegacyRouter::findPage('do=changepasswd&stuff', array(), true)
         );
     }
 
@@ -224,18 +227,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageChangepasswdInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_CHANGEPASSWORD,
-            Router::findPage('do=changepasswd', array(), 1)
+            LegacyRouter::$PAGE_CHANGEPASSWORD,
+            LegacyRouter::findPage('do=changepasswd', array(), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_CHANGEPASSWORD,
-            Router::findPage('do=changepasswd', array(), false)
+            LegacyRouter::$PAGE_CHANGEPASSWORD,
+            LegacyRouter::findPage('do=changepasswd', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_CHANGEPASSWORD,
-            Router::findPage('do=other', array(), true)
+            LegacyRouter::$PAGE_CHANGEPASSWORD,
+            LegacyRouter::findPage('do=other', array(), true)
         );
     }
     /**
@@ -247,13 +250,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageConfigureValid()
     {
         $this->assertEquals(
-            Router::$PAGE_CONFIGURE,
-            Router::findPage('do=configure', array(), true)
+            LegacyRouter::$PAGE_CONFIGURE,
+            LegacyRouter::findPage('do=configure', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_CONFIGURE,
-            Router::findPage('do=configure&stuff', array(), true)
+            LegacyRouter::$PAGE_CONFIGURE,
+            LegacyRouter::findPage('do=configure&stuff', array(), true)
         );
     }
 
@@ -266,18 +269,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageConfigureInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_CONFIGURE,
-            Router::findPage('do=configure', array(), 1)
+            LegacyRouter::$PAGE_CONFIGURE,
+            LegacyRouter::findPage('do=configure', array(), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_CONFIGURE,
-            Router::findPage('do=configure', array(), false)
+            LegacyRouter::$PAGE_CONFIGURE,
+            LegacyRouter::findPage('do=configure', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_CONFIGURE,
-            Router::findPage('do=other', array(), true)
+            LegacyRouter::$PAGE_CONFIGURE,
+            LegacyRouter::findPage('do=other', array(), true)
         );
     }
 
@@ -290,13 +293,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageChangetagValid()
     {
         $this->assertEquals(
-            Router::$PAGE_CHANGETAG,
-            Router::findPage('do=changetag', array(), true)
+            LegacyRouter::$PAGE_CHANGETAG,
+            LegacyRouter::findPage('do=changetag', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_CHANGETAG,
-            Router::findPage('do=changetag&stuff', array(), true)
+            LegacyRouter::$PAGE_CHANGETAG,
+            LegacyRouter::findPage('do=changetag&stuff', array(), true)
         );
     }
 
@@ -309,18 +312,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageChangetagInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_CHANGETAG,
-            Router::findPage('do=changetag', array(), 1)
+            LegacyRouter::$PAGE_CHANGETAG,
+            LegacyRouter::findPage('do=changetag', array(), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_CHANGETAG,
-            Router::findPage('do=changetag', array(), false)
+            LegacyRouter::$PAGE_CHANGETAG,
+            LegacyRouter::findPage('do=changetag', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_CHANGETAG,
-            Router::findPage('do=other', array(), true)
+            LegacyRouter::$PAGE_CHANGETAG,
+            LegacyRouter::findPage('do=other', array(), true)
         );
     }
 
@@ -333,13 +336,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageAddlinkValid()
     {
         $this->assertEquals(
-            Router::$PAGE_ADDLINK,
-            Router::findPage('do=addlink', array(), true)
+            LegacyRouter::$PAGE_ADDLINK,
+            LegacyRouter::findPage('do=addlink', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_ADDLINK,
-            Router::findPage('do=addlink&stuff', array(), true)
+            LegacyRouter::$PAGE_ADDLINK,
+            LegacyRouter::findPage('do=addlink&stuff', array(), true)
         );
     }
 
@@ -352,18 +355,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageAddlinkInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_ADDLINK,
-            Router::findPage('do=addlink', array(), 1)
+            LegacyRouter::$PAGE_ADDLINK,
+            LegacyRouter::findPage('do=addlink', array(), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_ADDLINK,
-            Router::findPage('do=addlink', array(), false)
+            LegacyRouter::$PAGE_ADDLINK,
+            LegacyRouter::findPage('do=addlink', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_ADDLINK,
-            Router::findPage('do=other', array(), true)
+            LegacyRouter::$PAGE_ADDLINK,
+            LegacyRouter::findPage('do=other', array(), true)
         );
     }
 
@@ -376,13 +379,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageExportValid()
     {
         $this->assertEquals(
-            Router::$PAGE_EXPORT,
-            Router::findPage('do=export', array(), true)
+            LegacyRouter::$PAGE_EXPORT,
+            LegacyRouter::findPage('do=export', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_EXPORT,
-            Router::findPage('do=export&stuff', array(), true)
+            LegacyRouter::$PAGE_EXPORT,
+            LegacyRouter::findPage('do=export&stuff', array(), true)
         );
     }
 
@@ -395,18 +398,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageExportInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_EXPORT,
-            Router::findPage('do=export', array(), 1)
+            LegacyRouter::$PAGE_EXPORT,
+            LegacyRouter::findPage('do=export', array(), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_EXPORT,
-            Router::findPage('do=export', array(), false)
+            LegacyRouter::$PAGE_EXPORT,
+            LegacyRouter::findPage('do=export', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_EXPORT,
-            Router::findPage('do=other', array(), true)
+            LegacyRouter::$PAGE_EXPORT,
+            LegacyRouter::findPage('do=other', array(), true)
         );
     }
 
@@ -419,13 +422,13 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageImportValid()
     {
         $this->assertEquals(
-            Router::$PAGE_IMPORT,
-            Router::findPage('do=import', array(), true)
+            LegacyRouter::$PAGE_IMPORT,
+            LegacyRouter::findPage('do=import', array(), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_IMPORT,
-            Router::findPage('do=import&stuff', array(), true)
+            LegacyRouter::$PAGE_IMPORT,
+            LegacyRouter::findPage('do=import&stuff', array(), true)
         );
     }
 
@@ -438,18 +441,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageImportInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_IMPORT,
-            Router::findPage('do=import', array(), 1)
+            LegacyRouter::$PAGE_IMPORT,
+            LegacyRouter::findPage('do=import', array(), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_IMPORT,
-            Router::findPage('do=import', array(), false)
+            LegacyRouter::$PAGE_IMPORT,
+            LegacyRouter::findPage('do=import', array(), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_IMPORT,
-            Router::findPage('do=other', array(), true)
+            LegacyRouter::$PAGE_IMPORT,
+            LegacyRouter::findPage('do=other', array(), true)
         );
     }
 
@@ -462,24 +465,24 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageEditlinkValid()
     {
         $this->assertEquals(
-            Router::$PAGE_EDITLINK,
-            Router::findPage('whatever', array('edit_link' => 1), true)
+            LegacyRouter::$PAGE_EDITLINK,
+            LegacyRouter::findPage('whatever', array('edit_link' => 1), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_EDITLINK,
-            Router::findPage('', array('edit_link' => 1), true)
+            LegacyRouter::$PAGE_EDITLINK,
+            LegacyRouter::findPage('', array('edit_link' => 1), true)
         );
 
 
         $this->assertEquals(
-            Router::$PAGE_EDITLINK,
-            Router::findPage('whatever', array('post' => 1), true)
+            LegacyRouter::$PAGE_EDITLINK,
+            LegacyRouter::findPage('whatever', array('post' => 1), true)
         );
 
         $this->assertEquals(
-            Router::$PAGE_EDITLINK,
-            Router::findPage('whatever', array('post' => 1, 'edit_link' => 1), true)
+            LegacyRouter::$PAGE_EDITLINK,
+            LegacyRouter::findPage('whatever', array('post' => 1, 'edit_link' => 1), true)
         );
     }
 
@@ -492,18 +495,18 @@ class RouterTest extends \PHPUnit\Framework\TestCase
     public function testFindPageEditlinkInvalid()
     {
         $this->assertNotEquals(
-            Router::$PAGE_EDITLINK,
-            Router::findPage('whatever', array('edit_link' => 1), false)
+            LegacyRouter::$PAGE_EDITLINK,
+            LegacyRouter::findPage('whatever', array('edit_link' => 1), false)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_EDITLINK,
-            Router::findPage('whatever', array('edit_link' => 1), 1)
+            LegacyRouter::$PAGE_EDITLINK,
+            LegacyRouter::findPage('whatever', array('edit_link' => 1), 1)
         );
 
         $this->assertNotEquals(
-            Router::$PAGE_EDITLINK,
-            Router::findPage('whatever', array(), true)
+            LegacyRouter::$PAGE_EDITLINK,
+            LegacyRouter::findPage('whatever', array(), true)
         );
     }
 }
index d052f8b9f24766911d4c295a4015b24456959f07..4018c1a852bea4c5ca634ce56dbba59cce744c4a 100644 (file)
@@ -2,7 +2,7 @@
 namespace Shaarli\Plugin\Addlink;
 
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 require_once 'plugins/addlink_toolbar/addlink_toolbar.php';
 
@@ -26,7 +26,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
     {
         $str = 'stuff';
         $data = array($str => $str);
-        $data['_PAGE_'] = Router::$PAGE_LINKLIST;
+        $data['_PAGE_'] = TemplatePage::LINKLIST;
         $data['_LOGGEDIN_'] = true;
 
         $data = hook_addlink_toolbar_render_header($data);
@@ -48,7 +48,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
     {
         $str = 'stuff';
         $data = array($str => $str);
-        $data['_PAGE_'] = Router::$PAGE_LINKLIST;
+        $data['_PAGE_'] = TemplatePage::LINKLIST;
         $data['_LOGGEDIN_'] = false;
 
         $data = hook_addlink_toolbar_render_header($data);
index 51472617ad47cf21cd5fbc418ca2fd5d0982652c..b7b6ce53fee211132aeee26030b3c1ffadd3249a 100644 (file)
@@ -6,7 +6,7 @@ namespace Shaarli\Plugin\Playvideos;
  */
 
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 require_once 'plugins/playvideos/playvideos.php';
 
@@ -31,7 +31,7 @@ class PluginPlayvideosTest extends \PHPUnit\Framework\TestCase
     {
         $str = 'stuff';
         $data = array($str => $str);
-        $data['_PAGE_'] = Router::$PAGE_LINKLIST;
+        $data['_PAGE_'] = TemplatePage::LINKLIST;
 
         $data = hook_playvideos_render_header($data);
         $this->assertEquals($str, $data[$str]);
@@ -50,7 +50,7 @@ class PluginPlayvideosTest extends \PHPUnit\Framework\TestCase
     {
         $str = 'stuff';
         $data = array($str => $str);
-        $data['_PAGE_'] = Router::$PAGE_LINKLIST;
+        $data['_PAGE_'] = TemplatePage::LINKLIST;
 
         $data = hook_playvideos_render_footer($data);
         $this->assertEquals($str, $data[$str]);
index a7bd8fc93d79980633fd7edc71a66eb248df0b3e..e66f484edcdb6928ec4213ae918c2ebff2b36323 100644 (file)
@@ -3,7 +3,7 @@ namespace Shaarli\Plugin\Pubsubhubbub;
 
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 require_once 'plugins/pubsubhubbub/pubsubhubbub.php';
 
@@ -34,7 +34,7 @@ class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase
         $hub = 'http://domain.hub';
         $conf = new ConfigManager(self::$configFile);
         $conf->set('plugins.PUBSUBHUB_URL', $hub);
-        $data['_PAGE_'] = Router::$PAGE_FEED_RSS;
+        $data['_PAGE_'] = TemplatePage::FEED_RSS;
 
         $data = hook_pubsubhubbub_render_feed($data, $conf);
         $expected = '<atom:link rel="hub" href="'. $hub .'" />';
@@ -49,7 +49,7 @@ class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase
         $hub = 'http://domain.hub';
         $conf = new ConfigManager(self::$configFile);
         $conf->set('plugins.PUBSUBHUB_URL', $hub);
-        $data['_PAGE_'] = Router::$PAGE_FEED_ATOM;
+        $data['_PAGE_'] = TemplatePage::FEED_ATOM;
 
         $data = hook_pubsubhubbub_render_feed($data, $conf);
         $expected = '<link rel="hub" href="'. $hub .'" />';
index 0c61e14a75bc841f1be4d5362bcb4b55c8b4662d..c9f8c733d40adcac140fc2bdb5fe8ab817123f6c 100644 (file)
@@ -6,7 +6,7 @@ namespace Shaarli\Plugin\Qrcode;
  */
 
 use Shaarli\Plugin\PluginManager;
-use Shaarli\Router;
+use Shaarli\Render\TemplatePage;
 
 require_once 'plugins/qrcode/qrcode.php';
 
@@ -57,7 +57,7 @@ class PluginQrcodeTest extends \PHPUnit\Framework\TestCase
     {
         $str = 'stuff';
         $data = array($str => $str);
-        $data['_PAGE_'] = Router::$PAGE_LINKLIST;
+        $data['_PAGE_'] = TemplatePage::LINKLIST;
 
         $data = hook_qrcode_render_footer($data);
         $this->assertEquals($str, $data[$str]);
index c689982b49ea15551b230290b76dbf50caa9f203..afc35aece2306fb4014fef30bb3b7543f3fcac0a 100644 (file)
@@ -2,7 +2,10 @@
 namespace Shaarli\Updater;
 
 use Exception;
+use Shaarli\Bookmark\BookmarkFileService;
+use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
+use Shaarli\History;
 
 require_once 'tests/updater/DummyUpdater.php';
 require_once 'tests/utils/ReferenceLinkDB.php';
@@ -29,6 +32,12 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
      */
     protected $conf;
 
+    /** @var BookmarkServiceInterface */
+    protected $bookmarkService;
+
+    /** @var Updater */
+    protected $updater;
+
     /**
      * Executed before each test.
      */
@@ -36,6 +45,8 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
     {
         copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
         $this->conf = new ConfigManager(self::$configFile);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), true);
+        $this->updater = new Updater([], $this->bookmarkService, $this->conf, true);
     }
 
     /**
@@ -167,4 +178,12 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
         $updater = new DummyUpdater($updates, array(), $this->conf, true);
         $updater->update();
     }
+
+    public function testUpdateMethodRelativeHomeLinkRename(): void
+    {
+        $this->conf->set('general.header_link', '?');
+        $this->updater->updateMethodRelativeHomeLink();
+
+        static::assertSame();
+    }
 }
index 8c1c2036972f3aaf500c0e003a028b9033b47d8a..c7617b228b5c13be9a140865a9c8e0dd5c7be784 100644 (file)
                     </div>
                   {/if}
                 {/if}
-                <a href="{$base_path}/?{$value.shorturl}" title="{$strPermalink}">
+                <a href="{$base_path}/shaare/{$value.shorturl}" title="{$strPermalink}">
                   {if="!$hide_timestamps || $is_logged_in"}
                     {$updated=$value.updated_timestamp ? $strEdited. format_date($value.updated) : $strPermalink}
                     <span class="linkdate" title="{$updated}">