]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Merge pull request #1671 from ArthurHoaro/fix/plugin-colors-update
authorArthurHoaro <arthur@hoa.ro>
Sun, 3 Jan 2021 10:43:54 +0000 (11:43 +0100)
committerGitHub <noreply@github.com>
Sun, 3 Jan 2021 10:43:54 +0000 (11:43 +0100)
Fix default_colors plugin: update CSS file on color change

15 files changed:
application/api/ApiUtils.php
application/api/controllers/Links.php
application/bookmark/LinkUtils.php
application/feed/CachedPage.php
application/front/controller/admin/ShaarePublishController.php
application/front/controller/visitor/DailyController.php
application/helper/DailyPageHelper.php
application/http/MetadataRetriever.php
application/render/PageCacheManager.php
tests/api/controllers/links/PostLinkTest.php
tests/api/controllers/links/PutLinkTest.php
tests/bookmark/LinkUtilsTest.php
tests/feed/CachedPageTest.php
tests/helper/DailyPageHelperTest.php
tests/http/MetadataRetrieverTest.php

index 05a2840a6221d3c50c215c7994415c586b01677c..9228bb2da768fcb7e8ba187f6494ff6fd8671666 100644 (file)
@@ -91,13 +91,17 @@ class ApiUtils
      * If no URL is provided, it will generate a local note URL.
      * If no title is provided, it will use the URL as title.
      *
-     * @param array|null  $input          Request Link.
-     * @param bool        $defaultPrivate Setting defined if a bookmark is private by default.
+     * @param array|null $input          Request Link.
+     * @param bool       $defaultPrivate Setting defined if a bookmark is private by default.
+     * @param string     $tagsSeparator  Tags separator loaded from the config file.
      *
      * @return Bookmark instance.
      */
