aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--application/bookmark/Bookmark.php15
-rw-r--r--application/bookmark/BookmarkFileService.php2
-rw-r--r--application/container/ContainerBuilder.php5
-rw-r--r--application/front/controllers/DailyController.php74
-rw-r--r--application/http/HttpUtils.php15
-rw-r--r--application/legacy/LegacyLinkDB.php2
-rw-r--r--application/render/PageCacheManager.php17
-rw-r--r--index.php103
-rw-r--r--tests/front/controller/DailyControllerTest.php152
-rw-r--r--tests/http/HttpUtils/IndexUrlTest.php32
-rw-r--r--tests/render/PageCacheManagerTest.php4
-rw-r--r--tpl/default/daily.html2
-rw-r--r--tpl/default/dailyrss.html48
-rw-r--r--tpl/vintage/daily.html2
-rw-r--r--tpl/vintage/dailyrss.html46
15 files changed, 365 insertions, 154 deletions
diff --git a/application/bookmark/Bookmark.php b/application/bookmark/Bookmark.php
index 83ddab82..90ff5b16 100644
--- a/application/bookmark/Bookmark.php
+++ b/application/bookmark/Bookmark.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Bookmark; 3namespace Shaarli\Bookmark;
4 4
5use DateTime; 5use DateTime;
6use DateTimeInterface;
6use Shaarli\Bookmark\Exception\InvalidBookmarkException; 7use Shaarli\Bookmark\Exception\InvalidBookmarkException;
7 8
8/** 9/**
@@ -42,10 +43,10 @@ class Bookmark
42 /** @var bool Set to true if the bookmark is set as sticky */ 43 /** @var bool Set to true if the bookmark is set as sticky */
43 protected $sticky; 44 protected $sticky;
44 45
45 /** @var DateTime Creation datetime */ 46 /** @var DateTimeInterface Creation datetime */
46 protected $created; 47 protected $created;
47 48
48 /** @var DateTime Update datetime */ 49 /** @var DateTimeInterface datetime */
49 protected $updated; 50 protected $updated;
50 51
51 /** @var bool True if the bookmark can only be seen while logged in */ 52 /** @var bool True if the bookmark can only be seen while logged in */
@@ -100,7 +101,7 @@ class Bookmark
100 || ! is_int($this->id) 101 || ! is_int($this->id)
101 || empty($this->shortUrl) 102 || empty($this->shortUrl)
102 || empty($this->created) 103 || empty($this->created)
103 || ! $this->created instanceof DateTime 104 || ! $this->created instanceof DateTimeInterface
104 ) { 105 ) {
105 throw new InvalidBookmarkException($this); 106 throw new InvalidBookmarkException($this);
106 } 107 }
@@ -188,7 +189,7 @@ class Bookmark
188 /** 189 /**
189 * Get the Created. 190 * Get the Created.
190 * 191 *
191 * @return DateTime 192 * @return DateTimeInterface
192 */ 193 */
193 public function getCreated() 194 public function getCreated()
194 { 195 {
@@ -198,7 +199,7 @@ class Bookmark
198 /** 199 /**
199 * Get the Updated. 200 * Get the Updated.
200 * 201 *
201 * @return DateTime 202 * @return DateTimeInterface
202 */ 203 */
203 public function getUpdated() 204 public function getUpdated()
204 { 205 {
@@ -270,7 +271,7 @@ class Bookmark
270 * Set the Created. 271 * Set the Created.
271 * Note: you shouldn't set this manually except for special cases (like bookmark import) 272 * Note: you shouldn't set this manually except for special cases (like bookmark import)
272 * 273 *
273 * @param DateTime $created 274 * @param DateTimeInterface $created
274 * 275 *
275 * @return Bookmark 276 * @return Bookmark
276 */ 277 */
@@ -284,7 +285,7 @@ class Bookmark
284 /** 285 /**
285 * Set the Updated. 286 * Set the Updated.
286 * 287 *
287 * @param DateTime $updated 288 * @param DateTimeInterface $updated
288 * 289 *
289 * @return Bookmark 290 * @return Bookmark
290 */ 291 */
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php
index 3b3812af..7439d8d8 100644
--- a/application/bookmark/BookmarkFileService.php
+++ b/application/bookmark/BookmarkFileService.php
@@ -53,7 +53,7 @@ class BookmarkFileService implements BookmarkServiceInterface
53 { 53 {
54 $this->conf = $conf; 54 $this->conf = $conf;
55 $this->history = $history; 55 $this->history = $history;
56 $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache')); 56 $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache'), $isLoggedIn);
57 $this->bookmarksIO = new BookmarkIO($this->conf); 57 $this->bookmarksIO = new BookmarkIO($this->conf);
58 $this->isLoggedIn = $isLoggedIn; 58 $this->isLoggedIn = $isLoggedIn;
59 59
diff --git a/application/container/ContainerBuilder.php b/application/container/ContainerBuilder.php
index c5c4a2c3..199f3f67 100644
--- a/application/container/ContainerBuilder.php
+++ b/application/container/ContainerBuilder.php
@@ -94,7 +94,10 @@ class ContainerBuilder
94 }; 94 };
95 95
96 $container['pageCacheManager'] = function (ShaarliContainer $container): PageCacheManager { 96 $container['pageCacheManager'] = function (ShaarliContainer $container): PageCacheManager {
97 return new PageCacheManager($container->conf->get('resource.page_cache')); 97 return new PageCacheManager(
98 $container->conf->get('resource.page_cache'),
99 $container->loginManager->isLoggedIn()
100 );
98 }; 101 };
99 102
100 return $container; 103 return $container;
diff --git a/application/front/controllers/DailyController.php b/application/front/controllers/DailyController.php
index 271c0ee2..4a0735aa 100644
--- a/application/front/controllers/DailyController.php
+++ b/application/front/controllers/DailyController.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
5namespace Shaarli\Front\Controller; 5namespace Shaarli\Front\Controller;
6 6
7use DateTime; 7use DateTime;
8use DateTimeImmutable;
8use Shaarli\Bookmark\Bookmark; 9use Shaarli\Bookmark\Bookmark;
9use Slim\Http\Request; 10use Slim\Http\Request;
10use Slim\Http\Response; 11use Slim\Http\Response;
@@ -18,6 +19,8 @@ use Slim\Http\Response;
18 */ 19 */
19class DailyController extends ShaarliController 20class DailyController extends ShaarliController
20{ 21{
22 public static $DAILY_RSS_NB_DAYS = 8;
23
21 /** 24 /**
22 * Controller displaying all bookmarks published in a single day. 25 * Controller displaying all bookmarks published in a single day.
23 * It take a `day` date query parameter (format YYYYMMDD). 26 * It take a `day` date query parameter (format YYYYMMDD).
@@ -88,6 +91,77 @@ class DailyController extends ShaarliController
88 } 91 }
89 92
90 /** 93 /**
94 * Daily RSS feed: 1 RSS entry per day giving all the bookmarks on that day.
95 * Gives the last 7 days (which have bookmarks).
96 * This RSS feed cannot be filtered and does not trigger plugins yet.
97 */
98 public function rss(Request $request, Response $response): Response
99 {
100 $response = $response->withHeader('Content-Type', 'application/rss+xml; charset=utf-8');
101
102 $pageUrl = page_url($this->container->environment);
103 $cache = $this->container->pageCacheManager->getCachePage($pageUrl);
104
105 $cached = $cache->cachedVersion();
106 if (!empty($cached)) {
107 return $response->write($cached);
108 }
109
110 $days = [];
111 foreach ($this->container->bookmarkService->search() as $bookmark) {
112 $day = $bookmark->getCreated()->format('Ymd');
113
114 // Stop iterating after DAILY_RSS_NB_DAYS entries
115 if (count($days) === static::$DAILY_RSS_NB_DAYS && !isset($days[$day])) {
116 break;
117 }
118
119 $days[$day][] = $bookmark;
120 }
121
122 // Build the RSS feed.
123 $indexUrl = escape(index_url($this->container->environment));
124
125 $formatter = $this->container->formatterFactory->getFormatter();
126 $formatter->addContextData('index_url', $indexUrl);
127
128 $dataPerDay = [];
129
130 /** @var Bookmark[] $bookmarks */
131 foreach ($days as $day => $bookmarks) {
132 $dayDatetime = DateTimeImmutable::createFromFormat(Bookmark::LINK_DATE_FORMAT, $day.'_000000');
133 $dataPerDay[$day] = [
134 'date' => $dayDatetime,
135 'date_rss' => $dayDatetime->format(DateTime::RSS),
136 'date_human' => format_date($dayDatetime, false, true),
137 'absolute_url' => $indexUrl . '/daily?day=' . $day,
138 'links' => [],
139 ];
140
141 foreach ($bookmarks as $key => $bookmark) {
142 $dataPerDay[$day]['links'][$key] = $formatter->format($bookmark);
143
144 // Make permalink URL absolute
145 if ($bookmark->isNote()) {
146 $dataPerDay[$day]['links'][$key]['url'] = $indexUrl . $bookmark->getUrl();
147 }
148 }
149 }
150
151 $this->assignView('title', $this->container->conf->get('general.title', 'Shaarli'));
152 $this->assignView('index_url', $indexUrl);
153 $this->assignView('page_url', $pageUrl);
154 $this->assignView('hide_timestamps', $this->container->conf->get('privacy.hide_timestamps', false));
155 $this->assignView('days', $dataPerDay);
156
157 $rssContent = $this->render('dailyrss');
158
159 $cache->cache($rssContent);
160
161 return $response->write($rssContent);
162 }
163
164 /**
91 * We need to spread the articles on 3 columns. 165 * We need to spread the articles on 3 columns.
92 * did not want to use a JavaScript lib like http://masonry.desandro.com/ 166 * did not want to use a JavaScript lib like http://masonry.desandro.com/
93 * so I manually spread entries with a simple method: I roughly evaluate the 167 * so I manually spread entries with a simple method: I roughly evaluate the
diff --git a/application/http/HttpUtils.php b/application/http/HttpUtils.php
index 2ea9195d..f00c4336 100644
--- a/application/http/HttpUtils.php
+++ b/application/http/HttpUtils.php
@@ -369,7 +369,7 @@ function server_url($server)
369 */ 369 */
370function index_url($server) 370function index_url($server)
371{ 371{
372 $scriptname = $server['SCRIPT_NAME']; 372 $scriptname = $server['SCRIPT_NAME'] ?? '';
373 if (endsWith($scriptname, 'index.php')) { 373 if (endsWith($scriptname, 'index.php')) {
374 $scriptname = substr($scriptname, 0, -9); 374 $scriptname = substr($scriptname, 0, -9);
375 } 375 }
@@ -377,7 +377,7 @@ function index_url($server)
377} 377}
378 378
379/** 379/**
380 * Returns the absolute URL of the current script, with the query 380 * Returns the absolute URL of the current script, with current route and query
381 * 381 *
382 * If the resource is "index.php", then it is removed (for better-looking URLs) 382 * If the resource is "index.php", then it is removed (for better-looking URLs)
383 * 383 *
@@ -387,10 +387,17 @@ function index_url($server)
387 */ 387 */
388function page_url($server) 388function page_url($server)
389{ 389{
390 $scriptname = $server['SCRIPT_NAME'] ?? '';
391 if (endsWith($scriptname, 'index.php')) {
392 $scriptname = substr($scriptname, 0, -9);
393 }
394
395 $route = ltrim($server['REQUEST_URI'] ?? '', $scriptname);
390 if (! empty($server['QUERY_STRING'])) { 396 if (! empty($server['QUERY_STRING'])) {
391 return index_url($server).'?'.$server['QUERY_STRING']; 397 return index_url($server) . $route . '?' . $server['QUERY_STRING'];
392 } 398 }
393 return index_url($server); 399
400 return index_url($server) . $route;
394} 401}
395 402
396/** 403/**
diff --git a/application/legacy/LegacyLinkDB.php b/application/legacy/LegacyLinkDB.php
index 947005ad..7bf76fd4 100644
--- a/application/legacy/LegacyLinkDB.php
+++ b/application/legacy/LegacyLinkDB.php
@@ -353,7 +353,7 @@ You use the community supported version of the original Shaarli project, by Seba
353 353
354 $this->write(); 354 $this->write();
355 355
356 $pageCacheManager = new PageCacheManager($pageCacheDir); 356 $pageCacheManager = new PageCacheManager($pageCacheDir, $this->loggedIn);
357 $pageCacheManager->invalidateCaches(); 357 $pageCacheManager->invalidateCaches();
358 } 358 }
359 359
diff --git a/application/render/PageCacheManager.php b/application/render/PageCacheManager.php
index bd91fe0d..97805c35 100644
--- a/application/render/PageCacheManager.php
+++ b/application/render/PageCacheManager.php
@@ -2,6 +2,8 @@
2 2
3namespace Shaarli\Render; 3namespace Shaarli\Render;
4 4
5use Shaarli\Feed\CachedPage;
6
5/** 7/**
6 * Cache utilities 8 * Cache utilities
7 */ 9 */
@@ -10,9 +12,13 @@ class PageCacheManager
10 /** @var string Cache directory */ 12 /** @var string Cache directory */
11 protected $pageCacheDir; 13 protected $pageCacheDir;
12 14
13 public function __construct(string $pageCacheDir) 15 /** @var bool */
16 protected $isLoggedIn;
17
18 public function __construct(string $pageCacheDir, bool $isLoggedIn)
14 { 19 {
15 $this->pageCacheDir = $pageCacheDir; 20 $this->pageCacheDir = $pageCacheDir;
21 $this->isLoggedIn = $isLoggedIn;
16 } 22 }
17 23
18 /** 24 /**
@@ -42,4 +48,13 @@ class PageCacheManager
42 // Purge page cache shared by sessions. 48 // Purge page cache shared by sessions.
43 $this->purgeCachedPages(); 49 $this->purgeCachedPages();
44 } 50 }
51
52 public function getCachePage(string $pageUrl): CachedPage
53 {
54 return new CachedPage(
55 $this->pageCacheDir,
56 $pageUrl,
57 false === $this->isLoggedIn
58 );
59 }
45} 60}
diff --git a/index.php b/index.php
index dbb76d3f..9dc67c4b 100644
--- a/index.php
+++ b/index.php
@@ -301,104 +301,6 @@ if (!isset($_SESSION['tokens'])) {
301} 301}
302 302
303/** 303/**
304 * Daily RSS feed: 1 RSS entry per day giving all the bookmarks on that day.
305 * Gives the last 7 days (which have bookmarks).
306 * This RSS feed cannot be filtered.
307 *
308 * @param BookmarkServiceInterface $bookmarkService
309 * @param ConfigManager $conf Configuration Manager instance
310 * @param LoginManager $loginManager LoginManager instance
311 */
312function showDailyRSS($bookmarkService, $conf, $loginManager)
313{
314 // Cache system
315 $query = $_SERVER['QUERY_STRING'];
316 $cache = new CachedPage(
317 $conf->get('config.PAGE_CACHE'),
318 page_url($_SERVER),
319 startsWith($query, 'do=dailyrss') && !$loginManager->isLoggedIn()
320 );
321 $cached = $cache->cachedVersion();
322 if (!empty($cached)) {
323 echo $cached;
324 exit;
325 }
326
327 /* Some Shaarlies may have very few bookmarks, so we need to look
328 back in time until we have enough days ($nb_of_days).
329 */
330 $nb_of_days = 7; // We take 7 days.
331 $today = date('Ymd');
332 $days = array();
333
334 foreach ($bookmarkService->search() as $bookmark) {
335 $day = $bookmark->getCreated()->format('Ymd'); // Extract day (without time)
336 if (strcmp($day, $today) < 0) {
337 if (empty($days[$day])) {
338 $days[$day] = array();
339 }
340 $days[$day][] = $bookmark;
341 }
342
343 if (count($days) > $nb_of_days) {
344 break; // Have we collected enough days?
345 }
346 }
347
348 // Build the RSS feed.
349 header('Content-Type: application/rss+xml; charset=utf-8');
350 $pageaddr = escape(index_url($_SERVER));
351 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">';
352 echo '<channel>';
353 echo '<title>Daily - '. $conf->get('general.title') . '</title>';
354 echo '<link>'. $pageaddr .'</link>';
355 echo '<description>Daily shared bookmarks</description>';
356 echo '<language>en-en</language>';
357 echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL;
358
359 $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
360 $formatter = $factory->getFormatter();
361 $formatter->addContextData('index_url', index_url($_SERVER));
362 // For each day.
363 /** @var Bookmark[] $bookmarks */
364 foreach ($days as $day => $bookmarks) {
365 $formattedBookmarks = [];
366 $dayDate = DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, $day.'_000000');
367 $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
368
369 // We pre-format some fields for proper output.
370 foreach ($bookmarks as $key => $bookmark) {
371 $formattedBookmarks[$key] = $formatter->format($bookmark);
372 // This page is a bit specific, we need raw description to calculate the length
373 $formattedBookmarks[$key]['formatedDescription'] = $formattedBookmarks[$key]['description'];
374 $formattedBookmarks[$key]['description'] = $bookmark->getDescription();
375
376 if ($bookmark->isNote()) {
377 $link['url'] = index_url($_SERVER) . $bookmark->getUrl(); // make permalink URL absolute
378 }
379 }
380
381 // Then build the HTML for this day:
382 $tpl = new RainTPL();
383 $tpl->assign('title', $conf->get('general.title'));
384 $tpl->assign('daydate', $dayDate->getTimestamp());
385 $tpl->assign('absurl', $absurl);
386 $tpl->assign('links', $formattedBookmarks);
387 $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS)));
388 $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false));
389 $tpl->assign('index_url', $pageaddr);
390 $html = $tpl->draw('dailyrss', true);
391
392 echo $html . PHP_EOL;
393 }
394 echo '</channel></rss><!-- Cached version of '. escape(page_url($_SERVER)) .' -->';
395
396 $cache->cache(ob_get_contents());
397 ob_end_flush();
398 exit;
399}
400
401/**
402 * Renders the linklist 304 * Renders the linklist
403 * 305 *
404 * @param pageBuilder $PAGE pageBuilder instance. 306 * @param pageBuilder $PAGE pageBuilder instance.
@@ -424,7 +326,7 @@ function showLinkList($PAGE, $linkDb, $conf, $pluginManager, $loginManager)
424 */ 326 */
425function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionManager, $loginManager) 327function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionManager, $loginManager)
426{ 328{
427 $pageCacheManager = new PageCacheManager($conf->get('resource.page_cache')); 329 $pageCacheManager = new PageCacheManager($conf->get('resource.page_cache'), $loginManager->isLoggedIn());
428 $updater = new Updater( 330 $updater = new Updater(
429 UpdaterUtils::read_updates_file($conf->get('resource.updates')), 331 UpdaterUtils::read_updates_file($conf->get('resource.updates')),
430 $bookmarkService, 332 $bookmarkService,
@@ -1715,7 +1617,7 @@ try {
1715$linkDb = new BookmarkFileService($conf, $history, $loginManager->isLoggedIn()); 1617$linkDb = new BookmarkFileService($conf, $history, $loginManager->isLoggedIn());
1716 1618
1717if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { 1619if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) {
1718 showDailyRSS($linkDb, $conf, $loginManager); 1620 header('Location: ./daily-rss');
1719 exit; 1621 exit;
1720} 1622}
1721 1623
@@ -1747,6 +1649,7 @@ $app->group('', function () {
1747 $this->get('/tag-cloud', '\Shaarli\Front\Controller\TagCloudController:cloud')->setName('tagcloud'); 1649 $this->get('/tag-cloud', '\Shaarli\Front\Controller\TagCloudController:cloud')->setName('tagcloud');
1748 $this->get('/tag-list', '\Shaarli\Front\Controller\TagCloudController:list')->setName('taglist'); 1650 $this->get('/tag-list', '\Shaarli\Front\Controller\TagCloudController:list')->setName('taglist');
1749 $this->get('/daily', '\Shaarli\Front\Controller\DailyController:index')->setName('daily'); 1651 $this->get('/daily', '\Shaarli\Front\Controller\DailyController:index')->setName('daily');
1652 $this->get('/daily-rss', '\Shaarli\Front\Controller\DailyController:rss')->setName('dailyrss');
1750 1653
1751 $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\TagController:addTag')->setName('add-tag'); 1654 $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\TagController:addTag')->setName('add-tag');
1752})->add('\Shaarli\Front\ShaarliMiddleware'); 1655})->add('\Shaarli\Front\ShaarliMiddleware');
diff --git a/tests/front/controller/DailyControllerTest.php b/tests/front/controller/DailyControllerTest.php
index 2714bfd9..72a0339f 100644
--- a/tests/front/controller/DailyControllerTest.php
+++ b/tests/front/controller/DailyControllerTest.php
@@ -9,11 +9,13 @@ use Shaarli\Bookmark\Bookmark;
9use Shaarli\Bookmark\BookmarkServiceInterface; 9use Shaarli\Bookmark\BookmarkServiceInterface;
10use Shaarli\Config\ConfigManager; 10use Shaarli\Config\ConfigManager;
11use Shaarli\Container\ShaarliContainer; 11use Shaarli\Container\ShaarliContainer;
12use Shaarli\Feed\CachedPage;
12use Shaarli\Formatter\BookmarkFormatter; 13use Shaarli\Formatter\BookmarkFormatter;
13use Shaarli\Formatter\BookmarkRawFormatter; 14use Shaarli\Formatter\BookmarkRawFormatter;
14use Shaarli\Formatter\FormatterFactory; 15use Shaarli\Formatter\FormatterFactory;
15use Shaarli\Plugin\PluginManager; 16use Shaarli\Plugin\PluginManager;
16use Shaarli\Render\PageBuilder; 17use Shaarli\Render\PageBuilder;
18use Shaarli\Render\PageCacheManager;
17use Shaarli\Security\LoginManager; 19use Shaarli\Security\LoginManager;
18use Slim\Http\Request; 20use Slim\Http\Request;
19use Slim\Http\Response; 21use Slim\Http\Response;
@@ -30,9 +32,10 @@ class DailyControllerTest extends TestCase
30 { 32 {
31 $this->container = $this->createMock(ShaarliContainer::class); 33 $this->container = $this->createMock(ShaarliContainer::class);
32 $this->controller = new DailyController($this->container); 34 $this->controller = new DailyController($this->container);
35 DailyController::$DAILY_RSS_NB_DAYS = 2;
33 } 36 }
34 37
35 public function testValidControllerInvokeDefault(): void 38 public function testValidIndexControllerInvokeDefault(): void
36 { 39 {
37 $this->createValidContainerMockSet(); 40 $this->createValidContainerMockSet();
38 41
@@ -173,7 +176,7 @@ class DailyControllerTest extends TestCase
173 /** 176 /**
174 * Daily page - test that everything goes fine with no future or past bookmarks 177 * Daily page - test that everything goes fine with no future or past bookmarks
175 */ 178 */
176 public function testValidControllerInvokeNoFutureOrPast(): void 179 public function testValidIndexControllerInvokeNoFutureOrPast(): void
177 { 180 {
178 $this->createValidContainerMockSet(); 181 $this->createValidContainerMockSet();
179 182
@@ -247,7 +250,7 @@ class DailyControllerTest extends TestCase
247 /** 250 /**
248 * Daily page - test that height adjustment in columns is working 251 * Daily page - test that height adjustment in columns is working
249 */ 252 */
250 public function testValidControllerInvokeHeightAdjustment(): void 253 public function testValidIndexControllerInvokeHeightAdjustment(): void
251 { 254 {
252 $this->createValidContainerMockSet(); 255 $this->createValidContainerMockSet();
253 256
@@ -318,7 +321,7 @@ class DailyControllerTest extends TestCase
318 /** 321 /**
319 * Daily page - no bookmark 322 * Daily page - no bookmark
320 */ 323 */
321 public function testValidControllerInvokeNoBookmark(): void 324 public function testValidIndexControllerInvokeNoBookmark(): void
322 { 325 {
323 $this->createValidContainerMockSet(); 326 $this->createValidContainerMockSet();
324 327
@@ -364,6 +367,136 @@ class DailyControllerTest extends TestCase
364 static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']); 367 static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']);
365 } 368 }
366 369
370 /**
371 * Daily RSS - default behaviour
372 */
373 public function testValidRssControllerInvokeDefault(): void
374 {
375 $this->createValidContainerMockSet();
376
377 $dates = [
378 new \DateTimeImmutable('2020-05-17'),
379 new \DateTimeImmutable('2020-05-15'),
380 new \DateTimeImmutable('2020-05-13'),
381 ];
382
383 $request = $this->createMock(Request::class);
384 $response = new Response();
385
386 $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
387 (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
388 (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
389 (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
390 (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'),
391 ]);
392
393 $this->container->pageCacheManager
394 ->expects(static::once())
395 ->method('getCachePage')
396 ->willReturnCallback(function (): CachedPage {
397 $cachedPage = $this->createMock(CachedPage::class);
398 $cachedPage->expects(static::once())->method('cache')->with('dailyrss');
399
400 return $cachedPage;
401 }
402 );
403
404 // Save RainTPL assigned variables
405 $assignedVariables = [];
406 $this->assignTemplateVars($assignedVariables);
407
408 $result = $this->controller->rss($request, $response);
409
410 static::assertSame(200, $result->getStatusCode());
411 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
412 static::assertSame('dailyrss', (string) $result->getBody());
413 static::assertSame('Shaarli', $assignedVariables['title']);
414 static::assertSame('http://shaarli', $assignedVariables['index_url']);
415 static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
416 static::assertFalse($assignedVariables['hide_timestamps']);
417 static::assertCount(2, $assignedVariables['days']);
418
419 $day = $assignedVariables['days'][$dates[0]->format('Ymd')];
420
421 static::assertEquals($dates[0], $day['date']);
422 static::assertSame($dates[0]->format(\DateTimeInterface::RSS), $day['date_rss']);
423 static::assertSame(format_date($dates[0], false), $day['date_human']);
424 static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
425 static::assertCount(1, $day['links']);
426 static::assertSame(1, $day['links'][0]['id']);
427 static::assertSame('http://domain.tld/1', $day['links'][0]['url']);
428 static::assertEquals($dates[0], $day['links'][0]['created']);
429
430 $day = $assignedVariables['days'][$dates[1]->format('Ymd')];
431
432 static::assertEquals($dates[1], $day['date']);
433 static::assertSame($dates[1]->format(\DateTimeInterface::RSS), $day['date_rss']);
434 static::assertSame(format_date($dates[1], false), $day['date_human']);
435 static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
436 static::assertCount(2, $day['links']);
437
438 static::assertSame(2, $day['links'][0]['id']);
439 static::assertSame('http://domain.tld/2', $day['links'][0]['url']);
440 static::assertEquals($dates[1], $day['links'][0]['created']);
441 static::assertSame(3, $day['links'][1]['id']);
442 static::assertSame('http://domain.tld/3', $day['links'][1]['url']);
443 static::assertEquals($dates[1], $day['links'][1]['created']);
444 }
445
446 /**
447 * Daily RSS - trigger cache rendering
448 */
449 public function testValidRssControllerInvokeTriggerCache(): void
450 {
451 $this->createValidContainerMockSet();
452
453 $request = $this->createMock(Request::class);
454 $response = new Response();
455
456 $this->container->pageCacheManager->method('getCachePage')->willReturnCallback(function (): CachedPage {
457 $cachedPage = $this->createMock(CachedPage::class);
458 $cachedPage->method('cachedVersion')->willReturn('this is cache!');
459
460 return $cachedPage;
461 });
462
463 $this->container->bookmarkService->expects(static::never())->method('search');
464
465 $result = $this->controller->rss($request, $response);
466
467 static::assertSame(200, $result->getStatusCode());
468 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
469 static::assertSame('this is cache!', (string) $result->getBody());
470 }
471
472 /**
473 * Daily RSS - No bookmark
474 */
475 public function testValidRssControllerInvokeNoBookmark(): void
476 {
477 $this->createValidContainerMockSet();
478
479 $request = $this->createMock(Request::class);
480 $response = new Response();
481
482 $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]);
483
484 // Save RainTPL assigned variables
485 $assignedVariables = [];
486 $this->assignTemplateVars($assignedVariables);
487
488 $result = $this->controller->rss($request, $response);
489
490 static::assertSame(200, $result->getStatusCode());
491 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
492 static::assertSame('dailyrss', (string) $result->getBody());
493 static::assertSame('Shaarli', $assignedVariables['title']);
494 static::assertSame('http://shaarli', $assignedVariables['index_url']);
495 static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
496 static::assertFalse($assignedVariables['hide_timestamps']);
497 static::assertCount(0, $assignedVariables['days']);
498 }
499
367 protected function createValidContainerMockSet(): void 500 protected function createValidContainerMockSet(): void
368 { 501 {
369 $loginManager = $this->createMock(LoginManager::class); 502 $loginManager = $this->createMock(LoginManager::class);
@@ -403,6 +536,17 @@ class DailyControllerTest extends TestCase
403 }) 536 })
404 ; 537 ;
405 $this->container->formatterFactory = $formatterFactory; 538 $this->container->formatterFactory = $formatterFactory;
539
540 // CacheManager
541 $pageCacheManager = $this->createMock(PageCacheManager::class);
542 $this->container->pageCacheManager = $pageCacheManager;
543
544 // $_SERVER
545 $this->container->environment = [
546 'SERVER_NAME' => 'shaarli',
547 'SERVER_PORT' => '80',
548 'REQUEST_URI' => '/daily-rss',
549 ];
406 } 550 }
407 551
408 protected function assignTemplateVars(array &$variables): void 552 protected function assignTemplateVars(array &$variables): void
diff --git a/tests/http/HttpUtils/IndexUrlTest.php b/tests/http/HttpUtils/IndexUrlTest.php
index bcbe59cb..73d33cd4 100644
--- a/tests/http/HttpUtils/IndexUrlTest.php
+++ b/tests/http/HttpUtils/IndexUrlTest.php
@@ -71,4 +71,36 @@ class IndexUrlTest extends \PHPUnit\Framework\TestCase
71 ) 71 )
72 ); 72 );
73 } 73 }
74
75 /**
76 * The route is stored in REQUEST_URI
77 */
78 public function testPageUrlWithRoute()
79 {
80 $this->assertEquals(
81 'http://host.tld/picture-wall',
82 page_url(
83 array(
84 'HTTPS' => 'Off',
85 'SERVER_NAME' => 'host.tld',
86 'SERVER_PORT' => '80',
87 'SCRIPT_NAME' => '/index.php',
88 'REQUEST_URI' => '/picture-wall',
89 )
90 )
91 );
92
93 $this->assertEquals(
94 'http://host.tld/admin/picture-wall',
95 page_url(
96 array(
97 'HTTPS' => 'Off',
98 'SERVER_NAME' => 'host.tld',
99 'SERVER_PORT' => '80',
100 'SCRIPT_NAME' => '/admin/index.php',
101 'REQUEST_URI' => '/admin/picture-wall',
102 )
103 )
104 );
105 }
74} 106}
diff --git a/tests/render/PageCacheManagerTest.php b/tests/render/PageCacheManagerTest.php
index 991515d0..b870e6eb 100644
--- a/tests/render/PageCacheManagerTest.php
+++ b/tests/render/PageCacheManagerTest.php
@@ -32,7 +32,7 @@ class PageCacheManagerTest extends TestCase
32 */ 32 */
33 public function setUp() 33 public function setUp()
34 { 34 {
35 $this->cacheManager = new PageCacheManager(static::$testCacheDir); 35 $this->cacheManager = new PageCacheManager(static::$testCacheDir, true);
36 36
37 if (!is_dir(self::$testCacheDir)) { 37 if (!is_dir(self::$testCacheDir)) {
38 mkdir(self::$testCacheDir); 38 mkdir(self::$testCacheDir);
@@ -73,7 +73,7 @@ class PageCacheManagerTest extends TestCase
73 */ 73 */
74 public function testPurgeCachedPagesMissingDir() 74 public function testPurgeCachedPagesMissingDir()
75 { 75 {
76 $this->cacheManager = new PageCacheManager(self::$testCacheDir . '_missing'); 76 $this->cacheManager = new PageCacheManager(self::$testCacheDir . '_missing', true);
77 77
78 $oldlog = ini_get('error_log'); 78 $oldlog = ini_get('error_log');
79 ini_set('error_log', '/dev/null'); 79 ini_set('error_log', '/dev/null');
diff --git a/tpl/default/daily.html b/tpl/default/daily.html
index f07c0a8b..9ccd1e61 100644
--- a/tpl/default/daily.html
+++ b/tpl/default/daily.html
@@ -11,7 +11,7 @@
11 <div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor" id="daily"> 11 <div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor" id="daily">
12 <h2 class="window-title"> 12 <h2 class="window-title">
13 {'The Daily Shaarli'|t} 13 {'The Daily Shaarli'|t}
14 <a href="./?do=dailyrss" title="{'1 RSS entry per day'|t}"><i class="fa fa-rss"></i></a> 14 <a href="./daily-rss" title="{'1 RSS entry per day'|t}"><i class="fa fa-rss"></i></a>
15 </h2> 15 </h2>
16 16
17 <div id="plugin_zone_start_daily" class="plugin_zone"> 17 <div id="plugin_zone_start_daily" class="plugin_zone">
diff --git a/tpl/default/dailyrss.html b/tpl/default/dailyrss.html
index f589b06e..d40d9496 100644
--- a/tpl/default/dailyrss.html
+++ b/tpl/default/dailyrss.html
@@ -1,16 +1,32 @@
1<item> 1<?xml version="1.0" encoding="UTF-8"?>
2 <title>{$title} - {function="strftime('%A %e %B %Y', $daydate)"}</title> 2<rss version="2.0">
3 <guid>{$absurl}</guid> 3 <channel>
4 <link>{$absurl}</link> 4 <title>Daily - {$title}</title>
5 <pubDate>{$rssdate}</pubDate> 5 <link>{$index_url}</link>
6 <description><![CDATA[ 6 <description>Daily shaared bookmarks</description>
7 {loop="links"} 7 <language>{$language}</language>
8 <h3><a href="{$value.url}">{$value.title}</a></h3> 8 <copyright>{$index_url}</copyright>
9 <small>{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br> 9 <generator>Shaarli</generator>
10 {$value.url}</small><br> 10
11 {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br> 11 {loop="$days"}
12 {if="$value.description"}{$value.formatedDescription}{/if} 12 <item>
13 <br><br><hr> 13 <title>{$value.date_human} - {$title}</title>
14 {/loop} 14 <guid>{$value.absolute_url}</guid>
15 ]]></description> 15 <link>{$value.absolute_url}</link>
16</item> 16 <pubDate>{$value.date_rss}</pubDate>
17 <description><![CDATA[
18 {loop="$value.links"}
19 <h3><a href="{$value.url}">{$value.title}</a></h3>
20 <small>
21 {if="!$hide_timestamps"}{$value.created|format_date} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
22 {$value.url}
23 </small><br>
24 {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
25 {if="$value.description"}{$value.description}{/if}
26 <br><br><hr>
27 {/loop}
28 ]]></description>
29 </item>
30 {/loop}
31 </channel>
32</rss><!-- Cached version of {$page_url} -->
diff --git a/tpl/vintage/daily.html b/tpl/vintage/daily.html
index 4892e0e1..adcdf6ab 100644
--- a/tpl/vintage/daily.html
+++ b/tpl/vintage/daily.html
@@ -24,7 +24,7 @@
24 {/loop} 24 {/loop}
25 25
26 <br> 26 <br>
27 <a href="./?do=dailyrss" title="1 RSS entry per day"><img src="img/feed-icon-14x14.png" alt="rss_feed">Daily RSS Feed</a> 27 <a href="./daily-rss" title="1 RSS entry per day"><img src="img/feed-icon-14x14.png" alt="rss_feed">Daily RSS Feed</a>
28 </div> 28 </div>
29 29
30 <div class="dailyTitle"> 30 <div class="dailyTitle">
diff --git a/tpl/vintage/dailyrss.html b/tpl/vintage/dailyrss.html
index f589b06e..ff19bbfb 100644
--- a/tpl/vintage/dailyrss.html
+++ b/tpl/vintage/dailyrss.html
@@ -1,16 +1,32 @@
1<item> 1<?xml version="1.0" encoding="UTF-8"?>
2 <title>{$title} - {function="strftime('%A %e %B %Y', $daydate)"}</title> 2<rss version="2.0">
3 <guid>{$absurl}</guid> 3 <channel>
4 <link>{$absurl}</link> 4 <title>Daily - {$title}</title>
5 <pubDate>{$rssdate}</pubDate> 5 <link>{$index_url}</link>
6 <description><![CDATA[ 6 <description>Daily shaared bookmarks</description>
7 {loop="links"} 7 <language>{$language}</language>
8 <h3><a href="{$value.url}">{$value.title}</a></h3> 8 <copyright>{$index_url}</copyright>
9 <small>{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br> 9 <generator>Shaarli</generator>
10 {$value.url}</small><br> 10
11 {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br> 11 {loop="$days"}
12 {if="$value.description"}{$value.formatedDescription}{/if} 12 <item>
13 <br><br><hr> 13 <title>{$value.date_human} - {$title}</title>
14 <guid>{$value.absolute_url}</guid>
15 <link>{$value.absolute_url}</link>
16 <pubDate>{$value.date_rss}</pubDate>
17 <description><![CDATA[
18 {loop="$value.links"}
19 <h3><a href="{$value.url}">{$value.title}</a></h3>
20 <small>
21 {if="!$hide_timestamps"}{$value.created|format_date} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
22 {$value.url}
23 </small><br>
24 {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
25 {if="$value.description"}{$value.description}{/if}
26 <br><br><hr>
14 {/loop} 27 {/loop}
15 ]]></description> 28 ]]></description>
16</item> 29 </item>
30 {/loop}
31 </channel>
32</rss><!-- Cached version of {$page_url} -->