]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Fix an issue with private tags and fix nomarkdown tag 1399/head
authorArthurHoaro <arthur@hoa.ro>
Sat, 18 Jan 2020 10:33:23 +0000 (11:33 +0100)
committerArthurHoaro <arthur@hoa.ro>
Sat, 18 Jan 2020 10:39:26 +0000 (11:39 +0100)
The new bookmark service wasn't handling private tags properly.

nomarkdown tag is now shown only for logged in user in bookmarks, and hidden for everyone in tag clouds/lists.

Fixes #726

13 files changed:
application/bookmark/BookmarkFileService.php
application/formatter/BookmarkDefaultFormatter.php
application/formatter/BookmarkFormatter.php
application/formatter/BookmarkMarkdownFormatter.php
application/formatter/FormatterFactory.php
index.php
tests/bookmark/BookmarkFileServiceTest.php
tests/feed/FeedBuilderTest.php
tests/formatter/BookmarkDefaultFormatterTest.php
tests/formatter/BookmarkMarkdownFormatterTest.php
tests/formatter/BookmarkRawFormatterTest.php
tests/formatter/FormatterFactoryTest.php
tests/netscape/BookmarkExportTest.php

index a56cc92b4067cc4f3fa0f0491e8c912404c9bfe4..9c59e1396a31418a957be70e9e776fcdd586978d 100644 (file)
@@ -8,6 +8,7 @@ use Exception;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Bookmark\Exception\EmptyDataStoreException;
 use Shaarli\Config\ConfigManager;
+use Shaarli\Formatter\BookmarkMarkdownFormatter;
 use Shaarli\History;
 use Shaarli\Legacy\LegacyLinkDB;
 use Shaarli\Legacy\LegacyUpdater;
@@ -130,7 +131,7 @@ class BookmarkFileService implements BookmarkServiceInterface
         }
 
         if ($visibility === null) {
-            $visibility = $this->isLoggedIn ? 'all' : 'public';
+            $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
         }
 
         $bookmark = $this->bookmarks[$id];
