aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/front/controller/visitor
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2020-07-06 08:04:35 +0200
committerArthurHoaro <arthur@hoa.ro>2020-07-23 21:19:21 +0200
commit1a8ac737e52cb25a5c346232ee398f5908cee7d7 (patch)
tree31954c4e106b5743e2005d72c2d548a0be8d6dce /application/front/controller/visitor
parent6132d64748dfc6806ed25f71d2e078a5ed29d071 (diff)
downloadShaarli-1a8ac737e52cb25a5c346232ee398f5908cee7d7.tar.gz
Shaarli-1a8ac737e52cb25a5c346232ee398f5908cee7d7.tar.zst
Shaarli-1a8ac737e52cb25a5c346232ee398f5908cee7d7.zip
Process main page (linklist) through Slim controller
Including a bunch of improvements on the container, and helper used across new controllers.
Diffstat (limited to 'application/front/controller/visitor')
-rw-r--r--application/front/controller/visitor/BookmarkListController.php248
-rw-r--r--application/front/controller/visitor/DailyController.php5
-rw-r--r--application/front/controller/visitor/LoginController.php3
-rw-r--r--application/front/controller/visitor/OpenSearchController.php3
-rw-r--r--application/front/controller/visitor/PictureWallController.php3
5 files changed, 257 insertions, 5 deletions
diff --git a/application/front/controller/visitor/BookmarkListController.php b/application/front/controller/visitor/BookmarkListController.php
new file mode 100644
index 00000000..a37a7f6b
--- /dev/null
+++ b/application/front/controller/visitor/BookmarkListController.php
@@ -0,0 +1,248 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Visitor;
6
7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9use Shaarli\Legacy\LegacyController;
10use Shaarli\Legacy\UnknowLegacyRouteException;
11use Shaarli\Render\TemplatePage;
12use Shaarli\Thumbnailer;
13use Slim\Http\Request;
14use Slim\Http\Response;
15
16/**
17 * Class BookmarkListController
18 *
19 * Slim controller used to render the bookmark list, the home page of Shaarli.
20 * It also displays permalinks, and process legacy routes based on GET parameters.
21 */
22class BookmarkListController extends ShaarliVisitorController
23{
24 /**
25 * GET / - Displays the bookmark list, with optional filter parameters.
26 */
27 public function index(Request $request, Response $response): Response
28 {
29 $legacyResponse = $this->processLegacyController($request, $response);
30 if (null !== $legacyResponse) {
31 return $legacyResponse;
32 }
33
34 $formatter = $this->container->formatterFactory->getFormatter();
35
36 $searchTags = escape(normalize_spaces($request->getParam('searchtags') ?? ''));
37 $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));;
38
39 // Filter bookmarks according search parameters.
40 $visibility = $this->container->sessionManager->getSessionParameter('visibility');
41 $search = [
42 'searchtags' => $searchTags,
43 'searchterm' => $searchTerm,
44 ];
45 $linksToDisplay = $this->container->bookmarkService->search(
46 $search,
47 $visibility,
48 false,
49 !!$this->container->sessionManager->getSessionParameter('untaggedonly')
50 ) ?? [];
51
52 // ---- Handle paging.
53 $keys = [];
54 foreach ($linksToDisplay as $key => $value) {
55 $keys[] = $key;
56 }
57
58 $linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
59
60 // Select articles according to paging.
61 $pageCount = (int) ceil(count($keys) / $linksPerPage) ?: 1;
62 $page = (int) $request->getParam('page') ?? 1;
63 $page = $page < 1 ? 1 : $page;
64 $page = $page > $pageCount ? $pageCount : $page;
65
66 // Start index.
67 $i = ($page - 1) * $linksPerPage;
68 $end = $i + $linksPerPage;
69
70 $linkDisp = [];
71 $save = false;
72 while ($i < $end && $i < count($keys)) {
73 $save = $this->updateThumbnail($linksToDisplay[$keys[$i]], false) || $save;
74 $link = $formatter->format($linksToDisplay[$keys[$i]]);
75
76 $linkDisp[$keys[$i]] = $link;
77 $i++;
78 }
79
80 if ($save) {
81 $this->container->bookmarkService->save();
82 }
83
84 // Compute paging navigation
85 $searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags);
86 $searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm);
87
88 $previous_page_url = '';
89 if ($i !== count($keys)) {
90 $previous_page_url = '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl;
91 }
92 $next_page_url = '';
93 if ($page > 1) {
94 $next_page_url = '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl;
95 }
96
97 // Fill all template fields.
98 $data = array_merge(
99 $this->initializeTemplateVars(),
100 [
101 'previous_page_url' => $previous_page_url,
102 'next_page_url' => $next_page_url,
103 'page_current' => $page,
104 'page_max' => $pageCount,
105 'result_count' => count($linksToDisplay),
106 'search_term' => $searchTerm,
107 'search_tags' => $searchTags,
108 'visibility' => $visibility,
109 'links' => $linkDisp,
110 ]
111 );
112
113 if (!empty($searchTerm) || !empty($searchTags)) {
114 $data['pagetitle'] = t('Search: ');
115 $data['pagetitle'] .= ! empty($searchTerm) ? $searchTerm . ' ' : '';
116 $bracketWrap = function ($tag) {
117 return '[' . $tag . ']';
118 };
119 $data['pagetitle'] .= ! empty($searchTags)
120 ? implode(' ', array_map($bracketWrap, preg_split('/\s+/', $searchTags))) . ' '
121 : '';
122 $data['pagetitle'] .= '- ';
123 }
124
125 $data['pagetitle'] = ($data['pagetitle'] ?? '') . $this->container->conf->get('general.title', 'Shaarli');
126
127 $this->executeHooks($data);
128 $this->assignAllView($data);
129
130 return $response->write($this->render(TemplatePage::LINKLIST));
131 }
132
133 /**
134 * GET /shaare/{hash} - Display a single shaare
135 */
136 public function permalink(Request $request, Response $response, array $args): Response
137 {
138 try {
139 $bookmark = $this->container->bookmarkService->findByHash($args['hash']);
140 } catch (BookmarkNotFoundException $e) {
141 $this->assignView('error_message', $e->getMessage());
142
143 return $response->write($this->render(TemplatePage::ERROR_404));
144 }
145
146 $this->updateThumbnail($bookmark);
147
148 $data = array_merge(
149 $this->initializeTemplateVars(),
150 [
151 'pagetitle' => $bookmark->getTitle() .' - '. $this->container->conf->get('general.title', 'Shaarli'),
152 'links' => [$this->container->formatterFactory->getFormatter()->format($bookmark)],
153 ]
154 );
155
156 $this->executeHooks($data);
157 $this->assignAllView($data);
158
159 return $response->write($this->render(TemplatePage::LINKLIST));
160 }
161
162 /**
163 * Update the thumbnail of a single bookmark if necessary.
164 */
165 protected function updateThumbnail(Bookmark $bookmark, bool $writeDatastore = true): bool
166 {
167 // Logged in, thumbnails enabled, not a note, is HTTP
168 // and (never retrieved yet or no valid cache file)
169 if ($this->container->loginManager->isLoggedIn()
170 && $this->container->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE
171 && false !== $bookmark->getThumbnail()
172 && !$bookmark->isNote()
173 && (null === $bookmark->getThumbnail() || !is_file($bookmark->getThumbnail()))
174 && startsWith(strtolower($bookmark->getUrl()), 'http')
175 ) {
176 $bookmark->setThumbnail($this->container->thumbnailer->get($bookmark->getUrl()));
177 $this->container->bookmarkService->set($bookmark, $writeDatastore);
178
179 return true;
180 }
181
182 return false;
183 }
184
185 /**
186 * @param mixed[] $data Template vars to process in plugins, passed as reference.
187 */
188 protected function executeHooks(array &$data): void
189 {
190 $this->container->pluginManager->executeHooks(
191 'render_linklist',
192 $data,
193 ['loggedin' => $this->container->loginManager->isLoggedIn()]
194 );
195 }
196
197 /**
198 * @return string[] Default template variables without values.
199 */
200 protected function initializeTemplateVars(): array
201 {
202 return [
203 'previous_page_url' => '',
204 'next_page_url' => '',
205 'page_max' => '',
206 'search_tags' => '',
207 'result_count' => '',
208 ];
209 }
210
211 /**
212 * Process legacy routes if necessary. They used query parameters.
213 * If no legacy routes is passed, return null.
214 */
215 protected function processLegacyController(Request $request, Response $response): ?Response
216 {
217 // Legacy smallhash filter
218 $queryString = $this->container->environment['QUERY_STRING'] ?? null;
219 if (null !== $queryString && 1 === preg_match('/^([a-zA-Z0-9-_@]{6})($|&|#)/', $queryString, $match)) {
220 return $this->redirect($response, '/shaare/' . $match[1]);
221 }
222
223 // Legacy controllers (mostly used for redirections)
224 if (null !== $request->getQueryParam('do')) {
225 $legacyController = new LegacyController($this->container);
226
227 try {
228 return $legacyController->process($request, $response, $request->getQueryParam('do'));
229 } catch (UnknowLegacyRouteException $e) {
230 // We ignore legacy 404
231 return null;
232 }
233 }
234
235 // Legacy GET admin routes
236 $legacyGetRoutes = array_intersect(
237 LegacyController::LEGACY_GET_ROUTES,
238 array_keys($request->getQueryParams() ?? [])
239 );
240 if (1 === count($legacyGetRoutes)) {
241 $legacyController = new LegacyController($this->container);
242
243 return $legacyController->process($request, $response, $legacyGetRoutes[0]);
244 }
245
246 return null;
247 }
248}
diff --git a/application/front/controller/visitor/DailyController.php b/application/front/controller/visitor/DailyController.php
index e5c9ddac..05b4f095 100644
--- a/application/front/controller/visitor/DailyController.php
+++ b/application/front/controller/visitor/DailyController.php
@@ -7,6 +7,7 @@ namespace Shaarli\Front\Controller\Visitor;
7use DateTime; 7use DateTime;
8use DateTimeImmutable; 8use DateTimeImmutable;
9use Shaarli\Bookmark\Bookmark; 9use Shaarli\Bookmark\Bookmark;
10use Shaarli\Render\TemplatePage;
10use Slim\Http\Request; 11use Slim\Http\Request;
11use Slim\Http\Response; 12use Slim\Http\Response;
12 13
@@ -85,7 +86,7 @@ class DailyController extends ShaarliVisitorController
85 t('Daily') .' - '. format_date($dayDate, false) . ' - ' . $mainTitle 86 t('Daily') .' - '. format_date($dayDate, false) . ' - ' . $mainTitle
86 ); 87 );
87 88
88 return $response->write($this->render('daily')); 89 return $response->write($this->render(TemplatePage::DAILY));
89 } 90 }
90 91
91 /** 92 /**
@@ -152,7 +153,7 @@ class DailyController extends ShaarliVisitorController
152 $this->assignView('hide_timestamps', $this->container->conf->get('privacy.hide_timestamps', false)); 153 $this->assignView('hide_timestamps', $this->container->conf->get('privacy.hide_timestamps', false));
153 $this->assignView('days', $dataPerDay); 154 $this->assignView('days', $dataPerDay);
154 155
155 $rssContent = $this->render('dailyrss'); 156 $rssContent = $this->render(TemplatePage::DAILY_RSS);
156 157
157 $cache->cache($rssContent); 158 $cache->cache($rssContent);
158 159
diff --git a/application/front/controller/visitor/LoginController.php b/application/front/controller/visitor/LoginController.php
index 0db1f463..a257766f 100644
--- a/application/front/controller/visitor/LoginController.php
+++ b/application/front/controller/visitor/LoginController.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
5namespace Shaarli\Front\Controller\Visitor; 5namespace Shaarli\Front\Controller\Visitor;
6 6
7use Shaarli\Front\Exception\LoginBannedException; 7use Shaarli\Front\Exception\LoginBannedException;
8use Shaarli\Render\TemplatePage;
8use Slim\Http\Request; 9use Slim\Http\Request;
9use Slim\Http\Response; 10use Slim\Http\Response;
10 11
@@ -41,6 +42,6 @@ class LoginController extends ShaarliVisitorController
41 ->assignView('pagetitle', t('Login') .' - '. $this->container->conf->get('general.title', 'Shaarli')) 42 ->assignView('pagetitle', t('Login') .' - '. $this->container->conf->get('general.title', 'Shaarli'))
42 ; 43 ;
43 44
44 return $response->write($this->render('loginform')); 45 return $response->write($this->render(TemplatePage::LOGIN));
45 } 46 }
46} 47}
diff --git a/application/front/controller/visitor/OpenSearchController.php b/application/front/controller/visitor/OpenSearchController.php
index 0fd68db6..36d60acf 100644
--- a/application/front/controller/visitor/OpenSearchController.php
+++ b/application/front/controller/visitor/OpenSearchController.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Visitor; 5namespace Shaarli\Front\Controller\Visitor;
6 6
7use Shaarli\Render\TemplatePage;
7use Slim\Http\Request; 8use Slim\Http\Request;
8use Slim\Http\Response; 9use Slim\Http\Response;
9 10
@@ -21,6 +22,6 @@ class OpenSearchController extends ShaarliVisitorController
21 22
22 $this->assignView('serverurl', index_url($this->container->environment)); 23 $this->assignView('serverurl', index_url($this->container->environment));
23 24
24 return $response->write($this->render('opensearch')); 25 return $response->write($this->render(TemplatePage::OPEN_SEARCH));
25 } 26 }
26} 27}
diff --git a/application/front/controller/visitor/PictureWallController.php b/application/front/controller/visitor/PictureWallController.php
index 4e1dce8c..5ef2cb17 100644
--- a/application/front/controller/visitor/PictureWallController.php
+++ b/application/front/controller/visitor/PictureWallController.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
5namespace Shaarli\Front\Controller\Visitor; 5namespace Shaarli\Front\Controller\Visitor;
6 6
7use Shaarli\Front\Exception\ThumbnailsDisabledException; 7use Shaarli\Front\Exception\ThumbnailsDisabledException;
8use Shaarli\Render\TemplatePage;
8use Shaarli\Thumbnailer; 9use Shaarli\Thumbnailer;
9use Slim\Http\Request; 10use Slim\Http\Request;
10use Slim\Http\Response; 11use Slim\Http\Response;
@@ -46,7 +47,7 @@ class PictureWallController extends ShaarliVisitorController
46 $this->assignView($key, $value); 47 $this->assignView($key, $value);
47 } 48 }
48 49
49 return $response->write($this->render('picwall')); 50 return $response->write($this->render(TemplatePage::PICTURE_WALL));
50 } 51 }
51 52
52 /** 53 /**