-    public static function buildBookmarkFromRequest(?array $input, bool $defaultPrivate): Bookmark
-    {
+    public static function buildBookmarkFromRequest(
+        ?array $input,
+        bool $defaultPrivate,
+        string $tagsSeparator
+    ): Bookmark {
         $bookmark = new Bookmark();
         $url = ! empty($input['url']) ? cleanup_url($input['url']) : '';
         if (isset($input['private'])) {
@@ -109,6 +113,15 @@ class ApiUtils
         $bookmark->setTitle(! empty($input['title']) ? $input['title'] : '');
         $bookmark->setUrl($url);
         $bookmark->setDescription(! empty($input['description']) ? $input['description'] : '');
+
+        // Be permissive with provided tags format
+        if (is_string($input['tags'] ?? null)) {
+            $input['tags'] = tags_str2array($input['tags'], $tagsSeparator);
+        }
+        if (is_array($input['tags'] ?? null) && count($input['tags']) === 1 && is_string($input['tags'][0])) {
+            $input['tags'] = tags_str2array($input['tags'][0], $tagsSeparator);
+        }
+
         $bookmark->setTags(! empty($input['tags']) ? $input['tags'] : []);
         $bookmark->setPrivate($private);
 
index c379b9622c6120b3eb8c29bde4702c17074a0961..b83b2260f4ef670ad091c35d55620968eabd38ad 100644 (file)
@@ -117,7 +117,11 @@ class Links extends ApiController
     public function postLink($request, $response)
     {
         $data = (array) ($request->getParsedBody() ?? []);
-        $bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links'));
+        $bookmark = ApiUtils::buildBookmarkFromRequest(
+            $data,
+            $this->conf->get('privacy.default_private_links'),
+            $this->conf->get('general.tags_separator', ' ')
+        );
         // duplicate by URL, return 409 Conflict
         if (
             ! empty($bookmark->getUrl())
@@ -158,7 +162,11 @@ class Links extends ApiController
         $index = index_url($this->ci['environment']);
         $data = $request->getParsedBody();
 
-        $requestBookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links'));
+        $requestBookmark = ApiUtils::buildBookmarkFromRequest(
+            $data,
+            $this->conf->get('privacy.default_private_links'),
+            $this->conf->get('general.tags_separator', ' ')
+        );
         // duplicate URL on a different link, return 409 Conflict
         if (
             ! empty($requestBookmark->getUrl())
index d65e97ed47ca9163bb8f0f9feef66969b1981166..0ab2d2138c5a01f620744dfac40e091ddd3aadaa 100644 (file)
@@ -68,11 +68,13 @@ function html_extract_tag($tag, $html)
     $properties = implode('|', $propertiesKey);
     // We need a OR here to accept either 'property=og:noquote' or 'property="og:unrelated og:my-tag"'
     $orCondition  = '["\']?(?:og:)?' . $tag . '["\']?|["\'][^\'"]*?(?:og:)?' . $tag . '[^\'"]*?[\'"]';
+    // Support quotes in double quoted content, and the other way around
+    $content = 'content=(["\'])((?:(?!\1).)*)\1';
     // Try to retrieve OpenGraph tag.
-    $ogRegex = '#<meta[^>]+(?:' . $properties . ')=(?:' . $orCondition . ')[^>]*content=(["\'])([^\1]*?)\1.*?>#';
+    $ogRegex = '#<meta[^>]+(?:' . $properties . ')=(?:' . $orCondition . ')[^>]*' . $content . '.*?>#';
     // If the attributes are not in the order property => content (e.g. Github)
     // New regex to keep this readable... more or less.
-    $ogRegexReverse = '#<meta[^>]+content=(["\'])([^\1]*?)\1[^>]+(?:' . $properties . ')=(?:' . $orCondition . ').*?>#';
+    $ogRegexReverse = '#<meta[^>]+' . $content . '[^>]+(?:' . $properties . ')=(?:' . $orCondition . ').*?>#';
 
     if (
         preg_match($ogRegex, $html, $matches) > 0
index d809bdd962ca901c54536309d17068652ff5f3bd..c23c200f3370869b952cc681daf98cfc456c4666 100644 (file)
@@ -1,34 +1,43 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Shaarli\Feed;
 
+use DatePeriod;
+
 /**
  * Simple cache system, mainly for the RSS/ATOM feeds
  */
 class CachedPage
 {
-    // Directory containing page caches
-    private $cacheDir;
+    /** Directory containing page caches */
+    protected $cacheDir;
+
+    /** Should this URL be cached (boolean)? */
+    protected $shouldBeCached;
 
-    // Should this URL be cached (boolean)?
-    private $shouldBeCached;
+    /** Name of the cache file for this URL */
+    protected $filename;
 
-    // Name of the cache file for this URL
-    private $filename;
+    /** @var DatePeriod|null Optionally specify a period of time for cache validity */
+    protected $validityPeriod;
 
     /**
      * Creates a new CachedPage
      *
-     * @param string $cacheDir       page cache directory
-     * @param string $url            page URL
-     * @param bool   $shouldBeCached whether this page needs to be cached
+     * @param string      $cacheDir       page cache directory
+     * @param string      $url            page URL
+     * @param bool        $shouldBeCached whether this page needs to be cached
+     * @param ?DatePeriod $validityPeriod Optionally specify a time limit on requested cache
      */
-    public function __construct($cacheDir, $url, $shouldBeCached)
+    public function __construct($cacheDir, $url, $shouldBeCached, ?DatePeriod $validityPeriod)
     {
         // TODO: check write access to the cache directory
         $this->cacheDir = $cacheDir;
         $this->filename = $this->cacheDir . '/' . sha1($url) . '.cache';
         $this->shouldBeCached = $shouldBeCached;
+        $this->validityPeriod = $validityPeriod;
     }
 
     /**
@@ -41,10 +50,20 @@ class CachedPage
         if (!$this->shouldBeCached) {
             return null;
         }
-        if (is_file($this->filename)) {
-            return file_get_contents($this->filename);
+        if (!is_file($this->filename)) {
+            return null;
+        }
+        if ($this->validityPeriod !== null) {
+            $cacheDate = \DateTime::createFromFormat('U', (string) filemtime($this->filename));
+            if (
+                $cacheDate < $this->validityPeriod->getStartDate()
+                || $cacheDate > $this->validityPeriod->getEndDate()
+            ) {
+                return null;
+            }
         }
-        return null;
+
+        return file_get_contents($this->filename);
     }
 
     /**
index 4cbfcdc503f2abeaaefc839056949bfe337c2188..fb9cacc22fae47b3e9bc57cfe054292f4511b87d 100644 (file)
@@ -227,7 +227,7 @@ class ShaarePublishController extends ShaarliAdminController
 
     protected function buildFormData(array $link, bool $isNew, Request $request): array
     {
-        $link['tags'] = strlen($link['tags']) > 0
+        $link['tags'] = $link['tags'] !== null && strlen($link['tags']) > 0
             ? $link['tags'] . $this->container->conf->get('general.tags_separator', ' ')
             : $link['tags']
         ;
index 5ae8929929374b85fbc48127cc1e8119c43e0b2a..29492a5f3c1f3acd50d65547d9d3543dbf7e7a8a 100644 (file)
@@ -86,9 +86,11 @@ class DailyController extends ShaarliVisitorController
     public function rss(Request $request, Response $response): Response
     {
         $response = $response->withHeader('Content-Type', 'application/rss+xml; charset=utf-8');
+        $type = DailyPageHelper::extractRequestedType($request);
+        $cacheDuration = DailyPageHelper::getCacheDatePeriodByType($type);
 
         $pageUrl = page_url($this->container->environment);
-        $cache = $this->container->pageCacheManager->getCachePage($pageUrl);
+        $cache = $this->container->pageCacheManager->getCachePage($pageUrl, $cacheDuration);
 
         $cached = $cache->cachedVersion();
         if (!empty($cached)) {
@@ -96,7 +98,6 @@ class DailyController extends ShaarliVisitorController
         }
 
         $days = [];
-        $type = DailyPageHelper::extractRequestedType($request);
         $format = DailyPageHelper::getFormatByType($type);
         $length = DailyPageHelper::getRssLengthByType($type);
         foreach ($this->container->bookmarkService->search() as $bookmark) {
index 9bdb7ba5030eb5093fe05d3e08264a700410ca66..05f95812a279825b5b31372d4e4761d424189f5e 100644 (file)
@@ -4,6 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Helper;
 
+use DatePeriod;
+use DateTimeImmutable;
+use Exception;
 use Shaarli\Bookmark\Bookmark;
 use Slim\Http\Request;
 
@@ -40,31 +43,31 @@ class DailyPageHelper
      * @param string|null   $requestedDate  Input string extracted from the request
      * @param Bookmark|null $latestBookmark Latest bookmark found in the datastore (by date)
      *
-     * @return \DateTimeImmutable from input or latest bookmark.
+     * @return DateTimeImmutable from input or latest bookmark.
      *
-     * @throws \Exception Type not supported.
+     * @throws Exception Type not supported.
      */
     public static function extractRequestedDateTime(
         string $type,
         ?string $requestedDate,
         Bookmark $latestBookmark = null
-    ): \DateTimeImmutable {
+    ): DateTimeImmutable {
         $format = static::getFormatByType($type);
         if (empty($requestedDate)) {
             return $latestBookmark instanceof Bookmark
-                ? new \DateTimeImmutable($latestBookmark->getCreated()->format(\DateTime::ATOM))
-                : new \DateTimeImmutable()
+                ? new DateTimeImmutable($latestBookmark->getCreated()->format(\DateTime::ATOM))
+                : new DateTimeImmutable()
             ;
         }
 
         // W is not supported by createFromFormat...
         if ($type === static::WEEK) {
-            return (new \DateTimeImmutable())
+            return (new DateTimeImmutable())
                 ->setISODate((int) substr($requestedDate, 0, 4), (int) substr($requestedDate, 4, 2))
             ;
         }
 
-        return \DateTimeImmutable::createFromFormat($format, $requestedDate);
+        return DateTimeImmutable::createFromFormat($format, $requestedDate);
     }
 
     /**
@@ -80,7 +83,7 @@ class DailyPageHelper
      *
      * @see https://www.php.net/manual/en/datetime.format.php
      *
-     * @throws \Exception Type not supported.
+     * @throws Exception Type not supported.
      */
     public static function getFormatByType(string $type): string
     {
@@ -92,7 +95,7 @@ class DailyPageHelper
             case static::DAY:
                 return 'Ymd';
             default:
-                throw new \Exception('Unsupported daily format type');
+                throw new Exception('Unsupported daily format type');
         }
     }
 
@@ -102,14 +105,14 @@ class DailyPageHelper
      *       and we don't want to alter original datetime.
      *
      * @param string             $type      month/week/day
-     * @param \DateTimeImmutable $requested DateTime extracted from request input
+     * @param DateTimeImmutable $requested DateTime extracted from request input
      *                                      (should come from extractRequestedDateTime)
      *
      * @return \DateTimeInterface First DateTime of the time period
      *
-     * @throws \Exception Type not supported.
+     * @throws Exception Type not supported.
      */
-    public static function getStartDateTimeByType(string $type, \DateTimeImmutable $requested): \DateTimeInterface
+    public static function getStartDateTimeByType(string $type, DateTimeImmutable $requested): \DateTimeInterface
     {
         switch ($type) {
             case static::MONTH:
@@ -119,7 +122,7 @@ class DailyPageHelper
             case static::DAY:
                 return $requested->modify('Today midnight');
             default:
-                throw new \Exception('Unsupported daily format type');
+                throw new Exception('Unsupported daily format type');
         }
     }
 
@@ -129,14 +132,14 @@ class DailyPageHelper
      *       and we don't want to alter original datetime.
      *
      * @param string             $type      month/week/day
-     * @param \DateTimeImmutable $requested DateTime extracted from request input
+     * @param DateTimeImmutable $requested DateTime extracted from request input
      *                                      (should come from extractRequestedDateTime)
      *
      * @return \DateTimeInterface Last DateTime of the time period
      *
-     * @throws \Exception Type not supported.
+     * @throws Exception Type not supported.
      */
-    public static function getEndDateTimeByType(string $type, \DateTimeImmutable $requested): \DateTimeInterface
+    public static function getEndDateTimeByType(string $type, DateTimeImmutable $requested): \DateTimeInterface
     {
         switch ($type) {
             case static::MONTH:
@@ -146,7 +149,7 @@ class DailyPageHelper
             case static::DAY:
                 return $requested->modify('Today 23:59:59');
             default:
-                throw new \Exception('Unsupported daily format type');
+                throw new Exception('Unsupported daily format type');
         }
     }
 
@@ -161,7 +164,7 @@ class DailyPageHelper
      *
      * @return string Localized time period description
      *
-     * @throws \Exception Type not supported.
+     * @throws Exception Type not supported.
      */
     public static function getDescriptionByType(
         string $type,
@@ -183,7 +186,7 @@ class DailyPageHelper
                 }
                 return $out . format_date($requested, false);
             default:
-                throw new \Exception('Unsupported daily format type');
+                throw new Exception('Unsupported daily format type');
         }
     }
 
@@ -194,7 +197,7 @@ class DailyPageHelper
      *
      * @return int number of elements
      *
-     * @throws \Exception Type not supported.
+     * @throws Exception Type not supported.
      */
     public static function getRssLengthByType(string $type): int
     {
@@ -206,7 +209,28 @@ class DailyPageHelper
             case static::DAY:
                 return 30; // ~1 month
             default:
-                throw new \Exception('Unsupported daily format type');
+                throw new Exception('Unsupported daily format type');
         }
     }
+
+    /**
+     * Get the number of items to display in the RSS feed depending on the given type.
+     *
+     * @param string             $type      month/week/day
+     * @param ?DateTimeImmutable $requested Currently only used for UT
+     *
+     * @return DatePeriod number of elements
+     *
+     * @throws Exception Type not supported.
+     */
+    public static function getCacheDatePeriodByType(string $type, DateTimeImmutable $requested = null): DatePeriod
+    {
+        $requested = $requested ?? new DateTimeImmutable();
+
+        return new DatePeriod(
+            static::getStartDateTimeByType($type, $requested),
+            new \DateInterval('P1D'),
+            static::getEndDateTimeByType($type, $requested)
+        );
+    }
 }
index 2e1401eca74f0c9857d7d31c34934a14b6811066..cfc72583e713a192f08199554388990d0d508f8b 100644 (file)
@@ -60,10 +60,15 @@ class MetadataRetriever
             $title = mb_convert_encoding($title, 'utf-8', $charset);
         }
 
-        return [
+        return array_map([$this, 'cleanMetadata'], [
             'title' => $title,
             'description' => $description,
             'tags' => $tags,
-        ];
+        ]);
+    }
+
+    protected function cleanMetadata($data): ?string
+    {
+        return !is_string($data) || empty(trim($data)) ? null : trim($data);
     }
 }
