aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2020-08-13 11:08:13 +0200
committerArthurHoaro <arthur@hoa.ro>2020-08-13 11:08:13 +0200
commitbedbb845eec20363b928b424143787dbe988eefe (patch)
tree6b835ca247e39157b333323a539dde3c410c08f5
parent1a68ae5a29bc33ab80c9cfbe043cb1213551533c (diff)
downloadShaarli-bedbb845eec20363b928b424143787dbe988eefe.tar.gz
Shaarli-bedbb845eec20363b928b424143787dbe988eefe.tar.zst
Shaarli-bedbb845eec20363b928b424143787dbe988eefe.zip
Move all admin controller into a dedicated group
Also handle authentication check in a new middleware for the admin group.
-rw-r--r--application/front/ShaarliAdminMiddleware.php27
-rw-r--r--application/front/ShaarliMiddleware.php12
-rw-r--r--application/front/controller/admin/SessionFilterController.php13
-rw-r--r--application/front/controller/admin/ShaarliAdminController.php9
-rw-r--r--application/front/controller/visitor/PublicSessionFilterController.php13
-rw-r--r--application/legacy/LegacyController.php2
-rw-r--r--index.php54
-rw-r--r--tests/front/ShaarliAdminMiddlewareTest.php100
-rw-r--r--tests/front/ShaarliMiddlewareTest.php2
-rw-r--r--tests/front/controller/admin/SessionFilterControllerTest.php51
-rw-r--r--tests/front/controller/admin/ShaarliAdminControllerTest.php15
-rw-r--r--tests/front/controller/visitor/PublicSessionFilterControllerTest.php51
-rw-r--r--tests/legacy/LegacyControllerTest.php4
-rw-r--r--tpl/default/linklist.paging.html4
-rw-r--r--tpl/default/page.header.html4
-rw-r--r--tpl/vintage/linklist.paging.html2
-rw-r--r--tpl/vintage/page.header.html2
17 files changed, 241 insertions, 124 deletions
diff --git a/application/front/ShaarliAdminMiddleware.php b/application/front/ShaarliAdminMiddleware.php
new file mode 100644
index 00000000..35ce4a3b
--- /dev/null
+++ b/application/front/ShaarliAdminMiddleware.php
@@ -0,0 +1,27 @@
1<?php
2
3namespace Shaarli\Front;
4
5use Slim\Http\Request;
6use Slim\Http\Response;
7
8/**
9 * Middleware used for controller requiring to be authenticated.
10 * It extends ShaarliMiddleware, and just make sure that the user is authenticated.
11 * Otherwise, it redirects to the login page.
12 */
13class ShaarliAdminMiddleware extends ShaarliMiddleware
14{
15 public function __invoke(Request $request, Response $response, callable $next): Response
16 {
17 $this->initBasePath($request);
18
19 if (true !== $this->container->loginManager->isLoggedIn()) {
20 $returnUrl = urlencode($this->container->environment['REQUEST_URI']);
21
22 return $response->withRedirect($this->container->basePath . '/login?returnurl=' . $returnUrl);
23 }
24
25 return parent::__invoke($request, $response, $next);
26 }
27}
diff --git a/application/front/ShaarliMiddleware.php b/application/front/ShaarliMiddleware.php
index 707489d0..a2a3837b 100644
--- a/application/front/ShaarliMiddleware.php
+++ b/application/front/ShaarliMiddleware.php
@@ -40,7 +40,7 @@ class ShaarliMiddleware
40 */ 40 */
41 public function __invoke(Request $request, Response $response, callable $next): Response 41 public function __invoke(Request $request, Response $response, callable $next): Response
42 { 42 {
43 $this->container->basePath = rtrim($request->getUri()->getBasePath(), '/'); 43 $this->initBasePath($request);
44 44
45 try { 45 try {
46 if (!is_file($this->container->conf->getConfigFileExt()) 46 if (!is_file($this->container->conf->getConfigFileExt())
@@ -125,4 +125,14 @@ class ShaarliMiddleware
125 125
126 return true; 126 return true;
127 } 127 }
128
129 /**
130 * Initialize the URL base path if it hasn't been defined yet.
131 */
132 protected function initBasePath(Request $request): void
133 {
134 if (null === $this->container->basePath) {
135 $this->container->basePath = rtrim($request->getUri()->getBasePath(), '/');
136 }
137 }
128} 138}
diff --git a/application/front/controller/admin/SessionFilterController.php b/application/front/controller/admin/SessionFilterController.php
index 081c0ba0..d9a7a2e0 100644
--- a/application/front/controller/admin/SessionFilterController.php
+++ b/application/front/controller/admin/SessionFilterController.php
@@ -17,7 +17,7 @@ use Slim\Http\Response;
17class SessionFilterController extends ShaarliAdminController 17class SessionFilterController extends ShaarliAdminController
18{ 18{
19 /** 19 /**
20 * GET /visibility: allows to display only public or only private bookmarks in linklist 20 * GET /admin/visibility: allows to display only public or only private bookmarks in linklist
21 */ 21 */
22 public function visibility(Request $request, Response $response, array $args): Response 22 public function visibility(Request $request, Response $response, array $args): Response
23 { 23 {
@@ -46,16 +46,5 @@ class SessionFilterController extends ShaarliAdminController
46 return $this->redirectFromReferer($request, $response, ['visibility']); 46 return $this->redirectFromReferer($request, $response, ['visibility']);
47 } 47 }
48 48
49 /**
50 * GET /untagged-only: allows to display only bookmarks without any tag
51 */
52 public function untaggedOnly(Request $request, Response $response): Response
53 {
54 $this->container->sessionManager->setSessionParameter(
55 SessionManager::KEY_UNTAGGED_ONLY,
56 empty($this->container->sessionManager->getSessionParameter(SessionManager::KEY_UNTAGGED_ONLY))
57 );
58 49
59 return $this->redirectFromReferer($request, $response, ['untaggedonly', 'untagged-only']);
60 }
61} 50}
diff --git a/application/front/controller/admin/ShaarliAdminController.php b/application/front/controller/admin/ShaarliAdminController.php
index 3bc5bb6b..3b5939bb 100644
--- a/application/front/controller/admin/ShaarliAdminController.php
+++ b/application/front/controller/admin/ShaarliAdminController.php
@@ -22,15 +22,6 @@ use Slim\Http\Request;
22 */ 22 */
23abstract class ShaarliAdminController extends ShaarliVisitorController 23abstract class ShaarliAdminController extends ShaarliVisitorController
24{ 24{
25 public function __construct(ShaarliContainer $container)
26 {
27 parent::__construct($container);
28
29 if (true !== $this->container->loginManager->isLoggedIn()) {
30 throw new UnauthorizedException();
31 }
32 }
33
34 /** 25 /**
35 * Any persistent action to the config or data store must check the XSRF token validity. 26 * Any persistent action to the config or data store must check the XSRF token validity.
36 */ 27 */
diff --git a/application/front/controller/visitor/PublicSessionFilterController.php b/application/front/controller/visitor/PublicSessionFilterController.php
index 35da0c5f..1a66362d 100644
--- a/application/front/controller/visitor/PublicSessionFilterController.php
+++ b/application/front/controller/visitor/PublicSessionFilterController.php
@@ -30,4 +30,17 @@ class PublicSessionFilterController extends ShaarliVisitorController
30 30
31 return $this->redirectFromReferer($request, $response, ['linksperpage'], ['nb']); 31 return $this->redirectFromReferer($request, $response, ['linksperpage'], ['nb']);
32 } 32 }
33
34 /**
35 * GET /untagged-only: allows to display only bookmarks without any tag
36 */
37 public function untaggedOnly(Request $request, Response $response): Response
38 {
39 $this->container->sessionManager->setSessionParameter(
40 SessionManager::KEY_UNTAGGED_ONLY,
41 empty($this->container->sessionManager->getSessionParameter(SessionManager::KEY_UNTAGGED_ONLY))
42 );
43
44 return $this->redirectFromReferer($request, $response, ['untaggedonly', 'untagged-only']);
45 }
33} 46}
diff --git a/application/legacy/LegacyController.php b/application/legacy/LegacyController.php
index a97b07b1..26465d2c 100644
--- a/application/legacy/LegacyController.php
+++ b/application/legacy/LegacyController.php
@@ -67,7 +67,7 @@ class LegacyController extends ShaarliVisitorController
67 /** Legacy route: ?do=logout */ 67 /** Legacy route: ?do=logout */
68 protected function logout(Request $request, Response $response): Response 68 protected function logout(Request $request, Response $response): Response
69 { 69 {
70 return $this->redirect($response, '/logout'); 70 return $this->redirect($response, '/admin/logout');
71 } 71 }
72 72
73 /** Legacy route: ?do=picwall */ 73 /** Legacy route: ?do=picwall */
diff --git a/index.php b/index.php
index 24c273be..e7471823 100644
--- a/index.php
+++ b/index.php
@@ -95,39 +95,41 @@ $app->group('', function () {
95 $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\Visitor\TagController:addTag'); 95 $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\Visitor\TagController:addTag');
96 $this->get('/remove-tag/{tag}', '\Shaarli\Front\Controller\Visitor\TagController:removeTag'); 96 $this->get('/remove-tag/{tag}', '\Shaarli\Front\Controller\Visitor\TagController:removeTag');
97 $this->get('/links-per-page', '\Shaarli\Front\Controller\Visitor\PublicSessionFilterController:linksPerPage'); 97 $this->get('/links-per-page', '\Shaarli\Front\Controller\Visitor\PublicSessionFilterController:linksPerPage');
98 $this->get('/untagged-only', '\Shaarli\Front\Controller\Admin\PublicSessionFilterController:untaggedOnly');
99})->add('\Shaarli\Front\ShaarliMiddleware');
98 100
99 /* -- LOGGED IN -- */ 101$app->group('/admin', function () {
100 $this->get('/logout', '\Shaarli\Front\Controller\Admin\LogoutController:index'); 102 $this->get('/logout', '\Shaarli\Front\Controller\Admin\LogoutController:index');
101 $this->get('/admin/tools', '\Shaarli\Front\Controller\Admin\ToolsController:index'); 103 $this->get('/tools', '\Shaarli\Front\Controller\Admin\ToolsController:index');
102 $this->get('/admin/password', '\Shaarli\Front\Controller\Admin\PasswordController:index'); 104 $this->get('/password', '\Shaarli\Front\Controller\Admin\PasswordController:index');
103 $this->post('/admin/password', '\Shaarli\Front\Controller\Admin\PasswordController:change'); 105 $this->post('/password', '\Shaarli\Front\Controller\Admin\PasswordController:change');
104 $this->get('/admin/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:index'); 106 $this->get('/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:index');
105 $this->post('/admin/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:save'); 107 $this->post('/configure', '\Shaarli\Front\Controller\Admin\ConfigureController:save');
106 $this->get('/admin/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:index'); 108 $this->get('/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:index');
107 $this->post('/admin/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:save'); 109 $this->post('/tags', '\Shaarli\Front\Controller\Admin\ManageTagController:save');
108 $this->get('/admin/add-shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:addShaare'); 110 $this->get('/add-shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:addShaare');
109 $this->get('/admin/shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:displayCreateForm'); 111 $this->get('/shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:displayCreateForm');
110 $this->get('/admin/shaare/{id:[0-9]+}', '\Shaarli\Front\Controller\Admin\ManageShaareController:displayEditForm'); 112 $this->get('/shaare/{id:[0-9]+}', '\Shaarli\Front\Controller\Admin\ManageShaareController:displayEditForm');
111 $this->post('/admin/shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:save'); 113 $this->post('/shaare', '\Shaarli\Front\Controller\Admin\ManageShaareController:save');
112 $this->get('/admin/shaare/delete', '\Shaarli\Front\Controller\Admin\ManageShaareController:deleteBookmark'); 114 $this->get('/shaare/delete', '\Shaarli\Front\Controller\Admin\ManageShaareController:deleteBookmark');
113 $this->get('/admin/shaare/visibility', '\Shaarli\Front\Controller\Admin\ManageShaareController:changeVisibility'); 115 $this->get('/shaare/visibility', '\Shaarli\Front\Controller\Admin\ManageShaareController:changeVisibility');
114 $this->get('/admin/shaare/{id:[0-9]+}/pin', '\Shaarli\Front\Controller\Admin\ManageShaareController:pinBookmark'); 116 $this->get('/shaare/{id:[0-9]+}/pin', '\Shaarli\Front\Controller\Admin\ManageShaareController:pinBookmark');
115 $this->patch( 117 $this->patch(
116 '/admin/shaare/{id:[0-9]+}/update-thumbnail', 118 '/shaare/{id:[0-9]+}/update-thumbnail',
117 '\Shaarli\Front\Controller\Admin\ThumbnailsController:ajaxUpdate' 119 '\Shaarli\Front\Controller\Admin\ThumbnailsController:ajaxUpdate'
118 ); 120 );
119 $this->get('/admin/export', '\Shaarli\Front\Controller\Admin\ExportController:index'); 121 $this->get('/export', '\Shaarli\Front\Controller\Admin\ExportController:index');
120 $this->post('/admin/export', '\Shaarli\Front\Controller\Admin\ExportController:export'); 122 $this->post('/export', '\Shaarli\Front\Controller\Admin\ExportController:export');
121 $this->get('/admin/import', '\Shaarli\Front\Controller\Admin\ImportController:index'); 123 $this->get('/import', '\Shaarli\Front\Controller\Admin\ImportController:index');
122 $this->post('/admin/import', '\Shaarli\Front\Controller\Admin\ImportController:import'); 124 $this->post('/import', '\Shaarli\Front\Controller\Admin\ImportController:import');
123 $this->get('/admin/plugins', '\Shaarli\Front\Controller\Admin\PluginsController:index'); 125 $this->get('/plugins', '\Shaarli\Front\Controller\Admin\PluginsController:index');
124 $this->post('/admin/plugins', '\Shaarli\Front\Controller\Admin\PluginsController:save'); 126 $this->post('/plugins', '\Shaarli\Front\Controller\Admin\PluginsController:save');
125 $this->get('/admin/token', '\Shaarli\Front\Controller\Admin\TokenController:getToken'); 127 $this->get('/token', '\Shaarli\Front\Controller\Admin\TokenController:getToken');
126 $this->get('/admin/thumbnails', '\Shaarli\Front\Controller\Admin\ThumbnailsController:index'); 128 $this->get('/thumbnails', '\Shaarli\Front\Controller\Admin\ThumbnailsController:index');
127 129
128 $this->get('/visibility/{visibility}', '\Shaarli\Front\Controller\Admin\SessionFilterController:visibility'); 130 $this->get('/visibility/{visibility}', '\Shaarli\Front\Controller\Admin\SessionFilterController:visibility');
129 $this->get('/untagged-only', '\Shaarli\Front\Controller\Admin\SessionFilterController:untaggedOnly'); 131})->add('\Shaarli\Front\ShaarliAdminMiddleware');
130})->add('\Shaarli\Front\ShaarliMiddleware'); 132
131 133
132// REST API routes 134// REST API routes
133$app->group('/api/v1', function () { 135$app->group('/api/v1', function () {
diff --git a/tests/front/ShaarliAdminMiddlewareTest.php b/tests/front/ShaarliAdminMiddlewareTest.php
new file mode 100644
index 00000000..7451330b
--- /dev/null
+++ b/tests/front/ShaarliAdminMiddlewareTest.php
@@ -0,0 +1,100 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Config\ConfigManager;
9use Shaarli\Container\ShaarliContainer;
10use Shaarli\Security\LoginManager;
11use Shaarli\Updater\Updater;
12use Slim\Http\Request;
13use Slim\Http\Response;
14use Slim\Http\Uri;
15
16class ShaarliAdminMiddlewareTest extends TestCase
17{
18 protected const TMP_MOCK_FILE = '.tmp';
19
20 /** @var ShaarliContainer */
21 protected $container;
22
23 /** @var ShaarliMiddleware */
24 protected $middleware;
25
26 public function setUp(): void
27 {
28 $this->container = $this->createMock(ShaarliContainer::class);
29
30 touch(static::TMP_MOCK_FILE);
31
32 $this->container->conf = $this->createMock(ConfigManager::class);
33 $this->container->conf->method('getConfigFileExt')->willReturn(static::TMP_MOCK_FILE);
34
35 $this->container->loginManager = $this->createMock(LoginManager::class);
36 $this->container->updater = $this->createMock(Updater::class);
37
38 $this->container->environment = ['REQUEST_URI' => 'http://shaarli/subfolder/path'];
39
40 $this->middleware = new ShaarliAdminMiddleware($this->container);
41 }
42
43 public function tearDown(): void
44 {
45 unlink(static::TMP_MOCK_FILE);
46 }
47
48 /**
49 * Try to access an admin controller while logged out -> redirected to login page.
50 */
51 public function testMiddlewareWhileLoggedOut(): void
52 {
53 $this->container->loginManager->expects(static::once())->method('isLoggedIn')->willReturn(false);
54
55 $request = $this->createMock(Request::class);
56 $request->method('getUri')->willReturnCallback(function (): Uri {
57 $uri = $this->createMock(Uri::class);
58 $uri->method('getBasePath')->willReturn('/subfolder');
59
60 return $uri;
61 });
62
63 $response = new Response();
64
65 /** @var Response $result */
66 $result = $this->middleware->__invoke($request, $response, function () {});
67
68 static::assertSame(302, $result->getStatusCode());
69 static::assertSame(
70 '/subfolder/login?returnurl=' . urlencode('http://shaarli/subfolder/path'),
71 $result->getHeader('location')[0]
72 );
73 }
74
75 /**
76 * Process controller while logged in.
77 */
78 public function testMiddlewareWhileLoggedIn(): void
79 {
80 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
81
82 $request = $this->createMock(Request::class);
83 $request->method('getUri')->willReturnCallback(function (): Uri {
84 $uri = $this->createMock(Uri::class);
85 $uri->method('getBasePath')->willReturn('/subfolder');
86
87 return $uri;
88 });
89
90 $response = new Response();
91 $controller = function (Request $request, Response $response): Response {
92 return $response->withStatus(418); // I'm a tea pot
93 };
94
95 /** @var Response $result */
96 $result = $this->middleware->__invoke($request, $response, $controller);
97
98 static::assertSame(418, $result->getStatusCode());
99 }
100}
diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php
index 09bebd04..d435f506 100644
--- a/tests/front/ShaarliMiddlewareTest.php
+++ b/tests/front/ShaarliMiddlewareTest.php
@@ -43,7 +43,7 @@ class ShaarliMiddlewareTest extends TestCase
43 $this->middleware = new ShaarliMiddleware($this->container); 43 $this->middleware = new ShaarliMiddleware($this->container);
44 } 44 }
45 45
46 public function tearDown() 46 public function tearDown(): void
47 { 47 {
48 unlink(static::TMP_MOCK_FILE); 48 unlink(static::TMP_MOCK_FILE);
49 } 49 }
diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index 7d5511ed..d306c6e9 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -174,55 +174,4 @@ class SessionFilterControllerTest extends TestCase
174 static::assertSame(302, $result->getStatusCode()); 174 static::assertSame(302, $result->getStatusCode());
175 static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); 175 static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
176 } 176 }
177
178 /**
179 * Untagged only - valid call
180 */
181 public function testUntaggedOnly(): void
182 {
183 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
184
185 $request = $this->createMock(Request::class);
186 $response = new Response();
187
188 $this->container->sessionManager
189 ->expects(static::once())
190 ->method('setSessionParameter')
191 ->with(SessionManager::KEY_UNTAGGED_ONLY, true)
192 ;
193
194 $result = $this->controller->untaggedOnly($request, $response);
195
196 static::assertInstanceOf(Response::class, $result);
197 static::assertSame(302, $result->getStatusCode());
198 static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
199 }
200
201 /**
202 * Untagged only - toggle off
203 */
204 public function testUntaggedOnlyToggleOff(): void
205 {
206 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
207
208 $request = $this->createMock(Request::class);
209 $response = new Response();
210
211 $this->container->sessionManager
212 ->method('getSessionParameter')
213 ->with(SessionManager::KEY_UNTAGGED_ONLY)
214 ->willReturn(true)
215 ;
216 $this->container->sessionManager
217 ->expects(static::once())
218 ->method('setSessionParameter')
219 ->with(SessionManager::KEY_UNTAGGED_ONLY, false)
220 ;
221
222 $result = $this->controller->untaggedOnly($request, $response);
223
224 static::assertInstanceOf(Response::class, $result);
225 static::assertSame(302, $result->getStatusCode());
226 static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
227 }
228} 177}
diff --git a/tests/front/controller/admin/ShaarliAdminControllerTest.php b/tests/front/controller/admin/ShaarliAdminControllerTest.php
index 7c5f50a6..fff427cb 100644
--- a/tests/front/controller/admin/ShaarliAdminControllerTest.php
+++ b/tests/front/controller/admin/ShaarliAdminControllerTest.php
@@ -5,9 +5,7 @@ declare(strict_types=1);
5namespace Shaarli\Front\Controller\Admin; 5namespace Shaarli\Front\Controller\Admin;
6 6
7use PHPUnit\Framework\TestCase; 7use PHPUnit\Framework\TestCase;
8use Shaarli\Front\Exception\UnauthorizedException;
9use Shaarli\Front\Exception\WrongTokenException; 8use Shaarli\Front\Exception\WrongTokenException;
10use Shaarli\Security\LoginManager;
11use Shaarli\Security\SessionManager; 9use Shaarli\Security\SessionManager;
12use Slim\Http\Request; 10use Slim\Http\Request;
13 11
@@ -53,19 +51,6 @@ class ShaarliAdminControllerTest extends TestCase
53 } 51 }
54 52
55 /** 53 /**
56 * Creating an instance of an admin controller while logged out should raise an exception.
57 */
58 public function testInstantiateWhileLoggedOut(): void
59 {
60 $this->expectException(UnauthorizedException::class);
61
62 $this->container->loginManager = $this->createMock(LoginManager::class);
63 $this->container->loginManager->method('isLoggedIn')->willReturn(false);
64
65 $this->controller = new class($this->container) extends ShaarliAdminController {};
66 }
67
68 /**
69 * Trigger controller's checkToken with a valid token. 54 * Trigger controller's checkToken with a valid token.
70 */ 55 */
71 public function testCheckTokenWithValidToken(): void 56 public function testCheckTokenWithValidToken(): void
diff --git a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
index 3aa1cb99..06352750 100644
--- a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
+++ b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
@@ -68,4 +68,55 @@ class PublicSessionFilterControllerTest extends TestCase
68 static::assertSame(302, $result->getStatusCode()); 68 static::assertSame(302, $result->getStatusCode());
69 static::assertSame(['/subfolder/'], $result->getHeader('location')); 69 static::assertSame(['/subfolder/'], $result->getHeader('location'));
70 } 70 }
71
72 /**
73 * Untagged only - valid call
74 */
75 public function testUntaggedOnly(): void
76 {
77 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
78
79 $request = $this->createMock(Request::class);
80 $response = new Response();
81
82 $this->container->sessionManager
83 ->expects(static::once())
84 ->method('setSessionParameter')
85 ->with(SessionManager::KEY_UNTAGGED_ONLY, true)
86 ;
87
88 $result = $this->controller->untaggedOnly($request, $response);
89
90 static::assertInstanceOf(Response::class, $result);
91 static::assertSame(302, $result->getStatusCode());
92 static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
93 }
94
95 /**
96 * Untagged only - toggle off
97 */
98 public function testUntaggedOnlyToggleOff(): void
99 {
100 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
101
102 $request = $this->createMock(Request::class);
103 $response = new Response();
104
105 $this->container->sessionManager
106 ->method('getSessionParameter')
107 ->with(SessionManager::KEY_UNTAGGED_ONLY)
108 ->willReturn(true)
109 ;
110 $this->container->sessionManager
111 ->expects(static::once())
112 ->method('setSessionParameter')
113 ->with(SessionManager::KEY_UNTAGGED_ONLY, false)
114 ;
115
116 $result = $this->controller->untaggedOnly($request, $response);
117
118 static::assertInstanceOf(Response::class, $result);
119 static::assertSame(302, $result->getStatusCode());
120 static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
121 }
71} 122}
diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
index ff4520a3..759a5b2a 100644
--- a/tests/legacy/LegacyControllerTest.php
+++ b/tests/legacy/LegacyControllerTest.php
@@ -73,8 +73,8 @@ class LegacyControllerTest extends TestCase
73 ['addlink', [], '/login', false], 73 ['addlink', [], '/login', false],
74 ['login', [], '/login', true], 74 ['login', [], '/login', true],
75 ['login', [], '/login', false], 75 ['login', [], '/login', false],
76 ['logout', [], '/logout', true], 76 ['logout', [], '/admin/logout', true],
77 ['logout', [], '/logout', false], 77 ['logout', [], '/admin/logout', false],
78 ['picwall', [], '/picture-wall', false], 78 ['picwall', [], '/picture-wall', false],
79 ['picwall', [], '/picture-wall', true], 79 ['picwall', [], '/picture-wall', true],
80 ['tagcloud', [], '/tags/cloud', false], 80 ['tagcloud', [], '/tags/cloud', false],
diff --git a/tpl/default/linklist.paging.html b/tpl/default/linklist.paging.html
index e1952b79..7b320eaf 100644
--- a/tpl/default/linklist.paging.html
+++ b/tpl/default/linklist.paging.html
@@ -6,10 +6,10 @@
6 {'Filters'|t} 6 {'Filters'|t}
7 </span> 7 </span>
8 {if="$is_logged_in"} 8 {if="$is_logged_in"}
9 <a href="{$base_path}/visibility/private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}" 9 <a href="{$base_path}/admin/visibility/private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}"
10 class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}" 10 class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}"
11 ><i class="fa fa-user-secret" aria-hidden="true"></i></a> 11 ><i class="fa fa-user-secret" aria-hidden="true"></i></a>
12 <a href="{$base_path}/visibility/public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}" 12 <a href="{$base_path}/admin/visibility/public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}"
13 class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}" 13 class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}"
14 ><i class="fa fa-globe" aria-hidden="true"></i></a> 14 ><i class="fa fa-globe" aria-hidden="true"></i></a>
15 {/if} 15 {/if}
diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html
index aa634a66..a71464c7 100644
--- a/tpl/default/page.header.html
+++ b/tpl/default/page.header.html
@@ -56,7 +56,7 @@
56 </li> 56 </li>
57 {if="$is_logged_in"} 57 {if="$is_logged_in"}
58 <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-logout"> 58 <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-logout">
59 <a href="{$base_path}/logout" class="pure-menu-link">{'Logout'|t}</a> 59 <a href="{$base_path}/admin/logout" class="pure-menu-link">{'Logout'|t}</a>
60 </li> 60 </li>
61 {else} 61 {else}
62 <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-login"> 62 <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-login">
@@ -88,7 +88,7 @@
88 </li> 88 </li>
89 {else} 89 {else}
90 <li class="pure-menu-item" id="shaarli-menu-desktop-logout"> 90 <li class="pure-menu-item" id="shaarli-menu-desktop-logout">
91 <a href="{$base_path}/logout" class="pure-menu-link" aria-label="{'Logout'|t}" title="{'Logout'|t}"> 91 <a href="{$base_path}/admin/logout" class="pure-menu-link" aria-label="{'Logout'|t}" title="{'Logout'|t}">
92 <i class="fa fa-sign-out" aria-hidden="true"></i> 92 <i class="fa fa-sign-out" aria-hidden="true"></i>
93 </a> 93 </a>
94 </li> 94 </li>
diff --git a/tpl/vintage/linklist.paging.html b/tpl/vintage/linklist.paging.html
index ea6a5ea2..b9396df6 100644
--- a/tpl/vintage/linklist.paging.html
+++ b/tpl/vintage/linklist.paging.html
@@ -1,7 +1,7 @@
1<div class="paging"> 1<div class="paging">
2{if="$is_logged_in"} 2{if="$is_logged_in"}
3 <div class="paging_privatelinks"> 3 <div class="paging_privatelinks">
4 <a href="{$base_path}/visibility/private"> 4 <a href="{$base_path}/admin/isibility/private">
5 {if="$visibility=='private'"} 5 {if="$visibility=='private'"}
6 <img src="{$asset_path}/img/private_16x16_active.png#" width="16" height="16" title="Click to see all links" alt="Click to see all links"> 6 <img src="{$asset_path}/img/private_16x16_active.png#" width="16" height="16" title="Click to see all links" alt="Click to see all links">
7 {else} 7 {else}
diff --git a/tpl/vintage/page.header.html b/tpl/vintage/page.header.html
index 1c00d19b..0a33523b 100644
--- a/tpl/vintage/page.header.html
+++ b/tpl/vintage/page.header.html
@@ -18,7 +18,7 @@
18{else} 18{else}
19<li><a href="{$titleLink}" class="nomobile">Home</a></li> 19<li><a href="{$titleLink}" class="nomobile">Home</a></li>
20 {if="$is_logged_in"} 20 {if="$is_logged_in"}
21 <li><a href="{$base_path}/logout">Logout</a></li> 21 <li><a href="{$base_path}/admin/logout">Logout</a></li>
22 <li><a href="{$base_path}/admin/tools">Tools</a></li> 22 <li><a href="{$base_path}/admin/tools">Tools</a></li>
23 <li><a href="{$base_path}/admin/add-shaare">Add link</a></li> 23 <li><a href="{$base_path}/admin/add-shaare">Add link</a></li>
24 {elseif="$openshaarli"} 24 {elseif="$openshaarli"}