The daily RSS template has been entirely rewritten to handle the whole feed through the template engine.
namespace Shaarli\Bookmark;
use DateTime;
+use DateTimeInterface;
use Shaarli\Bookmark\Exception\InvalidBookmarkException;
/**
/** @var bool Set to true if the bookmark is set as sticky */
protected $sticky;
- /** @var DateTime Creation datetime */
+ /** @var DateTimeInterface Creation datetime */
protected $created;
- /** @var DateTime Update datetime */
+ /** @var DateTimeInterface datetime */
protected $updated;
/** @var bool True if the bookmark can only be seen while logged in */
|| ! is_int($this->id)
|| empty($this->shortUrl)
|| empty($this->created)
- || ! $this->created instanceof DateTime
+ || ! $this->created instanceof DateTimeInterface
) {
throw new InvalidBookmarkException($this);
}
/**
* Get the Created.
*
- * @return DateTime
+ * @return DateTimeInterface
*/
public function getCreated()
{
/**
* Get the Updated.
*
- * @return DateTime
+ * @return DateTimeInterface
*/
public function getUpdated()
{
* Set the Created.
* Note: you shouldn't set this manually except for special cases (like bookmark import)
*
- * @param DateTime $created
+ * @param DateTimeInterface $created
*
* @return Bookmark
*/
/**
* Set the Updated.
*
- * @param DateTime $updated
+ * @param DateTimeInterface $updated
*
* @return Bookmark
*/
{
$this->conf = $conf;
$this->history = $history;
- $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache'));
+ $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache'), $isLoggedIn);
$this->bookmarksIO = new BookmarkIO($this->conf);
$this->isLoggedIn = $isLoggedIn;
};
$container['pageCacheManager'] = function (ShaarliContainer $container): PageCacheManager {
- return new PageCacheManager($container->conf->get('resource.page_cache'));
+ return new PageCacheManager(
+ $container->conf->get('resource.page_cache'),
+ $container->loginManager->isLoggedIn()
+ );
};
return $container;
namespace Shaarli\Front\Controller;
use DateTime;
+use DateTimeImmutable;
use Shaarli\Bookmark\Bookmark;
use Slim\Http\Request;
use Slim\Http\Response;
*/
class DailyController extends ShaarliController
{
+ public static $DAILY_RSS_NB_DAYS = 8;
+
/**
* Controller displaying all bookmarks published in a single day.
* It take a `day` date query parameter (format YYYYMMDD).
return $response->write($this->render('daily'));
}
+ /**
+ * Daily RSS feed: 1 RSS entry per day giving all the bookmarks on that day.
+ * Gives the last 7 days (which have bookmarks).
+ * This RSS feed cannot be filtered and does not trigger plugins yet.
+ */
+ public function rss(Request $request, Response $response): Response
+ {
+ $response = $response->withHeader('Content-Type', 'application/rss+xml; charset=utf-8');
+
+ $pageUrl = page_url($this->container->environment);
+ $cache = $this->container->pageCacheManager->getCachePage($pageUrl);
+
+ $cached = $cache->cachedVersion();
+ if (!empty($cached)) {
+ return $response->write($cached);
+ }
+
+ $days = [];
+ foreach ($this->container->bookmarkService->search() as $bookmark) {
+ $day = $bookmark->getCreated()->format('Ymd');
+
+ // Stop iterating after DAILY_RSS_NB_DAYS entries
+ if (count($days) === static::$DAILY_RSS_NB_DAYS && !isset($days[$day])) {
+ break;
+ }
+
+ $days[$day][] = $bookmark;
+ }
+
+ // Build the RSS feed.
+ $indexUrl = escape(index_url($this->container->environment));
+
+ $formatter = $this->container->formatterFactory->getFormatter();
+ $formatter->addContextData('index_url', $indexUrl);
+
+ $dataPerDay = [];
+
+ /** @var Bookmark[] $bookmarks */
+ foreach ($days as $day => $bookmarks) {
+ $dayDatetime = DateTimeImmutable::createFromFormat(Bookmark::LINK_DATE_FORMAT, $day.'_000000');
+ $dataPerDay[$day] = [
+ 'date' => $dayDatetime,
+ 'date_rss' => $dayDatetime->format(DateTime::RSS),
+ 'date_human' => format_date($dayDatetime, false, true),
+ 'absolute_url' => $indexUrl . '/daily?day=' . $day,
+ 'links' => [],
+ ];
+
+ foreach ($bookmarks as $key => $bookmark) {
+ $dataPerDay[$day]['links'][$key] = $formatter->format($bookmark);
+
+ // Make permalink URL absolute
+ if ($bookmark->isNote()) {
+ $dataPerDay[$day]['links'][$key]['url'] = $indexUrl . $bookmark->getUrl();
+ }
+ }
+ }
+
+ $this->assignView('title', $this->container->conf->get('general.title', 'Shaarli'));
+ $this->assignView('index_url', $indexUrl);
+ $this->assignView('page_url', $pageUrl);
+ $this->assignView('hide_timestamps', $this->container->conf->get('privacy.hide_timestamps', false));
+ $this->assignView('days', $dataPerDay);
+
+ $rssContent = $this->render('dailyrss');
+
+ $cache->cache($rssContent);
+
+ return $response->write($rssContent);
+ }
+
/**
* We need to spread the articles on 3 columns.
* did not want to use a JavaScript lib like http://masonry.desandro.com/
*/
function index_url($server)
{
- $scriptname = $server['SCRIPT_NAME'];
+ $scriptname = $server['SCRIPT_NAME'] ?? '';
if (endsWith($scriptname, 'index.php')) {
$scriptname = substr($scriptname, 0, -9);
}
}
/**
- * Returns the absolute URL of the current script, with the query
+ * Returns the absolute URL of the current script, with current route and query
*
* If the resource is "index.php", then it is removed (for better-looking URLs)
*
*/
function page_url($server)
{
+ $scriptname = $server['SCRIPT_NAME'] ?? '';
+ if (endsWith($scriptname, 'index.php')) {
+ $scriptname = substr($scriptname, 0, -9);
+ }
+
+ $route = ltrim($server['REQUEST_URI'] ?? '', $scriptname);
if (! empty($server['QUERY_STRING'])) {
- return index_url($server).'?'.$server['QUERY_STRING'];
+ return index_url($server) . $route . '?' . $server['QUERY_STRING'];
}
- return index_url($server);
+
+ return index_url($server) . $route;
}
/**
$this->write();
- $pageCacheManager = new PageCacheManager($pageCacheDir);
+ $pageCacheManager = new PageCacheManager($pageCacheDir, $this->loggedIn);
$pageCacheManager->invalidateCaches();
}
namespace Shaarli\Render;
+use Shaarli\Feed\CachedPage;
+
/**
* Cache utilities
*/
/** @var string Cache directory */
protected $pageCacheDir;
- public function __construct(string $pageCacheDir)
+ /** @var bool */
+ protected $isLoggedIn;
+
+ public function __construct(string $pageCacheDir, bool $isLoggedIn)
{
$this->pageCacheDir = $pageCacheDir;
+ $this->isLoggedIn = $isLoggedIn;
}
/**
// Purge page cache shared by sessions.
$this->purgeCachedPages();
}
+
+ public function getCachePage(string $pageUrl): CachedPage
+ {
+ return new CachedPage(
+ $this->pageCacheDir,
+ $pageUrl,
+ false === $this->isLoggedIn
+ );
+ }
}
$_SESSION['tokens']=array(); // Token are attached to the session.
}
-/**
- * Daily RSS feed: 1 RSS entry per day giving all the bookmarks on that day.
- * Gives the last 7 days (which have bookmarks).
- * This RSS feed cannot be filtered.
- *
- * @param BookmarkServiceInterface $bookmarkService
- * @param ConfigManager $conf Configuration Manager instance
- * @param LoginManager $loginManager LoginManager instance
- */
-function showDailyRSS($bookmarkService, $conf, $loginManager)
-{
- // Cache system
- $query = $_SERVER['QUERY_STRING'];
- $cache = new CachedPage(
- $conf->get('config.PAGE_CACHE'),
- page_url($_SERVER),
- startsWith($query, 'do=dailyrss') && !$loginManager->isLoggedIn()
- );
- $cached = $cache->cachedVersion();
- if (!empty($cached)) {
- echo $cached;
- exit;
- }
-
- /* Some Shaarlies may have very few bookmarks, so we need to look
- back in time until we have enough days ($nb_of_days).
- */
- $nb_of_days = 7; // We take 7 days.
- $today = date('Ymd');
- $days = array();
-
- foreach ($bookmarkService->search() as $bookmark) {
- $day = $bookmark->getCreated()->format('Ymd'); // Extract day (without time)
- if (strcmp($day, $today) < 0) {
- if (empty($days[$day])) {
- $days[$day] = array();
- }
- $days[$day][] = $bookmark;
- }
-
- if (count($days) > $nb_of_days) {
- break; // Have we collected enough days?
- }
- }
-
- // Build the RSS feed.
- header('Content-Type: application/rss+xml; charset=utf-8');
- $pageaddr = escape(index_url($_SERVER));
- echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">';
- echo '<channel>';
- echo '<title>Daily - '. $conf->get('general.title') . '</title>';
- echo '<link>'. $pageaddr .'</link>';
- echo '<description>Daily shared bookmarks</description>';
- echo '<language>en-en</language>';
- echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL;
-
- $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
- $formatter = $factory->getFormatter();
- $formatter->addContextData('index_url', index_url($_SERVER));
- // For each day.
- /** @var Bookmark[] $bookmarks */
- foreach ($days as $day => $bookmarks) {
- $formattedBookmarks = [];
- $dayDate = DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, $day.'_000000');
- $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
-
- // We pre-format some fields for proper output.
- foreach ($bookmarks as $key => $bookmark) {
- $formattedBookmarks[$key] = $formatter->format($bookmark);
- // This page is a bit specific, we need raw description to calculate the length
- $formattedBookmarks[$key]['formatedDescription'] = $formattedBookmarks[$key]['description'];
- $formattedBookmarks[$key]['description'] = $bookmark->getDescription();
-
- if ($bookmark->isNote()) {
- $link['url'] = index_url($_SERVER) . $bookmark->getUrl(); // make permalink URL absolute
- }
- }
-
- // Then build the HTML for this day:
- $tpl = new RainTPL();
- $tpl->assign('title', $conf->get('general.title'));
- $tpl->assign('daydate', $dayDate->getTimestamp());
- $tpl->assign('absurl', $absurl);
- $tpl->assign('links', $formattedBookmarks);
- $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS)));
- $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false));
- $tpl->assign('index_url', $pageaddr);
- $html = $tpl->draw('dailyrss', true);
-
- echo $html . PHP_EOL;
- }
- echo '</channel></rss><!-- Cached version of '. escape(page_url($_SERVER)) .' -->';
-
- $cache->cache(ob_get_contents());
- ob_end_flush();
- exit;
-}
-
/**
* Renders the linklist
*
*/
function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionManager, $loginManager)
{
- $pageCacheManager = new PageCacheManager($conf->get('resource.page_cache'));
+ $pageCacheManager = new PageCacheManager($conf->get('resource.page_cache'), $loginManager->isLoggedIn());
$updater = new Updater(
UpdaterUtils::read_updates_file($conf->get('resource.updates')),
$bookmarkService,
$linkDb = new BookmarkFileService($conf, $history, $loginManager->isLoggedIn());
if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) {
- showDailyRSS($linkDb, $conf, $loginManager);
+ header('Location: ./daily-rss');
exit;
}
$this->get('/tag-cloud', '\Shaarli\Front\Controller\TagCloudController:cloud')->setName('tagcloud');
$this->get('/tag-list', '\Shaarli\Front\Controller\TagCloudController:list')->setName('taglist');
$this->get('/daily', '\Shaarli\Front\Controller\DailyController:index')->setName('daily');
+ $this->get('/daily-rss', '\Shaarli\Front\Controller\DailyController:rss')->setName('dailyrss');
$this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\TagController:addTag')->setName('add-tag');
})->add('\Shaarli\Front\ShaarliMiddleware');
use Shaarli\Bookmark\BookmarkServiceInterface;
use Shaarli\Config\ConfigManager;
use Shaarli\Container\ShaarliContainer;
+use Shaarli\Feed\CachedPage;
use Shaarli\Formatter\BookmarkFormatter;
use Shaarli\Formatter\BookmarkRawFormatter;
use Shaarli\Formatter\FormatterFactory;
use Shaarli\Plugin\PluginManager;
use Shaarli\Render\PageBuilder;
+use Shaarli\Render\PageCacheManager;
use Shaarli\Security\LoginManager;
use Slim\Http\Request;
use Slim\Http\Response;
{
$this->container = $this->createMock(ShaarliContainer::class);
$this->controller = new DailyController($this->container);
+ DailyController::$DAILY_RSS_NB_DAYS = 2;
}
- public function testValidControllerInvokeDefault(): void
+ public function testValidIndexControllerInvokeDefault(): void
{
$this->createValidContainerMockSet();
/**
* Daily page - test that everything goes fine with no future or past bookmarks
*/
- public function testValidControllerInvokeNoFutureOrPast(): void
+ public function testValidIndexControllerInvokeNoFutureOrPast(): void
{
$this->createValidContainerMockSet();
/**
* Daily page - test that height adjustment in columns is working
*/
- public function testValidControllerInvokeHeightAdjustment(): void
+ public function testValidIndexControllerInvokeHeightAdjustment(): void
{
$this->createValidContainerMockSet();
/**
* Daily page - no bookmark
*/
- public function testValidControllerInvokeNoBookmark(): void
+ public function testValidIndexControllerInvokeNoBookmark(): void
{
$this->createValidContainerMockSet();
static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']);
}
+ /**
+ * Daily RSS - default behaviour
+ */
+ public function testValidRssControllerInvokeDefault(): void
+ {
+ $this->createValidContainerMockSet();
+
+ $dates = [
+ new \DateTimeImmutable('2020-05-17'),
+ new \DateTimeImmutable('2020-05-15'),
+ new \DateTimeImmutable('2020-05-13'),
+ ];
+
+ $request = $this->createMock(Request::class);
+ $response = new Response();
+
+ $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
+ (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
+ (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
+ (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
+ (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'),
+ ]);
+
+ $this->container->pageCacheManager
+ ->expects(static::once())
+ ->method('getCachePage')
+ ->willReturnCallback(function (): CachedPage {
+ $cachedPage = $this->createMock(CachedPage::class);
+ $cachedPage->expects(static::once())->method('cache')->with('dailyrss');
+
+ return $cachedPage;
+ }
+ );
+
+ // Save RainTPL assigned variables
+ $assignedVariables = [];
+ $this->assignTemplateVars($assignedVariables);
+
+ $result = $this->controller->rss($request, $response);
+
+ static::assertSame(200, $result->getStatusCode());
+ static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
+ static::assertSame('dailyrss', (string) $result->getBody());
+ static::assertSame('Shaarli', $assignedVariables['title']);
+ static::assertSame('http://shaarli', $assignedVariables['index_url']);
+ static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
+ static::assertFalse($assignedVariables['hide_timestamps']);
+ static::assertCount(2, $assignedVariables['days']);
+
+ $day = $assignedVariables['days'][$dates[0]->format('Ymd')];
+
+ static::assertEquals($dates[0], $day['date']);
+ static::assertSame($dates[0]->format(\DateTimeInterface::RSS), $day['date_rss']);
+ static::assertSame(format_date($dates[0], false), $day['date_human']);
+ static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
+ static::assertCount(1, $day['links']);
+ static::assertSame(1, $day['links'][0]['id']);
+ static::assertSame('http://domain.tld/1', $day['links'][0]['url']);
+ static::assertEquals($dates[0], $day['links'][0]['created']);
+
+ $day = $assignedVariables['days'][$dates[1]->format('Ymd')];
+
+ static::assertEquals($dates[1], $day['date']);
+ static::assertSame($dates[1]->format(\DateTimeInterface::RSS), $day['date_rss']);
+ static::assertSame(format_date($dates[1], false), $day['date_human']);
+ static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
+ static::assertCount(2, $day['links']);
+
+ static::assertSame(2, $day['links'][0]['id']);
+ static::assertSame('http://domain.tld/2', $day['links'][0]['url']);
+ static::assertEquals($dates[1], $day['links'][0]['created']);
+ static::assertSame(3, $day['links'][1]['id']);
+ static::assertSame('http://domain.tld/3', $day['links'][1]['url']);
+ static::assertEquals($dates[1], $day['links'][1]['created']);
+ }
+
+ /**
+ * Daily RSS - trigger cache rendering
+ */
+ public function testValidRssControllerInvokeTriggerCache(): void
+ {
+ $this->createValidContainerMockSet();
+
+ $request = $this->createMock(Request::class);
+ $response = new Response();
+
+ $this->container->pageCacheManager->method('getCachePage')->willReturnCallback(function (): CachedPage {
+ $cachedPage = $this->createMock(CachedPage::class);
+ $cachedPage->method('cachedVersion')->willReturn('this is cache!');
+
+ return $cachedPage;
+ });
+
+ $this->container->bookmarkService->expects(static::never())->method('search');
+
+ $result = $this->controller->rss($request, $response);
+
+ static::assertSame(200, $result->getStatusCode());
+ static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
+ static::assertSame('this is cache!', (string) $result->getBody());
+ }
+
+ /**
+ * Daily RSS - No bookmark
+ */
+ public function testValidRssControllerInvokeNoBookmark(): void
+ {
+ $this->createValidContainerMockSet();
+
+ $request = $this->createMock(Request::class);
+ $response = new Response();
+
+ $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]);
+
+ // Save RainTPL assigned variables
+ $assignedVariables = [];
+ $this->assignTemplateVars($assignedVariables);
+
+ $result = $this->controller->rss($request, $response);
+
+ static::assertSame(200, $result->getStatusCode());
+ static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
+ static::assertSame('dailyrss', (string) $result->getBody());
+ static::assertSame('Shaarli', $assignedVariables['title']);
+ static::assertSame('http://shaarli', $assignedVariables['index_url']);
+ static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
+ static::assertFalse($assignedVariables['hide_timestamps']);
+ static::assertCount(0, $assignedVariables['days']);
+ }
+
protected function createValidContainerMockSet(): void
{
$loginManager = $this->createMock(LoginManager::class);
})
;
$this->container->formatterFactory = $formatterFactory;
+
+ // CacheManager
+ $pageCacheManager = $this->createMock(PageCacheManager::class);
+ $this->container->pageCacheManager = $pageCacheManager;
+
+ // $_SERVER
+ $this->container->environment = [
+ 'SERVER_NAME' => 'shaarli',
+ 'SERVER_PORT' => '80',
+ 'REQUEST_URI' => '/daily-rss',
+ ];
}
protected function assignTemplateVars(array &$variables): void
)
);
}
+
+ /**
+ * The route is stored in REQUEST_URI
+ */
+ public function testPageUrlWithRoute()
+ {
+ $this->assertEquals(
+ 'http://host.tld/picture-wall',
+ page_url(
+ array(
+ 'HTTPS' => 'Off',
+ 'SERVER_NAME' => 'host.tld',
+ 'SERVER_PORT' => '80',
+ 'SCRIPT_NAME' => '/index.php',
+ 'REQUEST_URI' => '/picture-wall',
+ )
+ )
+ );
+
+ $this->assertEquals(
+ 'http://host.tld/admin/picture-wall',
+ page_url(
+ array(
+ 'HTTPS' => 'Off',
+ 'SERVER_NAME' => 'host.tld',
+ 'SERVER_PORT' => '80',
+ 'SCRIPT_NAME' => '/admin/index.php',
+ 'REQUEST_URI' => '/admin/picture-wall',
+ )
+ )
+ );
+ }
}
*/
public function setUp()
{
- $this->cacheManager = new PageCacheManager(static::$testCacheDir);
+ $this->cacheManager = new PageCacheManager(static::$testCacheDir, true);
if (!is_dir(self::$testCacheDir)) {
mkdir(self::$testCacheDir);
*/
public function testPurgeCachedPagesMissingDir()
{
- $this->cacheManager = new PageCacheManager(self::$testCacheDir . '_missing');
+ $this->cacheManager = new PageCacheManager(self::$testCacheDir . '_missing', true);
$oldlog = ini_get('error_log');
ini_set('error_log', '/dev/null');
<div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor" id="daily">
<h2 class="window-title">
{'The Daily Shaarli'|t}
- <a href="./?do=dailyrss" title="{'1 RSS entry per day'|t}"><i class="fa fa-rss"></i></a>
+ <a href="./daily-rss" title="{'1 RSS entry per day'|t}"><i class="fa fa-rss"></i></a>
</h2>
<div id="plugin_zone_start_daily" class="plugin_zone">
-<item>
- <title>{$title} - {function="strftime('%A %e %B %Y', $daydate)"}</title>
- <guid>{$absurl}</guid>
- <link>{$absurl}</link>
- <pubDate>{$rssdate}</pubDate>
- <description><![CDATA[
- {loop="links"}
- <h3><a href="{$value.url}">{$value.title}</a></h3>
- <small>{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
- {$value.url}</small><br>
- {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
- {if="$value.description"}{$value.formatedDescription}{/if}
- <br><br><hr>
- {/loop}
- ]]></description>
-</item>
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0">
+ <channel>
+ <title>Daily - {$title}</title>
+ <link>{$index_url}</link>
+ <description>Daily shaared bookmarks</description>
+ <language>{$language}</language>
+ <copyright>{$index_url}</copyright>
+ <generator>Shaarli</generator>
+
+ {loop="$days"}
+ <item>
+ <title>{$value.date_human} - {$title}</title>
+ <guid>{$value.absolute_url}</guid>
+ <link>{$value.absolute_url}</link>
+ <pubDate>{$value.date_rss}</pubDate>
+ <description><![CDATA[
+ {loop="$value.links"}
+ <h3><a href="{$value.url}">{$value.title}</a></h3>
+ <small>
+ {if="!$hide_timestamps"}{$value.created|format_date} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
+ {$value.url}
+ </small><br>
+ {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
+ {if="$value.description"}{$value.description}{/if}
+ <br><br><hr>
+ {/loop}
+ ]]></description>
+ </item>
+ {/loop}
+ </channel>
+</rss><!-- Cached version of {$page_url} -->
{/loop}
<br>
- <a href="./?do=dailyrss" title="1 RSS entry per day"><img src="img/feed-icon-14x14.png" alt="rss_feed">Daily RSS Feed</a>
+ <a href="./daily-rss" title="1 RSS entry per day"><img src="img/feed-icon-14x14.png" alt="rss_feed">Daily RSS Feed</a>
</div>
<div class="dailyTitle">
-<item>
- <title>{$title} - {function="strftime('%A %e %B %Y', $daydate)"}</title>
- <guid>{$absurl}</guid>
- <link>{$absurl}</link>
- <pubDate>{$rssdate}</pubDate>
- <description><![CDATA[
- {loop="links"}
- <h3><a href="{$value.url}">{$value.title}</a></h3>
- <small>{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
- {$value.url}</small><br>
- {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
- {if="$value.description"}{$value.formatedDescription}{/if}
- <br><br><hr>
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0">
+ <channel>
+ <title>Daily - {$title}</title>
+ <link>{$index_url}</link>
+ <description>Daily shaared bookmarks</description>
+ <language>{$language}</language>
+ <copyright>{$index_url}</copyright>
+ <generator>Shaarli</generator>
+
+ {loop="$days"}
+ <item>
+ <title>{$value.date_human} - {$title}</title>
+ <guid>{$value.absolute_url}</guid>
+ <link>{$value.absolute_url}</link>
+ <pubDate>{$value.date_rss}</pubDate>
+ <description><![CDATA[
+ {loop="$value.links"}
+ <h3><a href="{$value.url}">{$value.title}</a></h3>
+ <small>
+ {if="!$hide_timestamps"}{$value.created|format_date} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
+ {$value.url}
+ </small><br>
+ {if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
+ {if="$value.description"}{$value.description}{/if}
+ <br><br><hr>
{/loop}
- ]]></description>
-</item>
+ ]]></description>
+ </item>
+ {/loop}
+ </channel>
+</rss><!-- Cached version of {$page_url} -->