diff options
-rw-r--r-- | application/front/controller/admin/ConfigureController.php | 120 | ||||
-rw-r--r-- | application/render/PageBuilder.php | 4 | ||||
-rw-r--r-- | doc/md/Translations.md | 2 | ||||
-rw-r--r-- | index.php | 86 | ||||
-rw-r--r-- | tests/front/controller/admin/ConfigureControllerTest.php | 252 | ||||
-rw-r--r-- | tests/front/controller/admin/FrontAdminControllerMockHelper.php | 23 | ||||
-rw-r--r-- | tests/front/controller/visitor/DailyControllerTest.php | 27 | ||||
-rw-r--r-- | tests/front/controller/visitor/FrontControllerMockHelper.php | 10 | ||||
-rw-r--r-- | tpl/default/configure.html | 2 | ||||
-rw-r--r-- | tpl/default/tools.html | 2 | ||||
-rw-r--r-- | tpl/vintage/configure.html | 2 | ||||
-rw-r--r-- | tpl/vintage/tools.html | 2 |
12 files changed, 427 insertions, 105 deletions
diff --git a/application/front/controller/admin/ConfigureController.php b/application/front/controller/admin/ConfigureController.php new file mode 100644 index 00000000..b1d32270 --- /dev/null +++ b/application/front/controller/admin/ConfigureController.php | |||
@@ -0,0 +1,120 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Shaarli\Front\Controller\Admin; | ||
6 | |||
7 | use Shaarli\Languages; | ||
8 | use Shaarli\Render\ThemeUtils; | ||
9 | use Shaarli\Thumbnailer; | ||
10 | use Slim\Http\Request; | ||
11 | use Slim\Http\Response; | ||
12 | use Throwable; | ||
13 | |||
14 | /** | ||
15 | * Class PasswordController | ||
16 | * | ||
17 | * Slim controller used to handle Shaarli configuration page (display + save new config). | ||
18 | */ | ||
19 | class ConfigureController extends ShaarliAdminController | ||
20 | { | ||
21 | /** | ||
22 | * GET /configure - Displays the configuration page | ||
23 | */ | ||
24 | public function index(Request $request, Response $response): Response | ||
25 | { | ||
26 | $this->assignView('title', $this->container->conf->get('general.title', 'Shaarli')); | ||
27 | $this->assignView('theme', $this->container->conf->get('resource.theme')); | ||
28 | $this->assignView( | ||
29 | 'theme_available', | ||
30 | ThemeUtils::getThemes($this->container->conf->get('resource.raintpl_tpl')) | ||
31 | ); | ||
32 | $this->assignView('formatter_available', ['default', 'markdown']); | ||
33 | list($continents, $cities) = generateTimeZoneData( | ||
34 | timezone_identifiers_list(), | ||
35 | $this->container->conf->get('general.timezone') | ||
36 | ); | ||
37 | $this->assignView('continents', $continents); | ||
38 | $this->assignView('cities', $cities); | ||
39 | $this->assignView('retrieve_description', $this->container->conf->get('general.retrieve_description', false)); | ||
40 | $this->assignView('private_links_default', $this->container->conf->get('privacy.default_private_links', false)); | ||
41 | $this->assignView( | ||
42 | 'session_protection_disabled', | ||
43 | $this->container->conf->get('security.session_protection_disabled', false) | ||
44 | ); | ||
45 | $this->assignView('enable_rss_permalinks', $this->container->conf->get('feed.rss_permalinks', false)); | ||
46 | $this->assignView('enable_update_check', $this->container->conf->get('updates.check_updates', true)); | ||
47 | $this->assignView('hide_public_links', $this->container->conf->get('privacy.hide_public_links', false)); | ||
48 | $this->assignView('api_enabled', $this->container->conf->get('api.enabled', true)); | ||
49 | $this->assignView('api_secret', $this->container->conf->get('api.secret')); | ||
50 | $this->assignView('languages', Languages::getAvailableLanguages()); | ||
51 | $this->assignView('gd_enabled', extension_loaded('gd')); | ||
52 | $this->assignView('thumbnails_mode', $this->container->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE)); | ||
53 | $this->assignView('pagetitle', t('Configure') .' - '. $this->container->conf->get('general.title', 'Shaarli')); | ||
54 | |||
55 | return $response->write($this->render('configure')); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * POST /configure - Update Shaarli's configuration | ||
60 | */ | ||
61 | public function save(Request $request, Response $response): Response | ||
62 | { | ||
63 | $this->checkToken($request); | ||
64 | |||
65 | $continent = $request->getParam('continent'); | ||
66 | $city = $request->getParam('city'); | ||
67 | $tz = 'UTC'; | ||
68 | if (null !== $continent && null !== $city && isTimeZoneValid($continent, $city)) { | ||
69 | $tz = $continent . '/' . $city; | ||
70 | } | ||
71 | |||
72 | $this->container->conf->set('general.timezone', $tz); | ||
73 | $this->container->conf->set('general.title', escape($request->getParam('title'))); | ||
74 | $this->container->conf->set('general.header_link', escape($request->getParam('titleLink'))); | ||
75 | $this->container->conf->set('general.retrieve_description', !empty($request->getParam('retrieveDescription'))); | ||
76 | $this->container->conf->set('resource.theme', escape($request->getParam('theme'))); | ||
77 | $this->container->conf->set( | ||
78 | 'security.session_protection_disabled', | ||
79 | !empty($request->getParam('disablesessionprotection')) | ||
80 | ); | ||
81 | $this->container->conf->set( | ||
82 | 'privacy.default_private_links', | ||
83 | !empty($request->getParam('privateLinkByDefault')) | ||
84 | ); | ||
85 | $this->container->conf->set('feed.rss_permalinks', !empty($request->getParam('enableRssPermalinks'))); | ||
86 | $this->container->conf->set('updates.check_updates', !empty($request->getParam('updateCheck'))); | ||
87 | $this->container->conf->set('privacy.hide_public_links', !empty($request->getParam('hidePublicLinks'))); | ||
88 | $this->container->conf->set('api.enabled', !empty($request->getParam('enableApi'))); | ||
89 | $this->container->conf->set('api.secret', escape($request->getParam('apiSecret'))); | ||
90 | $this->container->conf->set('formatter', escape($request->getParam('formatter'))); | ||
91 | |||
92 | if (!empty($request->getParam('language'))) { | ||
93 | $this->container->conf->set('translation.language', escape($request->getParam('language'))); | ||
94 | } | ||
95 | |||
96 | $thumbnailsMode = extension_loaded('gd') ? $request->getParam('enableThumbnails') : Thumbnailer::MODE_NONE; | ||
97 | if ($thumbnailsMode !== Thumbnailer::MODE_NONE | ||
98 | && $thumbnailsMode !== $this->container->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) | ||
99 | ) { | ||
100 | $this->saveWarningMessage(t( | ||
101 | 'You have enabled or changed thumbnails mode. ' | ||
102 | .'<a href="./?do=thumbs_update">Please synchronize them</a>.' | ||
103 | )); | ||
104 | } | ||
105 | $this->container->conf->set('thumbnails.mode', $thumbnailsMode); | ||
106 | |||
107 | try { | ||
108 | $this->container->conf->write($this->container->loginManager->isLoggedIn()); | ||
109 | $this->container->history->updateSettings(); | ||
110 | $this->container->pageCacheManager->invalidateCaches(); | ||
111 | } catch (Throwable $e) { | ||
112 | // TODO: translation + stacktrace | ||
113 | $this->saveErrorMessage('ERROR while writing config file after configuration update.'); | ||
114 | } | ||
115 | |||
116 | $this->saveSuccessMessage(t('Configuration was saved.')); | ||
117 | |||
118 | return $response->withRedirect('./configure'); | ||
119 | } | ||
120 | } | ||
diff --git a/application/render/PageBuilder.php b/application/render/PageBuilder.php index 264cd33b..d90ed58b 100644 --- a/application/render/PageBuilder.php +++ b/application/render/PageBuilder.php | |||
@@ -143,6 +143,10 @@ class PageBuilder | |||
143 | $this->tpl->assign('conf', $this->conf); | 143 | $this->tpl->assign('conf', $this->conf); |
144 | } | 144 | } |
145 | 145 | ||
146 | /** | ||
147 | * Affect variable after controller processing. | ||
148 | * Used for alert messages. | ||
149 | */ | ||
146 | protected function finalize(): void | 150 | protected function finalize(): void |
147 | { | 151 | { |
148 | // TODO: use the SessionManager | 152 | // TODO: use the SessionManager |
diff --git a/doc/md/Translations.md b/doc/md/Translations.md index 38878940..9a16075a 100644 --- a/doc/md/Translations.md +++ b/doc/md/Translations.md | |||
@@ -35,7 +35,7 @@ http://<replace_domain>/?nonope | |||
35 | http://<replace_domain>/?do=addlink | 35 | http://<replace_domain>/?do=addlink |
36 | http://<replace_domain>/?do=changepasswd | 36 | http://<replace_domain>/?do=changepasswd |
37 | http://<replace_domain>/?do=changetag | 37 | http://<replace_domain>/?do=changetag |
38 | http://<replace_domain>/?do=configure | 38 | http://<replace_domain>/configure |
39 | http://<replace_domain>/tools | 39 | http://<replace_domain>/tools |
40 | http://<replace_domain>/daily | 40 | http://<replace_domain>/daily |
41 | http://<replace_domain>/?post | 41 | http://<replace_domain>/?post |
@@ -513,88 +513,8 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM | |||
513 | 513 | ||
514 | // -------- User wants to change configuration | 514 | // -------- User wants to change configuration |
515 | if ($targetPage == Router::$PAGE_CONFIGURE) { | 515 | if ($targetPage == Router::$PAGE_CONFIGURE) { |
516 | if (!empty($_POST['title'])) { | 516 | header('Location: ./configure'); |
517 | if (!$sessionManager->checkToken($_POST['token'])) { | 517 | exit; |
518 | die(t('Wrong token.')); // Go away! | ||
519 | } | ||
520 | $tz = 'UTC'; | ||
521 | if (!empty($_POST['continent']) && !empty($_POST['city']) | ||
522 | && isTimeZoneValid($_POST['continent'], $_POST['city']) | ||
523 | ) { | ||
524 | $tz = $_POST['continent'] . '/' . $_POST['city']; | ||
525 | } | ||
526 | $conf->set('general.timezone', $tz); | ||
527 | $conf->set('general.title', escape($_POST['title'])); | ||
528 | $conf->set('general.header_link', escape($_POST['titleLink'])); | ||
529 | $conf->set('general.retrieve_description', !empty($_POST['retrieveDescription'])); | ||
530 | $conf->set('resource.theme', escape($_POST['theme'])); | ||
531 | $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); | ||
532 | $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); | ||
533 | $conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks'])); | ||
534 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); | ||
535 | $conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks'])); | ||
536 | $conf->set('api.enabled', !empty($_POST['enableApi'])); | ||
537 | $conf->set('api.secret', escape($_POST['apiSecret'])); | ||
538 | $conf->set('formatter', escape($_POST['formatter'])); | ||
539 | |||
540 | if (! empty($_POST['language'])) { | ||
541 | $conf->set('translation.language', escape($_POST['language'])); | ||
542 | } | ||
543 | |||
544 | $thumbnailsMode = extension_loaded('gd') ? $_POST['enableThumbnails'] : Thumbnailer::MODE_NONE; | ||
545 | if ($thumbnailsMode !== Thumbnailer::MODE_NONE | ||
546 | && $thumbnailsMode !== $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) | ||
547 | ) { | ||
548 | $_SESSION['warnings'][] = t( | ||
549 | 'You have enabled or changed thumbnails mode. ' | ||
550 | .'<a href="./?do=thumbs_update">Please synchronize them</a>.' | ||
551 | ); | ||
552 | } | ||
553 | $conf->set('thumbnails.mode', $thumbnailsMode); | ||
554 | |||
555 | try { | ||
556 | $conf->write($loginManager->isLoggedIn()); | ||
557 | $history->updateSettings(); | ||
558 | $pageCacheManager->invalidateCaches(); | ||
559 | } catch (Exception $e) { | ||
560 | error_log( | ||
561 | 'ERROR while writing config file after configuration update.' . PHP_EOL . | ||
562 | $e->getMessage() | ||
563 | ); | ||
564 | |||
565 | // TODO: do not handle exceptions/errors in JS. | ||
566 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'./?do=configure\';</script>'; | ||
567 | exit; | ||
568 | } | ||
569 | echo '<script>alert("'. t('Configuration was saved.') .'");document.location=\'./?do=configure\';</script>'; | ||
570 | exit; | ||
571 | } else { | ||
572 | // Show the configuration form. | ||
573 | $PAGE->assign('title', $conf->get('general.title')); | ||
574 | $PAGE->assign('theme', $conf->get('resource.theme')); | ||
575 | $PAGE->assign('theme_available', ThemeUtils::getThemes($conf->get('resource.raintpl_tpl'))); | ||
576 | $PAGE->assign('formatter_available', ['default', 'markdown']); | ||
577 | list($continents, $cities) = generateTimeZoneData( | ||
578 | timezone_identifiers_list(), | ||
579 | $conf->get('general.timezone') | ||
580 | ); | ||
581 | $PAGE->assign('continents', $continents); | ||
582 | $PAGE->assign('cities', $cities); | ||
583 | $PAGE->assign('retrieve_description', $conf->get('general.retrieve_description')); | ||
584 | $PAGE->assign('private_links_default', $conf->get('privacy.default_private_links', false)); | ||
585 | $PAGE->assign('session_protection_disabled', $conf->get('security.session_protection_disabled', false)); | ||
586 | $PAGE->assign('enable_rss_permalinks', $conf->get('feed.rss_permalinks', false)); | ||
587 | $PAGE->assign('enable_update_check', $conf->get('updates.check_updates', true)); | ||
588 | $PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false)); | ||
589 | $PAGE->assign('api_enabled', $conf->get('api.enabled', true)); | ||
590 | $PAGE->assign('api_secret', $conf->get('api.secret')); | ||
591 | $PAGE->assign('languages', Languages::getAvailableLanguages()); | ||
592 | $PAGE->assign('gd_enabled', extension_loaded('gd')); | ||
593 | $PAGE->assign('thumbnails_mode', $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE)); | ||
594 | $PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli')); | ||
595 | $PAGE->renderPage('configure'); | ||
596 | exit; | ||
597 | } | ||
598 | } | 518 | } |
599 | 519 | ||
600 | // -------- User wants to rename a tag or delete it | 520 | // -------- User wants to rename a tag or delete it |
@@ -1458,6 +1378,8 @@ $app->group('', function () { | |||
1458 | $this->get('/tools', '\Shaarli\Front\Controller\Admin\ToolsController:index')->setName('tools'); | 1378 | $this->get('/tools', '\Shaarli\Front\Controller\Admin\ToolsController:index')->setName('tools'); |
1459 | $this->get('/password', '\Shaarli\Front\Controller\Admin\PasswordController:index')->setName('password'); | 1379 | $this->get('/password', '\Shaarli\Front\Controller\Admin\PasswordController:index')->setName('password'); |
1460 | $this->post('/password', '\Shaarli\Front\Controller\Admin\PasswordController:change')->setName('changePassword'); | 1380 | $this->post('/password', '\Shaarli\Front\Controller\Admin\PasswordController:change')->setName('changePassword'); |
1381 | $this->get('/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:index')->setName('configure'); | ||
1382 | $this->post('/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:save')->setName('saveConfigure'); | ||
1461 | 1383 | ||
1462 | $this | 1384 | $this |
1463 | ->get('/links-per-page', '\Shaarli\Front\Controller\Admin\SessionFilterController:linksPerPage') | 1385 | ->get('/links-per-page', '\Shaarli\Front\Controller\Admin\SessionFilterController:linksPerPage') |
diff --git a/tests/front/controller/admin/ConfigureControllerTest.php b/tests/front/controller/admin/ConfigureControllerTest.php new file mode 100644 index 00000000..40304a18 --- /dev/null +++ b/tests/front/controller/admin/ConfigureControllerTest.php | |||
@@ -0,0 +1,252 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Shaarli\Front\Controller\Admin; | ||
6 | |||
7 | use PHPUnit\Framework\TestCase; | ||
8 | use Shaarli\Config\ConfigManager; | ||
9 | use Shaarli\Front\Exception\WrongTokenException; | ||
10 | use Shaarli\Security\SessionManager; | ||
11 | use Shaarli\Thumbnailer; | ||
12 | use Slim\Http\Request; | ||
13 | use Slim\Http\Response; | ||
14 | |||
15 | class ConfigureControllerTest extends TestCase | ||
16 | { | ||
17 | use FrontAdminControllerMockHelper; | ||
18 | |||
19 | /** @var ConfigureController */ | ||
20 | protected $controller; | ||
21 | |||
22 | public function setUp(): void | ||
23 | { | ||
24 | $this->createContainer(); | ||
25 | |||
26 | $this->controller = new ConfigureController($this->container); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * Test displaying configure page - it should display all config variables | ||
31 | */ | ||
32 | public function testIndex(): void | ||
33 | { | ||
34 | $assignedVariables = []; | ||
35 | $this->assignTemplateVars($assignedVariables); | ||
36 | |||
37 | $request = $this->createMock(Request::class); | ||
38 | $response = new Response(); | ||
39 | |||
40 | $this->container->conf = $this->createMock(ConfigManager::class); | ||
41 | $this->container->conf->method('get')->willReturnCallback(function (string $key) { | ||
42 | return $key; | ||
43 | }); | ||
44 | |||
45 | $result = $this->controller->index($request, $response); | ||
46 | |||
47 | static::assertSame(200, $result->getStatusCode()); | ||
48 | static::assertSame('configure', (string) $result->getBody()); | ||
49 | |||
50 | static::assertSame('Configure - general.title', $assignedVariables['pagetitle']); | ||
51 | static::assertSame('general.title', $assignedVariables['title']); | ||
52 | static::assertSame('resource.theme', $assignedVariables['theme']); | ||
53 | static::assertEmpty($assignedVariables['theme_available']); | ||
54 | static::assertSame(['default', 'markdown'], $assignedVariables['formatter_available']); | ||
55 | static::assertNotEmpty($assignedVariables['continents']); | ||
56 | static::assertNotEmpty($assignedVariables['cities']); | ||
57 | static::assertSame('general.retrieve_description', $assignedVariables['retrieve_description']); | ||
58 | static::assertSame('privacy.default_private_links', $assignedVariables['private_links_default']); | ||
59 | static::assertSame('security.session_protection_disabled', $assignedVariables['session_protection_disabled']); | ||
60 | static::assertSame('feed.rss_permalinks', $assignedVariables['enable_rss_permalinks']); | ||
61 | static::assertSame('updates.check_updates', $assignedVariables['enable_update_check']); | ||
62 | static::assertSame('privacy.hide_public_links', $assignedVariables['hide_public_links']); | ||
63 | static::assertSame('api.enabled', $assignedVariables['api_enabled']); | ||
64 | static::assertSame('api.secret', $assignedVariables['api_secret']); | ||
65 | static::assertCount(4, $assignedVariables['languages']); | ||
66 | static::assertArrayHasKey('gd_enabled', $assignedVariables); | ||
67 | static::assertSame('thumbnails.mode', $assignedVariables['thumbnails_mode']); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * Test posting a new config - make sure that everything is saved properly, without errors. | ||
72 | */ | ||
73 | public function testSaveNewConfig(): void | ||
74 | { | ||
75 | $session = []; | ||
76 | $this->assignSessionVars($session); | ||
77 | |||
78 | $parameters = [ | ||
79 | 'token' => 'token', | ||
80 | 'continent' => 'Europe', | ||
81 | 'city' => 'Moscow', | ||
82 | 'title' => 'Shaarli', | ||
83 | 'titleLink' => './', | ||
84 | 'retrieveDescription' => 'on', | ||
85 | 'theme' => 'vintage', | ||
86 | 'disablesessionprotection' => null, | ||
87 | 'privateLinkByDefault' => true, | ||
88 | 'enableRssPermalinks' => true, | ||
89 | 'updateCheck' => false, | ||
90 | 'hidePublicLinks' => 'on', | ||
91 | 'enableApi' => 'on', | ||
92 | 'apiSecret' => 'abcdef', | ||
93 | 'formatter' => 'markdown', | ||
94 | 'language' => 'fr', | ||
95 | 'enableThumbnails' => Thumbnailer::MODE_NONE, | ||
96 | ]; | ||
97 | |||
98 | $parametersConfigMapping = [ | ||
99 | 'general.timezone' => $parameters['continent'] . '/' . $parameters['city'], | ||
100 | 'general.title' => $parameters['title'], | ||
101 | 'general.header_link' => $parameters['titleLink'], | ||
102 | 'general.retrieve_description' => !!$parameters['retrieveDescription'], | ||
103 | 'resource.theme' => $parameters['theme'], | ||
104 | 'security.session_protection_disabled' => !!$parameters['disablesessionprotection'], | ||
105 | 'privacy.default_private_links' => !!$parameters['privateLinkByDefault'], | ||
106 | 'feed.rss_permalinks' => !!$parameters['enableRssPermalinks'], | ||
107 | 'updates.check_updates' => !!$parameters['updateCheck'], | ||
108 | 'privacy.hide_public_links' => !!$parameters['hidePublicLinks'], | ||
109 | 'api.enabled' => !!$parameters['enableApi'], | ||
110 | 'api.secret' => $parameters['apiSecret'], | ||
111 | 'formatter' => $parameters['formatter'], | ||
112 | 'translation.language' => $parameters['language'], | ||
113 | 'thumbnails.mode' => $parameters['enableThumbnails'], | ||
114 | ]; | ||
115 | |||
116 | $request = $this->createMock(Request::class); | ||
117 | $request | ||
118 | ->expects(static::atLeastOnce()) | ||
119 | ->method('getParam')->willReturnCallback(function (string $key) use ($parameters) { | ||
120 | if (false === array_key_exists($key, $parameters)) { | ||
121 | static::fail('unknown key: ' . $key); | ||
122 | } | ||
123 | |||
124 | return $parameters[$key]; | ||
125 | } | ||
126 | ); | ||
127 | |||
128 | $response = new Response(); | ||
129 | |||
130 | $this->container->conf = $this->createMock(ConfigManager::class); | ||
131 | $this->container->conf | ||
132 | ->expects(static::atLeastOnce()) | ||
133 | ->method('set') | ||
134 | ->willReturnCallback(function (string $key, $value) use ($parametersConfigMapping): void { | ||
135 | if (false === array_key_exists($key, $parametersConfigMapping)) { | ||
136 | static::fail('unknown key: ' . $key); | ||
137 | } | ||
138 | |||
139 | static::assertSame($parametersConfigMapping[$key], $value); | ||
140 | } | ||
141 | ); | ||
142 | |||
143 | $result = $this->controller->save($request, $response); | ||
144 | static::assertSame(302, $result->getStatusCode()); | ||
145 | static::assertSame(['./configure'], $result->getHeader('Location')); | ||
146 | |||
147 | static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); | ||
148 | static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); | ||
149 | static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); | ||
150 | static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * Test posting a new config - wrong token. | ||
155 | */ | ||
156 | public function testSaveNewConfigWrongToken(): void | ||
157 | { | ||
158 | $this->container->sessionManager = $this->createMock(SessionManager::class); | ||
159 | $this->container->sessionManager->method('checkToken')->willReturn(false); | ||
160 | |||
161 | $this->container->conf->expects(static::never())->method('set'); | ||
162 | $this->container->conf->expects(static::never())->method('write'); | ||
163 | |||
164 | $request = $this->createMock(Request::class); | ||
165 | $response = new Response(); | ||
166 | |||
167 | $this->expectException(WrongTokenException::class); | ||
168 | |||
169 | $this->controller->save($request, $response); | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * Test posting a new config - thumbnail activation. | ||
174 | */ | ||
175 | public function testSaveNewConfigThumbnailsActivation(): void | ||
176 | { | ||
177 | $session = []; | ||
178 | $this->assignSessionVars($session); | ||
179 | |||
180 | $request = $this->createMock(Request::class); | ||
181 | $request | ||
182 | ->expects(static::atLeastOnce()) | ||
183 | ->method('getParam')->willReturnCallback(function (string $key) { | ||
184 | if ('enableThumbnails' === $key) { | ||
185 | return Thumbnailer::MODE_ALL; | ||
186 | } | ||
187 | |||
188 | return $key; | ||
189 | }) | ||
190 | ; | ||
191 | $response = new Response(); | ||
192 | |||
193 | $result = $this->controller->save($request, $response); | ||
194 | |||
195 | static::assertSame(302, $result->getStatusCode()); | ||
196 | static::assertSame(['./configure'], $result->getHeader('Location')); | ||
197 | |||
198 | static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); | ||
199 | static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); | ||
200 | static::assertStringContainsString( | ||
201 | 'You have enabled or changed thumbnails mode', | ||
202 | $session[SessionManager::KEY_WARNING_MESSAGES][0] | ||
203 | ); | ||
204 | static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); | ||
205 | static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * Test posting a new config - thumbnail activation. | ||
210 | */ | ||
211 | public function testSaveNewConfigThumbnailsAlreadyActive(): void | ||
212 | { | ||
213 | $session = []; | ||
214 | $this->assignSessionVars($session); | ||
215 | |||
216 | $request = $this->createMock(Request::class); | ||
217 | $request | ||
218 | ->expects(static::atLeastOnce()) | ||
219 | ->method('getParam')->willReturnCallback(function (string $key) { | ||
220 | if ('enableThumbnails' === $key) { | ||
221 | return Thumbnailer::MODE_ALL; | ||
222 | } | ||
223 | |||
224 | return $key; | ||
225 | }) | ||
226 | ; | ||
227 | $response = new Response(); | ||
228 | |||
229 | $this->container->conf = $this->createMock(ConfigManager::class); | ||
230 | $this->container->conf | ||
231 | ->expects(static::atLeastOnce()) | ||
232 | ->method('get') | ||
233 | ->willReturnCallback(function (string $key): string { | ||
234 | if ('thumbnails.mode' === $key) { | ||
235 | return Thumbnailer::MODE_ALL; | ||
236 | } | ||
237 | |||
238 | return $key; | ||
239 | }) | ||
240 | ; | ||
241 | |||
242 | $result = $this->controller->save($request, $response); | ||
243 | |||
244 | static::assertSame(302, $result->getStatusCode()); | ||
245 | static::assertSame(['./configure'], $result->getHeader('Location')); | ||
246 | |||
247 | static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); | ||
248 | static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); | ||
249 | static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); | ||
250 | static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); | ||
251 | } | ||
252 | } | ||
diff --git a/tests/front/controller/admin/FrontAdminControllerMockHelper.php b/tests/front/controller/admin/FrontAdminControllerMockHelper.php index bd40c0c7..2b9f2ef1 100644 --- a/tests/front/controller/admin/FrontAdminControllerMockHelper.php +++ b/tests/front/controller/admin/FrontAdminControllerMockHelper.php | |||
@@ -6,6 +6,7 @@ namespace Shaarli\Front\Controller\Admin; | |||
6 | 6 | ||
7 | use Shaarli\Container\ShaarliTestContainer; | 7 | use Shaarli\Container\ShaarliTestContainer; |
8 | use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper; | 8 | use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper; |
9 | use Shaarli\History; | ||
9 | 10 | ||
10 | /** | 11 | /** |
11 | * Trait FrontControllerMockHelper | 12 | * Trait FrontControllerMockHelper |
@@ -27,7 +28,29 @@ trait FrontAdminControllerMockHelper | |||
27 | { | 28 | { |
28 | $this->parentCreateContainer(); | 29 | $this->parentCreateContainer(); |
29 | 30 | ||
31 | $this->container->history = $this->createMock(History::class); | ||
32 | |||
30 | $this->container->loginManager->method('isLoggedIn')->willReturn(true); | 33 | $this->container->loginManager->method('isLoggedIn')->willReturn(true); |
31 | $this->container->sessionManager->method('checkToken')->willReturn(true); | 34 | $this->container->sessionManager->method('checkToken')->willReturn(true); |
32 | } | 35 | } |
36 | |||
37 | |||
38 | /** | ||
39 | * Pass a reference of an array which will be populated by `sessionManager->setSessionParameter` | ||
40 | * calls during execution. | ||
41 | * | ||
42 | * @param mixed $variables Array reference to populate. | ||
43 | */ | ||
44 | protected function assignSessionVars(array &$variables): void | ||
45 | { | ||
46 | $this->container->sessionManager | ||
47 | ->expects(static::atLeastOnce()) | ||
48 | ->method('setSessionParameter') | ||
49 | ->willReturnCallback(function ($key, $value) use (&$variables) { | ||
50 | $variables[$key] = $value; | ||
51 | |||
52 | return $this->container->sessionManager; | ||
53 | }) | ||
54 | ; | ||
55 | } | ||
33 | } | 56 | } |
diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php index 872420fd..b802c62c 100644 --- a/tests/front/controller/visitor/DailyControllerTest.php +++ b/tests/front/controller/visitor/DailyControllerTest.php | |||
@@ -57,20 +57,20 @@ class DailyControllerTest extends TestCase | |||
57 | (new Bookmark()) | 57 | (new Bookmark()) |
58 | ->setId(1) | 58 | ->setId(1) |
59 | ->setUrl('http://url.tld') | 59 | ->setUrl('http://url.tld') |
60 | ->setTitle(static::generateContent(50)) | 60 | ->setTitle(static::generateString(50)) |
61 | ->setDescription(static::generateContent(500)) | 61 | ->setDescription(static::generateString(500)) |
62 | , | 62 | , |
63 | (new Bookmark()) | 63 | (new Bookmark()) |
64 | ->setId(2) | 64 | ->setId(2) |
65 | ->setUrl('http://url2.tld') | 65 | ->setUrl('http://url2.tld') |
66 | ->setTitle(static::generateContent(50)) | 66 | ->setTitle(static::generateString(50)) |
67 | ->setDescription(static::generateContent(500)) | 67 | ->setDescription(static::generateString(500)) |
68 | , | 68 | , |
69 | (new Bookmark()) | 69 | (new Bookmark()) |
70 | ->setId(3) | 70 | ->setId(3) |
71 | ->setUrl('http://url3.tld') | 71 | ->setUrl('http://url3.tld') |
72 | ->setTitle(static::generateContent(50)) | 72 | ->setTitle(static::generateString(50)) |
73 | ->setDescription(static::generateContent(500)) | 73 | ->setDescription(static::generateString(500)) |
74 | , | 74 | , |
75 | ]; | 75 | ]; |
76 | }) | 76 | }) |
@@ -194,8 +194,8 @@ class DailyControllerTest extends TestCase | |||
194 | (new Bookmark()) | 194 | (new Bookmark()) |
195 | ->setId(1) | 195 | ->setId(1) |
196 | ->setUrl('http://url.tld') | 196 | ->setUrl('http://url.tld') |
197 | ->setTitle(static::generateContent(50)) | 197 | ->setTitle(static::generateString(50)) |
198 | ->setDescription(static::generateContent(500)) | 198 | ->setDescription(static::generateString(500)) |
199 | , | 199 | , |
200 | ]; | 200 | ]; |
201 | }) | 201 | }) |
@@ -267,8 +267,8 @@ class DailyControllerTest extends TestCase | |||
267 | (new Bookmark()) | 267 | (new Bookmark()) |
268 | ->setId(2) | 268 | ->setId(2) |
269 | ->setUrl('http://url.tld') | 269 | ->setUrl('http://url.tld') |
270 | ->setTitle(static::generateContent(50)) | 270 | ->setTitle(static::generateString(50)) |
271 | ->setDescription(static::generateContent(5000)) | 271 | ->setDescription(static::generateString(5000)) |
272 | , | 272 | , |
273 | (new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'), | 273 | (new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'), |
274 | (new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'), | 274 | (new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'), |
@@ -473,11 +473,4 @@ class DailyControllerTest extends TestCase | |||
473 | static::assertFalse($assignedVariables['hide_timestamps']); | 473 | static::assertFalse($assignedVariables['hide_timestamps']); |
474 | static::assertCount(0, $assignedVariables['days']); | 474 | static::assertCount(0, $assignedVariables['days']); |
475 | } | 475 | } |
476 | |||
477 | protected static function generateContent(int $length): string | ||
478 | { | ||
479 | // bin2hex(random_bytes) generates string twice as long as given parameter | ||
480 | $length = (int) ceil($length / 2); | ||
481 | return bin2hex(random_bytes($length)); | ||
482 | } | ||
483 | } | 476 | } |
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php index d16b6949..fecd0c82 100644 --- a/tests/front/controller/visitor/FrontControllerMockHelper.php +++ b/tests/front/controller/visitor/FrontControllerMockHelper.php | |||
@@ -42,7 +42,7 @@ trait FrontControllerMockHelper | |||
42 | // Config | 42 | // Config |
43 | $this->container->conf = $this->createMock(ConfigManager::class); | 43 | $this->container->conf = $this->createMock(ConfigManager::class); |
44 | $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { | 44 | $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { |
45 | return $default; | 45 | return $default === null ? $parameter : $default; |
46 | }); | 46 | }); |
47 | 47 | ||
48 | // PageBuilder | 48 | // PageBuilder |
@@ -101,6 +101,14 @@ trait FrontControllerMockHelper | |||
101 | ; | 101 | ; |
102 | } | 102 | } |
103 | 103 | ||
104 | protected static function generateString(int $length): string | ||
105 | { | ||
106 | // bin2hex(random_bytes) generates string twice as long as given parameter | ||
107 | $length = (int) ceil($length / 2); | ||
108 | |||
109 | return bin2hex(random_bytes($length)); | ||
110 | } | ||
111 | |||
104 | /** | 112 | /** |
105 | * Force to be used in PHPUnit context. | 113 | * Force to be used in PHPUnit context. |
106 | */ | 114 | */ |
diff --git a/tpl/default/configure.html b/tpl/default/configure.html index 9b6a9c46..46bef052 100644 --- a/tpl/default/configure.html +++ b/tpl/default/configure.html | |||
@@ -35,7 +35,7 @@ | |||
35 | <div class="form-label"> | 35 | <div class="form-label"> |
36 | <label for="titleLink"> | 36 | <label for="titleLink"> |
37 | <span class="label-name">{'Home link'|t}</span><br> | 37 | <span class="label-name">{'Home link'|t}</span><br> |
38 | <span class="label-desc">{'Default value'|t}: ?</span> | 38 | <span class="label-desc">{'Default value'|t}: ./</span> |
39 | </label> | 39 | </label> |
40 | </div> | 40 | </div> |
41 | </div> | 41 | </div> |
diff --git a/tpl/default/tools.html b/tpl/default/tools.html index 4a490963..0135c480 100644 --- a/tpl/default/tools.html +++ b/tpl/default/tools.html | |||
@@ -11,7 +11,7 @@ | |||
11 | <div class="pure-u-lg-1-3 pure-u-22-24 page-form page-form-light"> | 11 | <div class="pure-u-lg-1-3 pure-u-22-24 page-form page-form-light"> |
12 | <h2 class="window-title">{'Settings'|t}</h2> | 12 | <h2 class="window-title">{'Settings'|t}</h2> |
13 | <div class="tools-item"> | 13 | <div class="tools-item"> |
14 | <a href="./?do=configure" title="{'Change Shaarli settings: title, timezone, etc.'|t}"> | 14 | <a href="./configure" title="{'Change Shaarli settings: title, timezone, etc.'|t}"> |
15 | <span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Configure your Shaarli'|t}</span> | 15 | <span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Configure your Shaarli'|t}</span> |
16 | </a> | 16 | </a> |
17 | </div> | 17 | </div> |
diff --git a/tpl/vintage/configure.html b/tpl/vintage/configure.html index 8d20ea80..a87fdce7 100644 --- a/tpl/vintage/configure.html +++ b/tpl/vintage/configure.html | |||
@@ -16,7 +16,7 @@ | |||
16 | <tr> | 16 | <tr> |
17 | <td><b>Home link:</b></td> | 17 | <td><b>Home link:</b></td> |
18 | <td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label | 18 | <td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label |
19 | for="titleLink">(default value is: ?)</label></td> | 19 | for="titleLink">(default value is: ./)</label></td> |
20 | </tr> | 20 | </tr> |
21 | 21 | ||
22 | <tr> | 22 | <tr> |
diff --git a/tpl/vintage/tools.html b/tpl/vintage/tools.html index 174dc88f..0d8fcdec 100644 --- a/tpl/vintage/tools.html +++ b/tpl/vintage/tools.html | |||
@@ -5,7 +5,7 @@ | |||
5 | <div id="pageheader"> | 5 | <div id="pageheader"> |
6 | {include="page.header"} | 6 | {include="page.header"} |
7 | <div id="toolsdiv"> | 7 | <div id="toolsdiv"> |
8 | <a href="./?do=configure"><b>Configure your Shaarli</b><span>: Change Title, timezone...</span></a> | 8 | <a href="./configure"><b>Configure your Shaarli</b><span>: Change Title, timezone...</span></a> |
9 | <br><br> | 9 | <br><br> |
10 | <a href="./?do=pluginadmin"><b>Plugin administration</b><span>: Enable, disable and configure plugins.</span></a> | 10 | <a href="./?do=pluginadmin"><b>Plugin administration</b><span>: Enable, disable and configure plugins.</span></a> |
11 | <br><br> | 11 | <br><br> |