@@ -287,9 +288,13 @@ class BookmarkFileService implements BookmarkServiceInterface
         $caseMapping = [];
         foreach ($bookmarks as $bookmark) {
             foreach ($bookmark->getTags() as $tag) {
-                if (empty($tag) || (! $this->isLoggedIn && startsWith($tag, '.'))) {
+                if (empty($tag)
+                    || (! $this->isLoggedIn && startsWith($tag, '.'))
+                    || $tag === BookmarkMarkdownFormatter::NO_MD_TAG
+                ) {
                     continue;
                 }
+
                 // The first case found will be displayed.
                 if (!isset($caseMapping[strtolower($tag)])) {
                     $caseMapping[strtolower($tag)] = $tag;
index 7550c5566103116dd828b6b8a5c518feece4c091..c6c590647550e50c6ee688ec497d2a6c7167d497 100644 (file)
@@ -34,7 +34,7 @@ class BookmarkDefaultFormatter extends BookmarkFormatter
      */
     protected function formatTagList($bookmark)
     {
-        return escape($bookmark->getTags());
+        return escape(parent::formatTagList($bookmark));
     }
 
     /**
index c82c3452d11ebf9e042c01a3d73cfc59aa65e089..a80d83fc1639006ebd915f90c8588213383f3b9c 100644 (file)
@@ -20,6 +20,9 @@ abstract class BookmarkFormatter
      */
     protected $conf;
 
+    /** @var bool */
+    protected $isLoggedIn;
+
     /**
      * @var array Additional parameters than can be used for specific formatting
      *            e.g. index_url for Feed formatting
@@ -30,9 +33,10 @@ abstract class BookmarkFormatter
      * LinkDefaultFormatter constructor.
      * @param ConfigManager $conf
      */
-    public function __construct(ConfigManager $conf)
+    public function __construct(ConfigManager $conf, bool $isLoggedIn)
     {
         $this->conf = $conf;
+        $this->isLoggedIn = $isLoggedIn;
     }
 
     /**
@@ -172,7 +176,7 @@ abstract class BookmarkFormatter
      */
     protected function formatTagList($bookmark)
     {
-        return $bookmark->getTags();
+        return $this->filterTagList($bookmark->getTags());
     }
 
     /**
@@ -184,7 +188,7 @@ abstract class BookmarkFormatter
      */
     protected function formatTagString($bookmark)
     {
-        return implode(' ', $bookmark->getTags());
+        return implode(' ', $this->formatTagList($bookmark));
     }
 
     /**
@@ -253,4 +257,29 @@ abstract class BookmarkFormatter
         }
         return 0;
     }
+
+    /**
+     * Format tag list, e.g. remove private tags if the user is not logged in.
+     *
+     * @param array $tags
+     *
+     * @return array
+     */
+    protected function filterTagList(array $tags): array
+    {
+        if ($this->isLoggedIn === true) {
+            return $tags;
+        }
+
+        $out = [];
+        foreach ($tags as $tag) {
+            if (strpos($tag, '.') === 0) {
+                continue;
+            }
+
+            $out[] = $tag;
+        }
+
+        return $out;
+    }
 }
index 7797bfbf33433c308a6c7a396fb3f00d0083f267..077e5312b75b620fb2e2ace73cf353edb7cea99a 100644 (file)
@@ -36,10 +36,12 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter
      * LinkMarkdownFormatter constructor.
      *
      * @param ConfigManager $conf instance
+     * @param bool          $isLoggedIn
      */
-    public function __construct(ConfigManager $conf)
+    public function __construct(ConfigManager $conf, bool $isLoggedIn)
     {
-        parent::__construct($conf);
+        parent::__construct($conf, $isLoggedIn);
+
         $this->parsedown = new \Parsedown();
         $this->escape = $conf->get('security.markdown_escape', true);
         $this->allowedProtocols = $conf->get('security.allowed_protocols', []);
@@ -79,7 +81,7 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter
     protected function formatTagList($bookmark)
     {
         $out = parent::formatTagList($bookmark);
-        if (($pos = array_search(self::NO_MD_TAG, $out)) !== false) {
+        if ($this->isLoggedIn === false && ($pos = array_search(self::NO_MD_TAG, $out)) !== false) {
             unset($out[$pos]);
             return array_values($out);
         }
index 0d2c0466943f000a9e15aa0e99360c95f751b0b6..5f282f686b95ace2439c6db273be4ce78637f876 100644 (file)
@@ -16,14 +16,19 @@ class FormatterFactory
     /** @var ConfigManager instance */
     protected $conf;
 
+    /** @var bool */
+    protected $isLoggedIn;
+
     /**
      * FormatterFactory constructor.
      *
      * @param ConfigManager $conf
+     * @param bool          $isLoggedIn
      */
-    public function __construct(ConfigManager $conf)
+    public function __construct(ConfigManager $conf, bool $isLoggedIn)
     {
         $this->conf = $conf;
+        $this->isLoggedIn = $isLoggedIn;
     }
 
     /**
@@ -33,7 +38,7 @@ class FormatterFactory
      *
      * @return BookmarkFormatter instance.
      */
-    public function getFormatter($type = null)
+    public function getFormatter(string $type = null)
     {
         $type = $type ? $type : $this->conf->get('formatter', 'default');
         $className = '\\Shaarli\\Formatter\\Bookmark'. ucfirst($type) .'Formatter';
@@ -41,6 +46,6 @@ class FormatterFactory
             $className = '\\Shaarli\\Formatter\\BookmarkDefaultFormatter';
         }
 
-        return new $className($this->conf);
+        return new $className($this->conf, $this->isLoggedIn);
     }
 }
index 2dd003f0b73d578a315d7c58c41c1438a93bfcef..bf75f7c914691ba84f9f3c1995b03e4bcb424208 100644 (file)
--- a/index.php
+++ b/index.php
@@ -70,6 +70,7 @@ use Shaarli\Bookmark\BookmarkFileService;
 use \Shaarli\Config\ConfigManager;
 use \Shaarli\Feed\CachedPage;
 use \Shaarli\Feed\FeedBuilder;
+use Shaarli\Formatter\BookmarkMarkdownFormatter;
 use Shaarli\Formatter\FormatterFactory;
 use \Shaarli\History;
 use \Shaarli\Languages;
@@ -351,7 +352,7 @@ function showDailyRSS($bookmarkService, $conf, $loginManager)
     echo '<language>en-en</language>';
     echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL;
 
-    $factory = new FormatterFactory($conf);
+    $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
     $formatter = $factory->getFormatter();
     $formatter->addContextData('index_url', index_url($_SERVER));
     // For each day.
@@ -441,7 +442,7 @@ function showDaily($pageBuilder, $bookmarkService, $conf, $pluginManager, $login
         $linksToDisplay = [];
     }
 
-    $factory = new FormatterFactory($conf);
+    $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
     $formatter = $factory->getFormatter();
     // We pre-format some fields for proper output.
     foreach ($linksToDisplay as $key => $bookmark) {
@@ -630,7 +631,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
 
         // Get only bookmarks which have a thumbnail.
         // Note: we do not retrieve thumbnails here, the request is too heavy.
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
         $formatter = $factory->getFormatter();
         foreach ($links as $key => $link) {
             if ($link->getThumbnail() !== false) {
@@ -753,7 +754,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
             exit;
         }
 
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
         // Generate data.
         $feedGenerator = new FeedBuilder(
             $bookmarkService,
@@ -1183,7 +1184,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
         $bookmarkService->addOrSet($bookmark, false);
 
         // To preserve backward compatibility with 3rd parties, plugins still use arrays
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
         $formatter = $factory->getFormatter('raw');
         $data = $formatter->format($bookmark);
         $pluginManager->executeHooks('save_link', $data);
@@ -1230,7 +1231,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
         if (!count($ids)) {
             die('no id provided');
         }
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
         $formatter = $factory->getFormatter('raw');
         foreach ($ids as $id) {
             $id = (int) escape($id);
@@ -1286,7 +1287,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
         } else {
             $private = $_GET['newVisibility'] === 'private';
         }
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
         $formatter = $factory->getFormatter('raw');
         foreach ($ids as $id) {
             $id = (int) escape($id);
@@ -1324,14 +1325,18 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
             exit;
         }
 
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
         $formatter = $factory->getFormatter('raw');
         $formattedLink = $formatter->format($link);
+        $tags = $bookmarkService->bookmarksCountPerTag();
+        if ($conf->get('formatter') === 'markdown') {
+            $tags[BookmarkMarkdownFormatter::NO_MD_TAG] = 1;
+        }
         $data = array(
             'link' => $formattedLink,
             'link_is_new' => false,
             'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''),
-            'tags' => $bookmarkService->bookmarksCountPerTag(),
+            'tags' => $tags,
         );
         $pluginManager->executeHooks('render_editlink', $data);
 
@@ -1391,17 +1396,21 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
                 'private' => $private,
             ];
         } else {
-            $factory = new FormatterFactory($conf);
-        $formatter = $factory->getFormatter('raw');
+            $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
+            $formatter = $factory->getFormatter('raw');
             $link = $formatter->format($bookmark);
         }
 
+        $tags = $bookmarkService->bookmarksCountPerTag();
+        if ($conf->get('formatter') === 'markdown') {
+            $tags[BookmarkMarkdownFormatter::NO_MD_TAG] = 1;
+        }
         $data = [
             'link' => $link,
             'link_is_new' => $link_is_new,
             'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''),
             'source' => (isset($_GET['source']) ? $_GET['source'] : ''),
-            'tags' => $bookmarkService->bookmarksCountPerTag(),
+            'tags' => $tags,
             'default_private_links' => $conf->get('privacy.default_private_links', false),
         ];
         $pluginManager->executeHooks('render_editlink', $data);
@@ -1451,7 +1460,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
         }
 
         try {
-            $factory = new FormatterFactory($conf);
+            $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
             $formatter = $factory->getFormatter('raw');
             $PAGE->assign(
                 'links',
@@ -1633,7 +1642,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
         $bookmark->setThumbnail($thumbnailer->get($bookmark->getUrl()));
         $bookmarkService->set($bookmark);
 
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
         echo json_encode($factory->getFormatter('raw')->format($bookmark));
         exit;
     }
@@ -1655,7 +1664,7 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
  */
 function buildLinkList($PAGE, $linkDb, $conf, $pluginManager, $loginManager)
 {
-    $factory = new FormatterFactory($conf);
+    $factory = new FormatterFactory($conf, $loginManager->isLoggedIn());
     $formatter = $factory->getFormatter();
 
     // Used in templates
index 1b438a7f97304503e310093b457c11a86cba4e01..4900d41d80598b320e71784ff555739fb6444bdf 100644 (file)
@@ -12,6 +12,7 @@ use ReflectionClass;
 use Shaarli;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Config\ConfigManager;
+use Shaarli\Formatter\BookmarkMarkdownFormatter;
 use Shaarli\History;
 
 /**
@@ -1025,6 +1026,46 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($expected, $tags, var_export($tags, true));
     }
 
+    /**
+     * Test linksCountPerTag public tags with filter.
+     * Equal occurrences should be sorted alphabetically.
+     */
+    public function testCountTagsNoMarkdown()
+    {
+        $expected = [
+            'cartoon' => 3,
+            'dev' => 2,
+            'tag1' => 1,
+            'tag2' => 1,
+            'tag3' => 1,
+            'tag4' => 1,
+            'web' => 4,
+            'gnu' => 2,
+            'hashtag' => 2,
+            'sTuff' => 2,
+            '-exclude' => 1,
+            '.hidden' => 1,
+            'Mercurial' => 1,
+            'css' => 1,
+            'free' => 1,
+            'html' => 1,
+            'media' => 1,
+            'newTagToCount' => 1,
+            'samba' => 1,
+            'software' => 1,
+            'stallman' => 1,
+            'ut' => 1,
+            'w3c' => 1,
+        ];
+        $bookmark = new Bookmark();
+        $bookmark->setTags(['newTagToCount', BookmarkMarkdownFormatter::NO_MD_TAG]);
+        $this->privateLinkDB->add($bookmark);
+
+        $tags = $this->privateLinkDB->bookmarksCountPerTag();
+
+        $this->assertEquals($expected, $tags, var_export($tags, true));
+    }
+
     /**
      * Allows to test LinkDB's private methods
      *
index a43ff672632b092096b92301d9a9da39d324101b..5467189192bed2ac6442df947758394fef57244e 100644 (file)
@@ -51,7 +51,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $refLinkDB = new \ReferenceLinkDB();
         $refLinkDB->write(self::$testDatastore);
         $history = new History('sandbox/history.php');
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, true);
         self::$formatter = $factory->getFormatter();
         self::$bookmarkService = new BookmarkFileService($conf, $history, true);
 
index fe42a2087e7615b196a37defafd67c6fdf5035d4..382a560efcb2785ecbf357d26c466fa6ff18ccf1 100644 (file)
@@ -29,7 +29,7 @@ class BookmarkDefaultFormatterTest extends TestCase
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
-        $this->formatter = new BookmarkDefaultFormatter($this->conf);
+        $this->formatter = new BookmarkDefaultFormatter($this->conf, true);
     }
 
     /**
@@ -153,4 +153,25 @@ class BookmarkDefaultFormatterTest extends TestCase
             $link['description']
         );
     }
+
+    /**
+     * Make sure that private tags are properly filtered out when the user is logged out.
+     */
+    public function testFormatTagListRemovePrivate(): void
+    {
+        $this->formatter = new BookmarkDefaultFormatter($this->conf, false);
+
+        $bookmark = new Bookmark();
+        $bookmark->setId($id = 11);
+        $bookmark->setTags($tags = ['bookmark', '.private', 'othertag']);
+
+        $link = $this->formatter->format($bookmark);
+
+        unset($tags[1]);
+        $tags = array_values($tags);
+
+        $this->assertSame(11, $link['id']);
+        $this->assertSame($tags, $link['taglist']);
+        $this->assertSame(implode(' ', $tags), $link['tags']);
+    }
 }
index 0ca7f80202833e48806fcb8ab98d23e38ee86be8..f1f12c04efa6ef3f82e9a1d4ba76a280c1e0ce71 100644 (file)
@@ -29,7 +29,7 @@ class BookmarkMarkdownFormatterTest extends TestCase
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
-        $this->formatter = new BookmarkMarkdownFormatter($this->conf);
+        $this->formatter = new BookmarkMarkdownFormatter($this->conf, true);
     }
 
     /**
index ceb6fb73895fef071a4eb49d80a4243482482182..4491b03586ad7fddb1da215df67924d251435b3a 100644 (file)
@@ -29,7 +29,7 @@ class BookmarkRawFormatterTest extends TestCase
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
-        $this->formatter = new BookmarkRawFormatter($this->conf);
+        $this->formatter = new BookmarkRawFormatter($this->conf, true);
     }
 
     /**
index 317c0b2d99d08c9ded9cf043f4baddd9867de8b3..5adf3ffd8dd2acfe20eb47fcf5ab58ed40f7c9ce 100644 (file)
@@ -28,7 +28,7 @@ class FormatterFactoryTest extends TestCase
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
-        $this->factory = new FormatterFactory($this->conf);
+        $this->factory = new FormatterFactory($this->conf, true);
     }
 
     /**
index 011d19ac6ab107f473befb2234752ebba4fdac54..6c948bba4a0d805f09927af06e3e5d6d68482d57 100644 (file)
@@ -46,7 +46,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase
         self::$refDb->write(self::$testDatastore);
         $history = new History('sandbox/history.php');
         self::$bookmarkService = new BookmarkFileService($conf, $history, true);
-        $factory = new FormatterFactory($conf);
+        $factory = new FormatterFactory($conf, true);
         self::$formatter = $factory->getFormatter('raw');
     }