index 97805c3524605bae07b30cb06b4c935517c8126c..fe74bf271bb08448f3f4a605f701fb3b8af0ec24 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Shaarli\Render;
 
+use DatePeriod;
 use Shaarli\Feed\CachedPage;
 
 /**
@@ -49,12 +50,21 @@ class PageCacheManager
         $this->purgeCachedPages();
     }
 
-    public function getCachePage(string $pageUrl): CachedPage
+    /**
+     * Get CachedPage instance for provided URL.
+     *
+     * @param string      $pageUrl
+     * @param ?DatePeriod $validityPeriod Optionally specify a time limit on requested cache
+     *
+     * @return CachedPage
+     */
+    public function getCachePage(string $pageUrl, DatePeriod $validityPeriod = null): CachedPage
     {
         return new CachedPage(
             $this->pageCacheDir,
             $pageUrl,
-            false === $this->isLoggedIn
+            false === $this->isLoggedIn,
+            $validityPeriod
         );
     }
 }
index e12f803be3ce99004294b926e4e14dd7b98f0ba1..f755e2d2b9a9d6e0052b0a5e7875e8d539d2c03e 100644 (file)
@@ -229,4 +229,52 @@ class PostLinkTest extends TestCase
             \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
         );
     }
+
+    /**
+     * Test link creation with a tag string provided
+     */
+    public function testPostLinkWithTagString(): void
+    {
+        $link = [
+            'tags' => 'one two',
+        ];
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'POST',
+            'CONTENT_TYPE' => 'application/json'
+        ]);
+
+        $request = Request::createFromEnvironment($env);
+        $request = $request->withParsedBody($link);
+        $response = $this->controller->postLink($request, new Response());
+
+        $this->assertEquals(201, $response->getStatusCode());
+        $this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
+        $data = json_decode((string) $response->getBody(), true);
+        $this->assertEquals(self::NB_FIELDS_LINK, count($data));
+        $this->assertEquals(['one', 'two'], $data['tags']);
+    }
+
+    /**
+     * Test link creation with a tag string provided
+     */
+    public function testPostLinkWithTagString2(): void
+    {
+        $link = [
+            'tags' => ['one two'],
+        ];
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'POST',
+            'CONTENT_TYPE' => 'application/json'
+        ]);
+
+        $request = Request::createFromEnvironment($env);
+        $request = $request->withParsedBody($link);
+        $response = $this->controller->postLink($request, new Response());
+
+        $this->assertEquals(201, $response->getStatusCode());
+        $this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
+        $data = json_decode((string) $response->getBody(), true);
+        $this->assertEquals(self::NB_FIELDS_LINK, count($data));
+        $this->assertEquals(['one', 'two'], $data['tags']);
+    }
 }
