Process picwall rendering through Slim controller + UT
This commit is contained in:
parent
bee33239ed
commit
485b168a96
15 changed files with 346 additions and 88 deletions
|
@ -14,7 +14,7 @@ indent_size = 4
|
|||
indent_size = 2
|
||||
|
||||
[*.php]
|
||||
max_line_length = 100
|
||||
max_line_length = 120
|
||||
|
||||
[Dockerfile]
|
||||
max_line_length = 80
|
||||
|
|
|
@ -346,7 +346,7 @@ class Bookmark
|
|||
/**
|
||||
* Get the Thumbnail.
|
||||
*
|
||||
* @return string|bool
|
||||
* @return string|bool|null
|
||||
*/
|
||||
public function getThumbnail()
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Shaarli\Container;
|
|||
use Shaarli\Bookmark\BookmarkFileService;
|
||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Formatter\FormatterFactory;
|
||||
use Shaarli\History;
|
||||
use Shaarli\Plugin\PluginManager;
|
||||
use Shaarli\Render\PageBuilder;
|
||||
|
@ -76,6 +77,10 @@ class ContainerBuilder
|
|||
return new PluginManager($container->conf);
|
||||
};
|
||||
|
||||
$container['formatterFactory'] = function (ShaarliContainer $container): FormatterFactory {
|
||||
return new FormatterFactory($container->conf, $container->loginManager->isLoggedIn());
|
||||
};
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Shaarli\Container;
|
|||
|
||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Formatter\FormatterFactory;
|
||||
use Shaarli\History;
|
||||
use Shaarli\Plugin\PluginManager;
|
||||
use Shaarli\Render\PageBuilder;
|
||||
|
@ -23,6 +24,7 @@ use Slim\Container;
|
|||
* @property BookmarkServiceInterface $bookmarkService
|
||||
* @property PageBuilder $pageBuilder
|
||||
* @property PluginManager $pluginManager
|
||||
* @property FormatterFactory $formatterFactory
|
||||
*/
|
||||
class ShaarliContainer extends Container
|
||||
{
|
||||
|
|
72
application/front/controllers/PictureWallController.php
Normal file
72
application/front/controllers/PictureWallController.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Front\Controller;
|
||||
|
||||
use Shaarli\Front\Exception\ThumbnailsDisabledException;
|
||||
use Shaarli\Thumbnailer;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* Class PicturesWallController
|
||||
*
|
||||
* Slim controller used to render the pictures wall page.
|
||||
* If thumbnails mode is set to NONE, we just render the template without any image.
|
||||
*
|
||||
* @package Front\Controller
|
||||
*/
|
||||
class PictureWallController extends ShaarliController
|
||||
{
|
||||
public function index(Request $request, Response $response): Response
|
||||
{
|
||||
if ($this->container->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) {
|
||||
throw new ThumbnailsDisabledException();
|
||||
}
|
||||
|
||||
$this->assignView(
|
||||
'pagetitle',
|
||||
t('Picture wall') .' - '. $this->container->conf->get('general.title', 'Shaarli')
|
||||
);
|
||||
|
||||
// Optionally filter the results:
|
||||
$links = $this->container->bookmarkService->search($request->getQueryParams());
|
||||
$linksToDisplay = [];
|
||||
|
||||
// Get only bookmarks which have a thumbnail.
|
||||
// Note: we do not retrieve thumbnails here, the request is too heavy.
|
||||
$formatter = $this->container->formatterFactory->getFormatter('raw');
|
||||
foreach ($links as $key => $link) {
|
||||
if (!empty($link->getThumbnail())) {
|
||||
$linksToDisplay[] = $formatter->format($link);
|
||||
}
|
||||
}
|
||||
|
||||
$data = $this->executeHooks($linksToDisplay);
|
||||
foreach ($data as $key => $value) {
|
||||
$this->assignView($key, $value);
|
||||
}
|
||||
|
||||
return $response->write($this->render('picwall'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $linksToDisplay List of formatted bookmarks
|
||||
*
|
||||
* @return mixed[] Template data after active plugins render_picwall hook execution.
|
||||
*/
|
||||
protected function executeHooks(array $linksToDisplay): array
|
||||
{
|
||||
$data = [
|
||||
'linksToDisplay' => $linksToDisplay,
|
||||
];
|
||||
$this->container->pluginManager->executeHooks(
|
||||
'render_picwall',
|
||||
$data,
|
||||
['loggedin' => $this->container->loginManager->isLoggedIn()]
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
15
application/front/exceptions/ThumbnailsDisabledException.php
Normal file
15
application/front/exceptions/ThumbnailsDisabledException.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Front\Exception;
|
||||
|
||||
class ThumbnailsDisabledException extends ShaarliException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$message = t('Picture wall unavailable (thumbnails are disabled).');
|
||||
|
||||
parent::__construct($message, 400);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Shaarli\Updater;
|
||||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Updater\Exception\UpdaterException;
|
||||
|
||||
/**
|
||||
|
@ -111,4 +111,20 @@ class Updater
|
|||
{
|
||||
return $this->doneUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 `/`.
|
||||
*/
|
||||
public function updateMethodRelativeHomeLink(): bool
|
||||
{
|
||||
$link = trim($this->conf->get('general.header_link'));
|
||||
if ($link[0] === '?') {
|
||||
$link = './'. ltrim($link, '?');
|
||||
|
||||
$this->conf->set('general.header_link', $link, true, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,6 @@ For example, if you want to subscribe only to links tagged `photography`:
|
|||
- The same method **also works for a full-text search** (_Search_ box) **and for the Picture Wall** (want to only see pictures about `nature`?)
|
||||
- You can also build the URLs manually:
|
||||
- `https://my.shaarli.domain/?do=rss&searchtags=nature`
|
||||
- `https://my.shaarli.domain/links/?do=picwall&searchterm=poney`
|
||||
- `https://my.shaarli.domain/links/picture-wall?searchterm=poney`
|
||||
|
||||
![](images/rss-filter-1.png) ![](images/rss-filter-2.png)
|
||||
|
|
|
@ -42,7 +42,7 @@ http://<replace_domain>/?post
|
|||
http://<replace_domain>/?do=export
|
||||
http://<replace_domain>/?do=import
|
||||
http://<replace_domain>/login
|
||||
http://<replace_domain>/?do=picwall
|
||||
http://<replace_domain>/picture-wall
|
||||
http://<replace_domain>/?do=pluginadmin
|
||||
http://<replace_domain>/?do=tagcloud
|
||||
http://<replace_domain>/?do=taglist
|
||||
|
|
33
index.php
33
index.php
|
@ -610,37 +610,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
|
|||
|
||||
// -------- Picture wall
|
||||
if ($targetPage == Router::$PAGE_PICWALL) {
|
||||
$PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli'));
|
||||
if (! $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) {
|
||||
$PAGE->assign('linksToDisplay', []);
|
||||
$PAGE->renderPage('picwall');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Optionally filter the results:
|
||||
$links = $bookmarkService->search($_GET);
|
||||
$linksToDisplay = [];
|
||||
|
||||
// Get only bookmarks which have a thumbnail.
|
||||
// Note: we do not retrieve thumbnails here, the request is too heavy.
|
||||
$factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
|
||||
$formatter = $factory->getFormatter();
|
||||
foreach ($links as $key => $link) {
|
||||
if ($link->getThumbnail() !== false) {
|
||||
$linksToDisplay[] = $formatter->format($link);
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'linksToDisplay' => $linksToDisplay,
|
||||
];
|
||||
$pluginManager->executeHooks('render_picwall', $data, ['loggedin' => $loginManager->isLoggedIn()]);
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$PAGE->assign($key, $value);
|
||||
}
|
||||
|
||||
$PAGE->renderPage('picwall');
|
||||
header('Location: ./picture-wall');
|
||||
exit;
|
||||
}
|
||||
|
||||
|
@ -1944,6 +1914,7 @@ $app->group('/api/v1', function () {
|
|||
|
||||
$app->group('', function () {
|
||||
$this->get('/login', '\Shaarli\Front\Controller\LoginController:index')->setName('login');
|
||||
$this->get('/picture-wall', '\Shaarli\Front\Controller\PictureWallController:index')->setName('picwall');
|
||||
})->add('\Shaarli\Front\ShaarliMiddleware');
|
||||
|
||||
$response = $app->run(true);
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Shaarli\Container;
|
|||
use PHPUnit\Framework\TestCase;
|
||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Formatter\FormatterFactory;
|
||||
use Shaarli\History;
|
||||
use Shaarli\Render\PageBuilder;
|
||||
use Shaarli\Security\LoginManager;
|
||||
|
@ -30,7 +31,9 @@ class ContainerBuilderTest extends TestCase
|
|||
{
|
||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
||||
$this->sessionManager = $this->createMock(SessionManager::class);
|
||||
|
||||
$this->loginManager = $this->createMock(LoginManager::class);
|
||||
$this->loginManager->method('isLoggedIn')->willReturn(true);
|
||||
|
||||
$this->containerBuilder = new ContainerBuilder($this->conf, $this->sessionManager, $this->loginManager);
|
||||
}
|
||||
|
@ -45,5 +48,6 @@ class ContainerBuilderTest extends TestCase
|
|||
static::assertInstanceOf(History::class, $container->history);
|
||||
static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService);
|
||||
static::assertInstanceOf(PageBuilder::class, $container->pageBuilder);
|
||||
static::assertInstanceOf(FormatterFactory::class, $container->formatterFactory);
|
||||
}
|
||||
}
|
||||
|
|
180
tests/front/controller/PictureWallControllerTest.php
Normal file
180
tests/front/controller/PictureWallControllerTest.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Front\Controller;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Shaarli\Bookmark\Bookmark;
|
||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Container\ShaarliContainer;
|
||||
use Shaarli\Formatter\BookmarkFormatter;
|
||||
use Shaarli\Formatter\BookmarkRawFormatter;
|
||||
use Shaarli\Formatter\FormatterFactory;
|
||||
use Shaarli\Front\Exception\ThumbnailsDisabledException;
|
||||
use Shaarli\Plugin\PluginManager;
|
||||
use Shaarli\Render\PageBuilder;
|
||||
use Shaarli\Security\LoginManager;
|
||||
use Shaarli\Thumbnailer;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class PictureWallControllerTest extends TestCase
|
||||
{
|
||||
/** @var ShaarliContainer */
|
||||
protected $container;
|
||||
|
||||
/** @var PictureWallController */
|
||||
protected $controller;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->container = $this->createMock(ShaarliContainer::class);
|
||||
$this->controller = new PictureWallController($this->container);
|
||||
}
|
||||
|
||||
public function testValidControllerInvokeDefault(): void
|
||||
{
|
||||
$this->createValidContainerMockSet();
|
||||
|
||||
$request = $this->createMock(Request::class);
|
||||
$request->expects(static::once())->method('getQueryParams')->willReturn([]);
|
||||
$response = new Response();
|
||||
|
||||
// ConfigManager: thumbnails are enabled
|
||||
$this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) {
|
||||
if ($parameter === 'thumbnails.mode') {
|
||||
return Thumbnailer::MODE_COMMON;
|
||||
}
|
||||
|
||||
return $default;
|
||||
});
|
||||
|
||||
// Save RainTPL assigned variables
|
||||
$assignedVariables = [];
|
||||
$this->container->pageBuilder
|
||||
->expects(static::atLeastOnce())
|
||||
->method('assign')
|
||||
->willReturnCallback(function ($key, $value) use (&$assignedVariables) {
|
||||
$assignedVariables[$key] = $value;
|
||||
|
||||
return $this;
|
||||
})
|
||||
;
|
||||
|
||||
// Links dataset: 2 links with thumbnails
|
||||
$this->container->bookmarkService
|
||||
->expects(static::once())
|
||||
->method('search')
|
||||
->willReturnCallback(function (array $parameters, ?string $visibility): array {
|
||||
// Visibility is set through the container, not the call
|
||||
static::assertNull($visibility);
|
||||
|
||||
// No query parameters
|
||||
if (count($parameters) === 0) {
|
||||
return [
|
||||
(new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'),
|
||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld'),
|
||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'),
|
||||
];
|
||||
}
|
||||
})
|
||||
;
|
||||
|
||||
// Make sure that PluginManager hook is triggered
|
||||
$this->container->pluginManager
|
||||
->expects(static::at(0))
|
||||
->method('executeHooks')
|
||||
->willReturnCallback(function (string $hook, array $data, array $param): array {
|
||||
static::assertSame('render_picwall', $hook);
|
||||
static::assertArrayHasKey('linksToDisplay', $data);
|
||||
static::assertCount(2, $data['linksToDisplay']);
|
||||
static::assertSame(1, $data['linksToDisplay'][0]['id']);
|
||||
static::assertSame(3, $data['linksToDisplay'][1]['id']);
|
||||
static::assertArrayHasKey('loggedin', $param);
|
||||
|
||||
return $data;
|
||||
});
|
||||
|
||||
$result = $this->controller->index($request, $response);
|
||||
|
||||
static::assertSame(200, $result->getStatusCode());
|
||||
static::assertSame('picwall', (string) $result->getBody());
|
||||
static::assertSame('Picture wall - Shaarli', $assignedVariables['pagetitle']);
|
||||
static::assertCount(2, $assignedVariables['linksToDisplay']);
|
||||
|
||||
$link = $assignedVariables['linksToDisplay'][0];
|
||||
|
||||
static::assertSame(1, $link['id']);
|
||||
static::assertSame('http://url.tld', $link['url']);
|
||||
static::assertSame('thumb1', $link['thumbnail']);
|
||||
|
||||
$link = $assignedVariables['linksToDisplay'][1];
|
||||
|
||||
static::assertSame(3, $link['id']);
|
||||
static::assertSame('http://url3.tld', $link['url']);
|
||||
static::assertSame('thumb2', $link['thumbnail']);
|
||||
}
|
||||
|
||||
public function testControllerWithThumbnailsDisabled(): void
|
||||
{
|
||||
$this->expectException(ThumbnailsDisabledException::class);
|
||||
|
||||
$this->createValidContainerMockSet();
|
||||
|
||||
$request = $this->createMock(Request::class);
|
||||
$response = new Response();
|
||||
|
||||
// ConfigManager: thumbnails are disabled
|
||||
$this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) {
|
||||
if ($parameter === 'thumbnails.mode') {
|
||||
return Thumbnailer::MODE_NONE;
|
||||
}
|
||||
|
||||
return $default;
|
||||
});
|
||||
|
||||
$this->controller->index($request, $response);
|
||||
}
|
||||
|
||||
protected function createValidContainerMockSet(): void
|
||||
{
|
||||
$loginManager = $this->createMock(LoginManager::class);
|
||||
$this->container->loginManager = $loginManager;
|
||||
|
||||
// Config
|
||||
$conf = $this->createMock(ConfigManager::class);
|
||||
$this->container->conf = $conf;
|
||||
|
||||
// PageBuilder
|
||||
$pageBuilder = $this->createMock(PageBuilder::class);
|
||||
$pageBuilder
|
||||
->method('render')
|
||||
->willReturnCallback(function (string $template): string {
|
||||
return $template;
|
||||
})
|
||||
;
|
||||
$this->container->pageBuilder = $pageBuilder;
|
||||
|
||||
// Plugin Manager
|
||||
$pluginManager = $this->createMock(PluginManager::class);
|
||||
$this->container->pluginManager = $pluginManager;
|
||||
|
||||
// BookmarkService
|
||||
$bookmarkService = $this->createMock(BookmarkServiceInterface::class);
|
||||
$this->container->bookmarkService = $bookmarkService;
|
||||
|
||||
// Formatter
|
||||
$formatterFactory = $this->createMock(FormatterFactory::class);
|
||||
$formatterFactory
|
||||
->method('getFormatter')
|
||||
->willReturnCallback(function (string $type): BookmarkFormatter {
|
||||
if ($type === 'raw') {
|
||||
return new BookmarkRawFormatter($this->container->conf, true);
|
||||
}
|
||||
})
|
||||
;
|
||||
$this->container->formatterFactory = $formatterFactory;
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@
|
|||
</li>
|
||||
{if="$thumbnails_enabled"}
|
||||
<li class="pure-menu-item" id="shaarli-menu-picwall">
|
||||
<a href="./?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a>
|
||||
<a href="./picture-wall?{function="ltrim($searchcrits, '&')"}" class="pure-menu-link">{'Picture wall'|t}</a>
|
||||
</li>
|
||||
{/if}
|
||||
<li class="pure-menu-item" id="shaarli-menu-daily">
|
||||
|
|
|
@ -5,13 +5,7 @@
|
|||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
{if="!$thumbnails_enabled"}
|
||||
<div class="pure-g pure-alert pure-alert-warning page-single-alert">
|
||||
<div class="pure-u-1 center">
|
||||
{'Picture wall unavailable (thumbnails are disabled).'|t}
|
||||
</div>
|
||||
</div>
|
||||
{else}
|
||||
|
||||
{if="count($linksToDisplay)===0 && $is_logged_in"}
|
||||
<div class="pure-g pure-alert pure-alert-warning page-single-alert">
|
||||
<div class="pure-u-1 center">
|
||||
|
@ -56,7 +50,6 @@
|
|||
</div>
|
||||
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{include="page.footer"}
|
||||
<script src="js/thumbnails.min.js?v={$version_hash}"></script>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<li><a href="{$feedurl}?do=atom{$searchcrits}" class="nomobile">ATOM Feed</a></li>
|
||||
{/if}
|
||||
<li><a href="./?do=tagcloud">Tag cloud</a></li>
|
||||
<li><a href="./?do=picwall{$searchcrits}">Picture wall</a></li>
|
||||
<li><a href="./picture-wall{function="ltrim($searchcrits, '&')"}">Picture wall</a></li>
|
||||
<li><a href="./?do=daily">Daily</a></li>
|
||||
{loop="$plugins_header.buttons_toolbar"}
|
||||
<li><a
|
||||
|
|
Loading…
Reference in a new issue