index 240ee323a345cff812cc9ad529ea4ebe25f1ca7a..fe24f2eb91a1ae1d27cd0032a45cced641442a95 100644 (file)
@@ -233,4 +233,52 @@ class PutLinkTest extends \Shaarli\TestCase
 
         $this->controller->putLink($request, new Response(), ['id' => -1]);
     }
+
+    /**
+     * Test link creation with a tag string provided
+     */
+    public function testPutLinkWithTagString(): void
+    {
+        $link = [
+            'tags' => 'one two',
+        ];
+        $id = '41';
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'PUT',
+            'CONTENT_TYPE' => 'application/json'
+        ]);
+
+        $request = Request::createFromEnvironment($env);
+        $request = $request->withParsedBody($link);
+        $response = $this->controller->putLink($request, new Response(), ['id' => $id]);
+
+        $this->assertEquals(200, $response->getStatusCode());
+        $data = json_decode((string) $response->getBody(), true);
+        $this->assertEquals(self::NB_FIELDS_LINK, count($data));
+        $this->assertEquals(['one', 'two'], $data['tags']);
+    }
+
+    /**
+     * Test link creation with a tag string provided
+     */
+    public function testPutLinkWithTagString2(): void
+    {
+        $link = [
+            'tags' => ['one two'],
+        ];
+        $id = '41';
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'PUT',
+            'CONTENT_TYPE' => 'application/json'
+        ]);
+
+        $request = Request::createFromEnvironment($env);
+        $request = $request->withParsedBody($link);
+        $response = $this->controller->putLink($request, new Response(), ['id' => $id]);
+
+        $this->assertEquals(200, $response->getStatusCode());
+        $data = json_decode((string) $response->getBody(), true);
+        $this->assertEquals(self::NB_FIELDS_LINK, count($data));
+        $this->assertEquals(['one', 'two'], $data['tags']);
+    }
 }
index ddab4e3caebd0e7070273738054f9f58d0821aa0..46a7f1fe7a4fd42b749bee30bd455d41ccdc107a 100644 (file)
@@ -245,6 +245,16 @@ class LinkUtilsTest extends TestCase
         $this->assertFalse(html_extract_tag('description', $html));
     }
 
+    public function testHtmlExtractDescriptionFromGoogleRealCase(): void
+    {
+        $html = 'id="gsr"><meta content="Fêtes de fin d\'année" property="twitter:title"><meta '.
+                'content="Bonnes fêtes de fin d\'année ! #GoogleDoodle" property="twitter:description">'.
+                '<meta content="Bonnes fêtes de fin d\'année ! #GoogleDoodle" property="og:description">'.
+                '<meta content="summary_large_image" property="twitter:card"><meta co'
+        ;
+        $this->assertSame('Bonnes fêtes de fin d\'année ! #GoogleDoodle', html_extract_tag('description', $html));
+    }
+
     /**
      * Test the header callback with valid value
      */
index 904db9dc2251a4f23da5ecbf57df59c1b85e5d72..1decfaf3b5c70fd00e31dd1200bcae62f5b892e2 100644 (file)
@@ -40,10 +40,10 @@ class CachedPageTest extends \Shaarli\TestCase
      */
     public function testConstruct()
     {
-        new CachedPage(self::$testCacheDir, '', true);
-        new CachedPage(self::$testCacheDir, '', false);
-        new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/rss', true);
-        new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/atom', false);
+        new CachedPage(self::$testCacheDir, '', true, null);
+        new CachedPage(self::$testCacheDir, '', false, null);
+        new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/rss', true, null);
+        new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/atom', false, null);
         $this->addToAssertionCount(1);
     }
 
@@ -52,7 +52,7 @@ class CachedPageTest extends \Shaarli\TestCase
      */
     public function testCache()
     {
-        $page = new CachedPage(self::$testCacheDir, self::$url, true);
+        $page = new CachedPage(self::$testCacheDir, self::$url, true, null);
 
         $this->assertFileNotExists(self::$filename);
         $page->cache('<p>Some content</p>');
@@ -68,7 +68,7 @@ class CachedPageTest extends \Shaarli\TestCase
      */
     public function testShouldNotCache()
     {
-        $page = new CachedPage(self::$testCacheDir, self::$url, false);
+        $page = new CachedPage(self::$testCacheDir, self::$url, false, null);
 
         $this->assertFileNotExists(self::$filename);
         $page->cache('<p>Some content</p>');
@@ -80,7 +80,7 @@ class CachedPageTest extends \Shaarli\TestCase
      */
     public function testCachedVersion()
     {
-        $page = new CachedPage(self::$testCacheDir, self::$url, true);
+        $page = new CachedPage(self::$testCacheDir, self::$url, true, null);
 
         $this->assertFileNotExists(self::$filename);
         $page->cache('<p>Some content</p>');
@@ -96,7 +96,7 @@ class CachedPageTest extends \Shaarli\TestCase
      */
     public function testCachedVersionNoFile()
     {
-        $page = new CachedPage(self::$testCacheDir, self::$url, true);
+        $page = new CachedPage(self::$testCacheDir, self::$url, true, null);
 
         $this->assertFileNotExists(self::$filename);
         $this->assertEquals(
@@ -110,7 +110,7 @@ class CachedPageTest extends \Shaarli\TestCase
      */
     public function testNoCachedVersion()
     {
-        $page = new CachedPage(self::$testCacheDir, self::$url, false);
+        $page = new CachedPage(self::$testCacheDir, self::$url, false, null);
 
         $this->assertFileNotExists(self::$filename);
         $this->assertEquals(
@@ -118,4 +118,43 @@ class CachedPageTest extends \Shaarli\TestCase
             $page->cachedVersion()
         );
     }
+
+    /**
+     * Return a page's cached content within date period
+     */
+    public function testCachedVersionInDatePeriod()
+    {
+        $period = new \DatePeriod(
+            new \DateTime('yesterday'),
+            new \DateInterval('P1D'),
+            new \DateTime('tomorrow')
+        );
+        $page = new CachedPage(self::$testCacheDir, self::$url, true, $period);
+
+        $this->assertFileNotExists(self::$filename);
+        $page->cache('<p>Some content</p>');
+        $this->assertFileExists(self::$filename);
+        $this->assertEquals(
+            '<p>Some content</p>',
+            $page->cachedVersion()
+        );
+    }
+
+    /**
+     * Return a page's cached content outside of date period
+     */
+    public function testCachedVersionNotInDatePeriod()
+    {
+        $period = new \DatePeriod(
+            new \DateTime('yesterday noon'),
+            new \DateInterval('P1D'),
+            new \DateTime('yesterday midnight')
+        );
+        $page = new CachedPage(self::$testCacheDir, self::$url, true, $period);
+
+        $this->assertFileNotExists(self::$filename);
+        $page->cache('<p>Some content</p>');
+        $this->assertFileExists(self::$filename);
+        $this->assertNull($page->cachedVersion());
+    }
 }
index 6238e6481e40b40bfedd52f70b6a37a2334fb1c9..2d7458004ade968e2b678a8dbcd9e32e4513ded0 100644 (file)
@@ -4,6 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Helper;
 
+use DateTimeImmutable;
+use DateTimeInterface;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\TestCase;
 use Slim\Http\Request;
@@ -32,7 +34,7 @@ class DailyPageHelperTest extends TestCase
         string $type,
         string $input,
         ?Bookmark $bookmark,
-        \DateTimeInterface $expectedDateTime,
+        DateTimeInterface $expectedDateTime,
         string $compareFormat = 'Ymd'
     ): void {
         $dateTime = DailyPageHelper::extractRequestedDateTime($type, $input, $bookmark);
@@ -71,8 +73,8 @@ class DailyPageHelperTest extends TestCase
      */
     public function testGetStartDatesByType(
         string $type,
-        \DateTimeImmutable $dateTime,
-        \DateTimeInterface $expectedDateTime
+        DateTimeImmutable $dateTime,
+        DateTimeInterface $expectedDateTime
     ): void {
         $startDateTime = DailyPageHelper::getStartDateTimeByType($type, $dateTime);
 
@@ -84,7 +86,7 @@ class DailyPageHelperTest extends TestCase
         $this->expectException(\Exception::class);
         $this->expectExceptionMessage('Unsupported daily format type');
 
-        DailyPageHelper::getStartDateTimeByType('nope', new \DateTimeImmutable());
+        DailyPageHelper::getStartDateTimeByType('nope', new DateTimeImmutable());
     }
 
     /**
@@ -92,8 +94,8 @@ class DailyPageHelperTest extends TestCase
      */
     public function testGetEndDatesByType(
         string $type,
-        \DateTimeImmutable $dateTime,
-        \DateTimeInterface $expectedDateTime
+        DateTimeImmutable $dateTime,
+        DateTimeInterface $expectedDateTime
     ): void {
         $endDateTime = DailyPageHelper::getEndDateTimeByType($type, $dateTime);
 
@@ -105,7 +107,7 @@ class DailyPageHelperTest extends TestCase
         $this->expectException(\Exception::class);
         $this->expectExceptionMessage('Unsupported daily format type');
 
-        DailyPageHelper::getEndDateTimeByType('nope', new \DateTimeImmutable());
+        DailyPageHelper::getEndDateTimeByType('nope', new DateTimeImmutable());
     }
 
     /**
@@ -113,7 +115,7 @@ class DailyPageHelperTest extends TestCase
      */
     public function testGeDescriptionsByType(
         string $type,
-        \DateTimeImmutable $dateTime,
+        DateTimeImmutable $dateTime,
         string $expectedDescription
     ): void {
         $description = DailyPageHelper::getDescriptionByType($type, $dateTime);
@@ -139,7 +141,7 @@ class DailyPageHelperTest extends TestCase
         $this->expectException(\Exception::class);
         $this->expectExceptionMessage('Unsupported daily format type');
 
-        DailyPageHelper::getDescriptionByType('nope', new \DateTimeImmutable());
+        DailyPageHelper::getDescriptionByType('nope', new DateTimeImmutable());
     }
 
     /**
@@ -159,6 +161,29 @@ class DailyPageHelperTest extends TestCase
         DailyPageHelper::getRssLengthByType('nope');
     }
 
+    /**
+     * @dataProvider getCacheDatePeriodByType
+     */
+    public function testGetCacheDatePeriodByType(
+        string $type,
+        DateTimeImmutable $requested,
+        DateTimeInterface $start,
+        DateTimeInterface $end
+    ): void {
+        $period = DailyPageHelper::getCacheDatePeriodByType($type, $requested);
+
+        static::assertEquals($start, $period->getStartDate());
+        static::assertEquals($end, $period->getEndDate());
+    }
+
+    public function testGetCacheDatePeriodByTypeExceptionUnknownType(): void
+    {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Unsupported daily format type');
+
+        DailyPageHelper::getCacheDatePeriodByType('nope');
+    }
+
     /**
      * Data provider for testExtractRequestedType() test method.
      */
@@ -229,9 +254,9 @@ class DailyPageHelperTest extends TestCase
     public function getStartDatesByType(): array
     {
         return [
-            [DailyPageHelper::DAY, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-09 00:00:00')],
-            [DailyPageHelper::WEEK, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-05 00:00:00')],
-            [DailyPageHelper::MONTH, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-01 00:00:00')],
+            [DailyPageHelper::DAY, new DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-09 00:00:00')],
+            [DailyPageHelper::WEEK, new DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-05 00:00:00')],
+            [DailyPageHelper::MONTH, new DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-01 00:00:00')],
         ];
     }
 
@@ -241,9 +266,9 @@ class DailyPageHelperTest extends TestCase
     public function getEndDatesByType(): array
     {
         return [
-            [DailyPageHelper::DAY, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-09 23:59:59')],
-            [DailyPageHelper::WEEK, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-11 23:59:59')],
-            [DailyPageHelper::MONTH, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-31 23:59:59')],
+            [DailyPageHelper::DAY, new DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-09 23:59:59')],
+            [DailyPageHelper::WEEK, new DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-11 23:59:59')],
+            [DailyPageHelper::MONTH, new DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-31 23:59:59')],
         ];
     }
 
@@ -253,11 +278,11 @@ class DailyPageHelperTest extends TestCase
     public function getDescriptionsByType(): array
     {
         return [
-            [DailyPageHelper::DAY, $date = new \DateTimeImmutable(), 'Today - ' . $date->format('F j, Y')],
-            [DailyPageHelper::DAY, $date = new \DateTimeImmutable('-1 day'), 'Yesterday - ' . $date->format('F j, Y')],
-            [DailyPageHelper::DAY, new \DateTimeImmutable('2020-10-09 04:05:06'), 'October 9, 2020'],
-            [DailyPageHelper::WEEK, new \DateTimeImmutable('2020-10-09 04:05:06'), 'Week 41 (October 5, 2020)'],
-            [DailyPageHelper::MONTH, new \DateTimeImmutable('2020-10-09 04:05:06'), 'October, 2020'],
+            [DailyPageHelper::DAY, $date = new DateTimeImmutable(), 'Today - ' . $date->format('F j, Y')],
+            [DailyPageHelper::DAY, $date = new DateTimeImmutable('-1 day'), 'Yesterday - ' . $date->format('F j, Y')],
+            [DailyPageHelper::DAY, new DateTimeImmutable('2020-10-09 04:05:06'), 'October 9, 2020'],
+            [DailyPageHelper::WEEK, new DateTimeImmutable('2020-10-09 04:05:06'), 'Week 41 (October 5, 2020)'],
+            [DailyPageHelper::MONTH, new DateTimeImmutable('2020-10-09 04:05:06'), 'October, 2020'],
         ];
     }
 
@@ -276,7 +301,7 @@ class DailyPageHelperTest extends TestCase
     }
 
     /**
-     * Data provider for testGetDescriptionsByType() test method.
+     * Data provider for testGetRssLengthsByType() test method.
      */
     public function getRssLengthsByType(): array
     {
@@ -286,4 +311,31 @@ class DailyPageHelperTest extends TestCase
             [DailyPageHelper::MONTH],
         ];
     }
+
+    /**
+     * Data provider for testGetCacheDatePeriodByType() test method.
+     */
+    public function getCacheDatePeriodByType(): array
+    {
+        return [
+            [
+                DailyPageHelper::DAY,
+                new DateTimeImmutable('2020-10-09 04:05:06'),
+                new \DateTime('2020-10-09 00:00:00'),
+                new \DateTime('2020-10-09 23:59:59'),
+            ],
+            [
+                DailyPageHelper::WEEK,
+                new DateTimeImmutable('2020-10-09 04:05:06'),
+                new \DateTime('2020-10-05 00:00:00'),
+                new \DateTime('2020-10-11 23:59:59'),
+            ],
+            [
+                DailyPageHelper::MONTH,
+                new DateTimeImmutable('2020-10-09 04:05:06'),
+                new \DateTime('2020-10-01 00:00:00'),
+                new \DateTime('2020-10-31 23:59:59'),
+            ],
+        ];
+    }
 }
index 3c9eaa0e706a40803bee68a0a952028bd7c44e1c..cae65091f77c81c1bf01e837de3c20be8b4e245b 100644 (file)
@@ -41,7 +41,7 @@ class MetadataRetrieverTest extends TestCase
         $remoteCharset = 'utf-8';
 
         $expectedResult = [
-            'title' => $remoteTitle,
+            'title' => trim($remoteTitle),
             'description' => $remoteDesc,
             'tags' => $remoteTags,
         ];