]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Slim router: handle add tag route
authorArthurHoaro <arthur@hoa.ro>
Tue, 12 May 2020 10:44:48 +0000 (12:44 +0200)
committerArthurHoaro <arthur@hoa.ro>
Thu, 23 Jul 2020 19:19:21 +0000 (21:19 +0200)
20 files changed:
application/bookmark/LinkUtils.php
application/container/ShaarliContainer.php
application/formatter/BookmarkMarkdownFormatter.php
application/front/controllers/TagController.php [new file with mode: 0644]
composer.lock
index.php
tests/bookmark/LinkUtilsTest.php
tests/feed/FeedBuilderTest.php
tests/formatter/BookmarkDefaultFormatterTest.php
tests/formatter/BookmarkMarkdownFormatterTest.php
tests/front/controller/TagControllerTest.php [new file with mode: 0644]
tests/plugins/resources/hashtags.md [deleted file]
tests/plugins/resources/hashtags.raw [deleted file]
tests/plugins/resources/markdown.html [deleted file]
tests/plugins/resources/markdown.md [deleted file]
tpl/default/linklist.html
tpl/default/tag.cloud.html
tpl/default/tag.list.html
tpl/vintage/linklist.html
tpl/vintage/tag.cloud.html

index 8837943037dd52468ff6e73bbbc39f8e669b1b04..98d9038a4949325a23e2a2db2037b9ac1feca4de 100644 (file)
@@ -220,7 +220,7 @@ function hashtag_autolink($description, $indexUrl = '')
      * \p{Mn} - any non marking space (accents, umlauts, etc)
      */
     $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui';
-    $replacement = '$1<a href="'. $indexUrl .'?addtag=$2" title="Hashtag $2">#$2</a>';
+    $replacement = '$1<a href="'. $indexUrl .'./add-tag/$2" title="Hashtag $2">#$2</a>';
     return preg_replace($regex, $replacement, $description);
 }
 
index af62e5747f86d049988cec9e4509e15d7615bdc9..3995f669ca3815a01c3765a6fc94f988cbfd1744 100644 (file)
@@ -18,6 +18,7 @@ use Slim\Container;
 /**
  * Extension of Slim container to document the injected objects.
  *
+ * @property mixed[]                  $environment     $_SERVER automatically injected by Slim
  * @property ConfigManager            $conf
  * @property SessionManager           $sessionManager
  * @property LoginManager             $loginManager
index 077e5312b75b620fb2e2ace73cf353edb7cea99a..5d244d4c92de249721f0c1c6e18ab79ba2222752 100644 (file)
@@ -114,7 +114,7 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter
 
     /**
      * Replace hashtag in Markdown links format
-     * E.g. `#hashtag` becomes `[#hashtag](?addtag=hashtag)`
+     * E.g. `#hashtag` becomes `[#hashtag](./add-tag/hashtag)`
      * It includes the index URL if specified.
      *
      * @param string $description
@@ -133,7 +133,7 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter
          * \p{Mn} - any non marking space (accents, umlauts, etc)
          */
         $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui';
-        $replacement = '$1[#$2]('. $indexUrl .'?addtag=$2)';
+        $replacement = '$1[#$2]('. $indexUrl .'./add-tag/$2)';
 
         $descriptionLines = explode(PHP_EOL, $description);
         $descriptionOut = '';
diff --git a/application/front/controllers/TagController.php b/application/front/controllers/TagController.php
new file mode 100644 (file)
index 0000000..598275b
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller;
+
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+/**
+ * Class TagController
+ *
+ * Slim controller handle tags.
+ *
+ * @package Front\Controller
+ */
+class TagController extends ShaarliController
+{
+    /**
+     * Add another tag in the current search through an HTTP redirection.
+     *
+     * @param array $args Should contain `newTag` key as tag to add to current search
+     */
+    public function addTag(Request $request, Response $response, array $args): Response
+    {
+        $newTag = $args['newTag'] ?? null;
+        $referer = $this->container->environment['HTTP_REFERER'] ?? null;
+
+        // In case browser does not send HTTP_REFERER, we search a single tag
+        if (null === $referer) {
+            if (null !== $newTag) {
+                return $response->withRedirect('./?searchtags='. urlencode($newTag));
+            }
+
+            return $response->withRedirect('./');
+        }
+
+        $currentUrl = parse_url($this->container->environment['HTTP_REFERER']);
+        parse_str($currentUrl['query'] ?? '', $params);
+
+        if (null === $newTag) {
+            return $response->withRedirect(($currentUrl['path'] ?? './') .'?'. http_build_query($params));
+        }
+
+        // Prevent redirection loop
+        if (isset($params['addtag'])) {
+            unset($params['addtag']);
+        }
+
+        // Check if this tag is already in the search query and ignore it if it is.
+        // Each tag is always separated by a space
+        $currentTags = isset($params['searchtags']) ? explode(' ', $params['searchtags']) : [];
+
+        $addtag = true;
+        foreach ($currentTags as $value) {
+            if ($value === $newTag) {
+                $addtag = false;
+                break;
+            }
+        }
+
+        // Append the tag if necessary
+        if (true === $addtag) {
+            $currentTags[] = trim($newTag);
+        }
+
+        $params['searchtags'] = trim(implode(' ', $currentTags));
+
+        // We also remove page (keeping the same page has no sense, since the results are different)
+        unset($params['page']);
+
+        return $response->withRedirect(($currentUrl['path'] ?? './') .'?'. http_build_query($params));
+    }
+}
index b3373a3263c1c895814e929ab4363b28832323a9..fccc741c37bf44edf35a921d7f2d343f6ae42e0c 100644 (file)
         },
         {
             "name": "psr/log",
-            "version": "1.1.2",
+            "version": "1.1.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/log.git",
-                "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
+                "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
-                "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
+                "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
                 "shasum": ""
             },
             "require": {
                 "psr",
                 "psr-3"
             ],
-            "time": "2019-11-01T11:05:21+00:00"
+            "time": "2020-03-23T09:12:05+00:00"
         },
         {
             "name": "pubsubhubbub/publisher",
         },
         {
             "name": "phpdocumentor/reflection-common",
-            "version": "2.0.0",
+            "version": "2.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
-                "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a"
+                "reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a",
-                "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
+                "reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.1"
             },
-            "require-dev": {
-                "phpunit/phpunit": "~6"
-            },
             "type": "library",
             "extra": {
                 "branch-alias": {
                 "reflection",
                 "static analysis"
             ],
-            "time": "2018-08-07T13:53:10+00:00"
+            "time": "2020-04-27T09:25:28+00:00"
         },
         {
             "name": "phpdocumentor/reflection-docblock",
         },
         {
             "name": "phpspec/prophecy",
-            "version": "1.10.1",
+            "version": "v1.10.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc"
+                "reference": "451c3cd1418cf640de218914901e51b064abb093"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
-                "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093",
+                "reference": "451c3cd1418cf640de218914901e51b064abb093",
                 "shasum": ""
             },
             "require": {
                 "doctrine/instantiator": "^1.0.2",
                 "php": "^5.3|^7.0",
                 "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
-                "sebastian/comparator": "^1.2.3|^2.0|^3.0",
-                "sebastian/recursion-context": "^1.0|^2.0|^3.0"
+                "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
+                "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
             },
             "require-dev": {
                 "phpspec/phpspec": "^2.5 || ^3.2",
                 "spy",
                 "stub"
             ],
-            "time": "2019-12-22T21:05:45+00:00"
+            "time": "2020-03-05T15:02:03+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Roave/SecurityAdvisories.git",
-                "reference": "67ac6ea8f4a078c3c9b7aec5d7ae70f098c37389"
+                "reference": "ec1a75b10126327b351fdea7c2b9bfb94e2f6f35"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/67ac6ea8f4a078c3c9b7aec5d7ae70f098c37389",
-                "reference": "67ac6ea8f4a078c3c9b7aec5d7ae70f098c37389",
+                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/ec1a75b10126327b351fdea7c2b9bfb94e2f6f35",
+                "reference": "ec1a75b10126327b351fdea7c2b9bfb94e2f6f35",
                 "shasum": ""
             },
             "conflict": {
                 "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6",
                 "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99",
                 "aws/aws-sdk-php": ">=3,<3.2.1",
+                "bagisto/bagisto": "<0.1.5",
+                "barrelstrength/sprout-base-email": "<3.9",
+                "bolt/bolt": "<3.6.10",
                 "brightlocal/phpwhois": "<=4.2.5",
+                "buddypress/buddypress": "<5.1.2",
                 "bugsnag/bugsnag-laravel": ">=2,<2.0.2",
                 "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7",
                 "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4",
                 "cartalyst/sentry": "<=2.1.6",
+                "centreon/centreon": "<18.10.8|>=19,<19.4.5",
+                "cesnet/simplesamlphp-module-proxystatistics": "<3.1",
                 "codeigniter/framework": "<=3.0.6",
                 "composer/composer": "<=1-alpha.11",
                 "contao-components/mediaelement": ">=2.14.2,<2.21.1",
                 "doctrine/mongodb-odm": ">=1,<1.0.2",
                 "doctrine/mongodb-odm-bundle": ">=2,<3.0.1",
                 "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1",
+                "dolibarr/dolibarr": "<=10.0.6",
                 "dompdf/dompdf": ">=0.6,<0.6.2",
-                "drupal/core": ">=7,<7.69|>=8,<8.7.11|>=8.8,<8.8.1",
-                "drupal/drupal": ">=7,<7.69|>=8,<8.7.11|>=8.8,<8.8.1",
+                "drupal/core": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4",
+                "drupal/drupal": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4",
                 "endroid/qr-code-bundle": "<3.4.2",
+                "enshrined/svg-sanitize": "<0.13.1",
                 "erusev/parsedown": "<1.7.2",
-                "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.4",
-                "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1",
-                "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3",
+                "ezsystems/demobundle": ">=5.4,<5.4.6.1",
+                "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1",
+                "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1",
+                "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4",
+                "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6",
+                "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2",
+                "ezsystems/ezplatform-user": ">=1,<1.0.1",
+                "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.1|>=6,<6.7.9.1|>=6.8,<6.13.6.2|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.6.2",
+                "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.1|>=2011,<2017.12.7.2|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.4.2",
                 "ezsystems/repository-forms": ">=2.3,<2.3.2.1",
                 "ezyang/htmlpurifier": "<4.1.1",
                 "firebase/php-jwt": "<2",
                 "fooman/tcpdf": "<6.2.22",
                 "fossar/tcpdf-parser": "<6.2.22",
+                "friendsofsymfony/oauth2-php": "<1.3",
                 "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2",
                 "friendsofsymfony/user-bundle": ">=1.2,<1.3.5",
                 "fuel/core": "<1.8.1",
+                "getgrav/grav": "<1.7-beta.8",
                 "gree/jose": "<=2.2",
                 "gregwar/rst": "<1.0.3",
                 "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1",
                 "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30",
                 "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29",
                 "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15",
+                "illuminate/view": ">=7,<7.1.2",
                 "ivankristianto/phpwhois": "<=4.3",
                 "james-heinrich/getid3": "<1.9.9",
                 "joomla/session": "<1.3.1",
                 "kazist/phpwhois": "<=4.2.6",
                 "kreait/firebase-php": ">=3.2,<3.8.1",
                 "la-haute-societe/tcpdf": "<6.2.22",
-                "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30",
+                "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30|>=7,<7.1.2",
                 "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10",
                 "league/commonmark": "<0.18.3",
+                "librenms/librenms": "<1.53",
+                "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3",
                 "magento/magento1ce": "<1.9.4.3",
                 "magento/magento1ee": ">=1,<1.14.4.3",
                 "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2",
                 "monolog/monolog": ">=1.8,<1.12",
                 "namshi/jose": "<2.2",
+                "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1",
                 "onelogin/php-saml": "<2.10.4",
+                "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5",
                 "openid/php-openid": "<2.3",
                 "oro/crm": ">=1.7,<1.7.4",
                 "oro/platform": ">=1.7,<1.7.4",
                 "paragonie/random_compat": "<2",
                 "paypal/merchant-sdk-php": "<3.12",
                 "pear/archive_tar": "<1.4.4",
+                "phpfastcache/phpfastcache": ">=5,<5.0.13",
                 "phpmailer/phpmailer": ">=5,<5.2.27|>=6,<6.0.6",
-                "phpoffice/phpexcel": "<=1.8.1",
-                "phpoffice/phpspreadsheet": "<=1.5",
+                "phpmyadmin/phpmyadmin": "<4.9.2",
+                "phpoffice/phpexcel": "<1.8.2",
+                "phpoffice/phpspreadsheet": "<1.8",
                 "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3",
                 "phpwhois/phpwhois": "<=4.2.5",
                 "phpxmlrpc/extras": "<0.6.1",
+                "pimcore/pimcore": "<6.3",
+                "prestashop/autoupgrade": ">=4,<4.10.1",
+                "prestashop/gamification": "<2.3.2",
+                "prestashop/ps_facetedsearch": "<3.4.1",
+                "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2",
                 "propel/propel": ">=2-alpha.1,<=2-alpha.7",
                 "propel/propel1": ">=1,<=1.7.1",
                 "pusher/pusher-php-server": "<2.2.1",
-                "robrichards/xmlseclibs": ">=1,<3.0.4",
+                "robrichards/xmlseclibs": "<3.0.4",
                 "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9",
                 "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11",
                 "sensiolabs/connect": "<4.2.3",
                 "serluck/phpwhois": "<=4.2.6",
                 "shopware/shopware": "<5.3.7",
-                "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11",
+                "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1",
+                "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2",
+                "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4",
+                "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1",
                 "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3",
-                "silverstripe/framework": ">=3,<3.6.7|>=3.7,<3.7.3|>=4,<4.4",
+                "silverstripe/framework": "<4.4.5|>=4.5,<4.5.2",
                 "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2",
                 "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1",
                 "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4",
+                "silverstripe/subsites": ">=2,<2.1.1",
+                "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1",
                 "silverstripe/userforms": "<3",
                 "simple-updates/phpwhois": "<=1",
                 "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4",
-                "simplesamlphp/simplesamlphp": "<1.17.8",
+                "simplesamlphp/simplesamlphp": "<1.18.6",
                 "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1",
+                "simplito/elliptic-php": "<1.0.6",
                 "slim/slim": "<2.6",
                 "smarty/smarty": "<3.1.33",
                 "socalnick/scn-social-auth": "<1.15.2",
                 "spoonity/tcpdf": "<6.2.22",
                 "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1",
+                "ssddanbrown/bookstack": "<0.29.2",
                 "stormpath/sdk": ">=0,<9.9.99",
-                "studio-42/elfinder": "<2.1.48",
+                "studio-42/elfinder": "<2.1.49",
                 "swiftmailer/swiftmailer": ">=4,<5.4.5",
                 "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2",
                 "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
                 "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
-                "sylius/sylius": ">=1,<1.1.18|>=1.2,<1.2.17|>=1.3,<1.3.12|>=1.4,<1.4.4",
+                "sylius/resource-bundle": "<1.3.13|>=1.4,<1.4.6|>=1.5,<1.5.1|>=1.6,<1.6.3",
+                "sylius/sylius": "<1.3.16|>=1.4,<1.4.12|>=1.5,<1.5.9|>=1.6,<1.6.5",
+                "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99",
+                "symbiote/silverstripe-versionedfiles": "<=2.0.3",
                 "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8",
                 "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
+                "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4",
                 "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1",
                 "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
-                "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8",
+                "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
                 "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8",
                 "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13",
                 "symfony/mime": ">=4.3,<4.3.8",
                 "symfony/polyfill-php55": ">=1,<1.10",
                 "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
                 "symfony/routing": ">=2,<2.0.19",
-                "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
+                "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=4.4,<4.4.7|>=5,<5.0.7",
                 "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11",
                 "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7",
                 "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11",
                 "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11",
-                "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8",
+                "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
                 "symfony/serializer": ">=2,<2.0.11",
-                "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8",
+                "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
                 "symfony/translation": ">=2,<2.0.17",
                 "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3",
                 "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8",
                 "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4",
                 "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1",
                 "ua-parser/uap-php": "<3.8",
+                "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2",
+                "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4",
                 "wallabag/tcpdf": "<6.2.22",
                 "willdurand/js-translation-bundle": "<2.1.1",
+                "yii2mod/yii2-cms": "<1.9.2",
                 "yiisoft/yii": ">=1.1.14,<1.1.15",
                 "yiisoft/yii2": "<2.0.15",
                 "yiisoft/yii2-bootstrap": "<2.0.4",
                 "yiisoft/yii2-gii": "<2.0.4",
                 "yiisoft/yii2-jui": "<2.0.4",
                 "yiisoft/yii2-redis": "<2.0.8",
+                "yourls/yourls": "<1.7.4",
                 "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3",
                 "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2",
                 "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2",
                     "name": "Marco Pivetta",
                     "email": "ocramius@gmail.com",
                     "role": "maintainer"
+                },
+                {
+                    "name": "Ilya Tribusean",
+                    "email": "slash3b@gmail.com",
+                    "role": "maintainer"
                 }
             ],
             "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
-            "time": "2020-01-06T19:16:46+00:00"
+            "time": "2020-05-09T00:00:21+00:00"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
         },
         {
             "name": "squizlabs/php_codesniffer",
-            "version": "3.5.3",
+            "version": "3.5.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
-                "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb"
+                "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb",
-                "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb",
+                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
+                "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
                 "shasum": ""
             },
             "require": {
                 "phpcs",
                 "standards"
             ],
-            "time": "2019-12-04T04:46:47+00:00"
+            "time": "2020-04-17T01:09:41+00:00"
         },
         {
             "name": "symfony/console",
-            "version": "v4.4.2",
+            "version": "v4.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0"
+                "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/82437719dab1e6bdd28726af14cb345c2ec816d0",
-                "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0",
+                "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7",
+                "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7",
                 "shasum": ""
             },
             "require": {
             ],
             "description": "Symfony Console Component",
             "homepage": "https://symfony.com",
-            "time": "2019-12-17T10:32:23+00:00"
+            "time": "2020-03-30T11:41:10+00:00"
         },
         {
             "name": "symfony/finder",
-            "version": "v4.4.2",
+            "version": "v4.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "ce8743441da64c41e2a667b8eb66070444ed911e"
+                "reference": "5729f943f9854c5781984ed4907bbb817735776b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/ce8743441da64c41e2a667b8eb66070444ed911e",
-                "reference": "ce8743441da64c41e2a667b8eb66070444ed911e",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/5729f943f9854c5781984ed4907bbb817735776b",
+                "reference": "5729f943f9854c5781984ed4907bbb817735776b",
                 "shasum": ""
             },
             "require": {
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2019-11-17T21:56:56+00:00"
+            "time": "2020-03-27T16:54:36+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
-            "version": "v1.13.1",
+            "version": "v1.16.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
+                "reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
-                "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1aab00e39cebaef4d8652497f46c15c1b7e45294",
+                "reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.16-dev"
                 }
             },
             "autoload": {
                 "polyfill",
                 "portable"
             ],
-            "time": "2019-11-27T13:56:44+00:00"
+            "time": "2020-05-08T16:50:20+00:00"
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.13.1",
+            "version": "v1.16.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f"
+                "reference": "a54881ec0ab3b2005c406aed0023c062879031e7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f",
-                "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a54881ec0ab3b2005c406aed0023c062879031e7",
+                "reference": "a54881ec0ab3b2005c406aed0023c062879031e7",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.16-dev"
                 }
             },
             "autoload": {
                 "portable",
                 "shim"
             ],
-            "time": "2019-11-27T14:18:11+00:00"
+            "time": "2020-05-08T16:50:20+00:00"
         },
         {
             "name": "symfony/polyfill-php73",
-            "version": "v1.13.1",
+            "version": "v1.16.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php73.git",
-                "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f"
+                "reference": "7e95fe59d12169fcf4041487e4bf34fca37ee0ed"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/4b0e2222c55a25b4541305a053013d5647d3a25f",
-                "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f",
+                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/7e95fe59d12169fcf4041487e4bf34fca37ee0ed",
+                "reference": "7e95fe59d12169fcf4041487e4bf34fca37ee0ed",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.16-dev"
                 }
             },
             "autoload": {
                 "portable",
                 "shim"
             ],
-            "time": "2019-11-27T16:25:15+00:00"
+            "time": "2020-05-02T14:56:09+00:00"
         },
         {
             "name": "symfony/service-contracts",
         },
         {
             "name": "webmozart/assert",
-            "version": "1.6.0",
+            "version": "1.8.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webmozart/assert.git",
-                "reference": "573381c0a64f155a0d9a23f4b0c797194805b925"
+                "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925",
-                "reference": "573381c0a64f155a0d9a23f4b0c797194805b925",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
+                "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
                 "shasum": ""
             },
             "require": {
                 "symfony/polyfill-ctype": "^1.8"
             },
             "conflict": {
-                "vimeo/psalm": "<3.6.0"
+                "vimeo/psalm": "<3.9.1"
             },
             "require-dev": {
                 "phpunit/phpunit": "^4.8.36 || ^7.5.13"
                 "check",
                 "validate"
             ],
-            "time": "2019-11-24T13:36:37+00:00"
+            "time": "2020-04-18T12:12:48+00:00"
         }
     ],
     "aliases": [],
index 57e13d4e4f0c19c9e97dc44ebd45380a8b5bf5d5..a42c844a8bac754d1e4fccf3118cb75f1460d5f3 100644 (file)
--- a/index.php
+++ b/index.php
@@ -1916,6 +1916,7 @@ $app->group('', function () {
     $this->get('/login', '\Shaarli\Front\Controller\LoginController:index')->setName('login');
     $this->get('/logout', '\Shaarli\Front\Controller\LogoutController:index')->setName('logout');
     $this->get('/picture-wall', '\Shaarli\Front\Controller\PictureWallController:index')->setName('picwall');
+    $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\TagController:addTag')->setName('add-tag');
 })->add('\Shaarli\Front\ShaarliMiddleware');
 
 $response = $app->run(true);
index 591976f2c30b1a293ec7f845972147a02c3420c4..7d4a7b89a20131d9827112ffbd85fb905c1dffd3 100644 (file)
@@ -3,8 +3,6 @@
 namespace Shaarli\Bookmark;
 
 use PHPUnit\Framework\TestCase;
-use ReferenceLinkDB;
-use Shaarli\Config\ConfigManager;
 
 require_once 'tests/utils/CurlUtils.php';
 
@@ -491,7 +489,7 @@ class LinkUtilsTest extends TestCase
      */
     private function getHashtagLink($hashtag, $index = '')
     {
-        $hashtagLink = '<a href="' . $index . '?addtag=$1" title="Hashtag $1">#$1</a>';
+        $hashtagLink = '<a href="' . $index . './add-tag/$1" title="Hashtag $1">#$1</a>';
         return str_replace('$1', $hashtag, $hashtagLink);
     }
 }
index 5467189192bed2ac6442df947758394fef57244e..535207aaf788a5110e800ad9f9169d6b05aaf2f5 100644 (file)
@@ -306,6 +306,6 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['guid']);
         $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['url']);
-        $this->assertContains('http://host.tld:8080/~user/shaarli/?addtag=hashtag', $link['description']);
+        $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
     }
 }
index 382a560efcb2785ecbf357d26c466fa6ff18ccf1..cf48b00b63ce2c397a89cf836d1d9b04e812e9b9 100644 (file)
@@ -123,7 +123,7 @@ class BookmarkDefaultFormatterTest extends TestCase
         $description[0] = 'This a &lt;strong&gt;description&lt;/strong&gt;<br />';
         $url = 'https://sub.domain.tld?query=here&amp;for=real#hash';
         $description[1] = 'text <a href="'. $url .'">'. $url .'</a> more text<br />';
-        $description[2] = 'Also, there is an <a href="?addtag=hashtag" '.
+        $description[2] = 'Also, there is an <a href="./add-tag/hashtag" '.
             'title="Hashtag hashtag">#hashtag</a> added<br />';
         $description[3] = '&nbsp; &nbsp; A &nbsp;N &nbsp;D KEEP &nbsp; &nbsp; '.
             'SPACES &nbsp; &nbsp;! &nbsp; <br />';
@@ -148,7 +148,7 @@ class BookmarkDefaultFormatterTest extends TestCase
         $this->assertEquals($root . $short, $link['url']);
         $this->assertEquals($root . $short, $link['real_url']);
         $this->assertEquals(
-            'Text <a href="'. $root .'?addtag=hashtag" title="Hashtag hashtag">'.
+            'Text <a href="'. $root .'./add-tag/hashtag" title="Hashtag hashtag">'.
             '#hashtag</a> more text',
             $link['description']
         );
index f1f12c04efa6ef3f82e9a1d4ba76a280c1e0ce71..3e72d1eea340988b4b69c4f94e9cfdc2907d2cbf 100644 (file)
@@ -125,7 +125,7 @@ class BookmarkMarkdownFormatterTest extends TestCase
         $description .= 'This a &lt;strong&gt;description&lt;/strong&gt;<br />'. PHP_EOL;
         $url = 'https://sub.domain.tld?query=here&amp;for=real#hash';
         $description .= 'text <a href="'. $url .'">'. $url .'</a> more text<br />'. PHP_EOL;
-        $description .= 'Also, there is an <a href="?addtag=hashtag">#hashtag</a> added<br />'. PHP_EOL;
+        $description .= 'Also, there is an <a href="./add-tag/hashtag">#hashtag</a> added<br />'. PHP_EOL;
         $description .= 'A  N  D KEEP     SPACES    !   ';
         $description .= '</p></div>';
 
@@ -146,7 +146,7 @@ class BookmarkMarkdownFormatterTest extends TestCase
         $this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/');
 
         $description = '<div class="markdown"><p>';
-        $description .= 'Text <a href="'. $root .'?addtag=hashtag">#hashtag</a> more text';
+        $description .= 'Text <a href="'. $root .'./add-tag/hashtag">#hashtag</a> more text';
         $description .= '</p></div>';
 
         $link = $this->formatter->format($bookmark);
diff --git a/tests/front/controller/TagControllerTest.php b/tests/front/controller/TagControllerTest.php
new file mode 100644 (file)
index 0000000..bbac565
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller;
+
+use PHPUnit\Framework\TestCase;
+use Shaarli\Bookmark\BookmarkServiceInterface;
+use Shaarli\Config\ConfigManager;
+use Shaarli\Container\ShaarliContainer;
+use Shaarli\Plugin\PluginManager;
+use Shaarli\Render\PageBuilder;
+use Shaarli\Security\LoginManager;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+class TagControllerTest extends TestCase
+{
+    /** @var ShaarliContainer */
+    protected $container;
+
+    /** @var TagController */
+    protected $controller;
+
+    public function setUp(): void
+    {
+        $this->container = $this->createMock(ShaarliContainer::class);
+        $this->controller = new TagController($this->container);
+    }
+
+    public function testAddTagWithReferer(): void
+    {
+        $this->createValidContainerMockSet();
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/'];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $tags = ['newTag' => 'abc'];
+
+        $result = $this->controller->addTag($request, $response, $tags);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location'));
+    }
+
+    public function testAddTagWithRefererAndExistingSearch(): void
+    {
+        $this->createValidContainerMockSet();
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def'];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $tags = ['newTag' => 'abc'];
+
+        $result = $this->controller->addTag($request, $response, $tags);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location'));
+    }
+
+    public function testAddTagWithoutRefererAndExistingSearch(): void
+    {
+        $this->createValidContainerMockSet();
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $tags = ['newTag' => 'abc'];
+
+        $result = $this->controller->addTag($request, $response, $tags);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['./?searchtags=abc'], $result->getHeader('location'));
+    }
+
+    public function testAddTagRemoveLegacyQueryParam(): void
+    {
+        $this->createValidContainerMockSet();
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc'];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $tags = ['newTag' => 'abc'];
+
+        $result = $this->controller->addTag($request, $response, $tags);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location'));
+    }
+
+    public function testAddTagResetPagination(): void
+    {
+        $this->createValidContainerMockSet();
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12'];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $tags = ['newTag' => 'abc'];
+
+        $result = $this->controller->addTag($request, $response, $tags);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location'));
+    }
+
+    public function testAddTagWithRefererAndEmptySearch(): void
+    {
+        $this->createValidContainerMockSet();
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags='];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $tags = ['newTag' => 'abc'];
+
+        $result = $this->controller->addTag($request, $response, $tags);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location'));
+    }
+
+    public function testAddTagWithoutNewTagWithReferer(): void
+    {
+        $this->createValidContainerMockSet();
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def'];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $result = $this->controller->addTag($request, $response, []);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location'));
+    }
+
+    public function testAddTagWithoutNewTagWithoutReferer(): void
+    {
+        $this->createValidContainerMockSet();
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $result = $this->controller->addTag($request, $response, []);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['./'], $result->getHeader('location'));
+    }
+
+    protected function createValidContainerMockSet(): void
+    {
+        // User logged out
+        $loginManager = $this->createMock(LoginManager::class);
+        $loginManager->method('isLoggedIn')->willReturn(false);
+        $loginManager->method('canLogin')->willReturn(true);
+        $this->container->loginManager = $loginManager;
+
+        // Config
+        $conf = $this->createMock(ConfigManager::class);
+        $conf->method('get')->willReturnCallback(function (string $parameter, $default) {
+            return $default;
+        });
+        $this->container->conf = $conf;
+
+        // PageBuilder
+        $pageBuilder = $this->createMock(PageBuilder::class);
+        $pageBuilder
+            ->method('render')
+            ->willReturnCallback(function (string $template): string {
+                return $template;
+            })
+        ;
+        $this->container->pageBuilder = $pageBuilder;
+
+        $pluginManager = $this->createMock(PluginManager::class);
+        $this->container->pluginManager = $pluginManager;
+        $bookmarkService = $this->createMock(BookmarkServiceInterface::class);
+        $this->container->bookmarkService = $bookmarkService;
+    }
+}
diff --git a/tests/plugins/resources/hashtags.md b/tests/plugins/resources/hashtags.md
deleted file mode 100644 (file)
index 46326de..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[#lol](?addtag=lol)
-
-    #test
-
-`#test2`
-
-```
-bla #bli blo
-#bla
-```
diff --git a/tests/plugins/resources/hashtags.raw b/tests/plugins/resources/hashtags.raw
deleted file mode 100644 (file)
index 9d2dc98..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#lol
-
-    #test
-
-`#test2`
-
-```
-bla #bli blo
-#bla
-```
diff --git a/tests/plugins/resources/markdown.html b/tests/plugins/resources/markdown.html
deleted file mode 100644 (file)
index c3460bf..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<div class="markdown"><ul>
-<li>test:
-<ul>
-<li><a href="http://link.tld">zero</a></li>
-<li><a href="http://link.tld">two</a></li>
-<li><a href="http://link.tld">three</a></li>
-</ul></li>
-</ul>
-<ol>
-<li><a href="http://link.tld">zero</a>
-<ol start="2">
-<li><a href="http://link.tld">two</a></li>
-<li><a href="http://link.tld">three</a></li>
-<li><a href="http://link.tld">four</a></li>
-<li>foo <a href="?addtag=foobar">#foobar</a></li>
-</ol></li>
-</ol>
-<p><a href="?addtag=foobar">#foobar</a> foo <code>lol #foo</code> <a href="?addtag=bar">#bar</a></p>
-<p>fsdfs <a href="http://link.tld">http://link.tld</a> <a href="?addtag=foobar">#foobar</a> <code>http://link.tld</code></p>
-<pre><code>http://link.tld #foobar
-next #foo</code></pre>
-<p>Block:</p>
-<pre><code>lorem ipsum #foobar http://link.tld
-#foobar http://link.tld</code></pre>
-<p><a href="?123456">link</a><br />
-<img src="/img/train.png" alt="link" /><br />
-<a href="http://test.tld/path/?query=value#hash">link</a><br />
-<a href="http://test.tld/path/?query=value#hash">link</a><br />
-<a href="https://test.tld/path/?query=value#hash">link</a><br />
-<a href="ftp://test.tld/path/?query=value#hash">link</a><br />
-<a href="magnet:test.tld/path/?query=value#hash">link</a><br />
-<a href="http://alert(&#039;xss&#039;)">link</a><br />
-<a href="http://test.tld/path/?query=value#hash">link</a></p></div>
diff --git a/tests/plugins/resources/markdown.md b/tests/plugins/resources/markdown.md
deleted file mode 100644 (file)
index 9350a8c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-* test:
-    * [zero](http://link.tld)
-    + [two](http://link.tld)
-    - [three](http://link.tld)
-
-1. [zero](http://link.tld)
-  2. [two](http://link.tld)
-   3. [three](http://link.tld)
-    4. [four](http://link.tld)
-    5. foo #foobar
-
-#foobar foo `lol #foo` #bar
-
-fsdfs http://link.tld #foobar `http://link.tld`
-
-    http://link.tld #foobar
-    next #foo
-    
-Block:
-
-```
-lorem ipsum #foobar http://link.tld
-#foobar http://link.tld
-```
-
-[link](?123456)
-![link](/img/train.png)
-[link](test.tld/path/?query=value#hash)
-[link](http://test.tld/path/?query=value#hash)
-[link](https://test.tld/path/?query=value#hash)
-[link](ftp://test.tld/path/?query=value#hash)
-[link](magnet:test.tld/path/?query=value#hash)
-[link](javascript:alert('xss'))
-[link](other://test.tld/path/?query=value#hash)
index 505b1614cf8d9f03e4ec4937422cb435446359eb..d8a15823892a57ae14be1c67f0502aa89daa31ff 100644 (file)
                 {$tag_counter=count($value.taglist)}
                 {loop="value.taglist"}
                   <span class="label label-tag" title="{$strAddTag}">
-                    <a href="?addtag={$value|urlencode}">{$value}</a>
+                    <a href="./add-tag/{$value|urlencode}">{$value}</a>
                   </span>
                   {if="$tag_counter - 1 != $counter"}&middot;{/if}
                 {/loop}
index 7839fcca78e4b1b5f6c408ae190a576a083ac4da..80dcebf5b753a444d72c3f91131ea41717a898f5 100644 (file)
@@ -49,7 +49,7 @@
     <div id="cloudtag" class="cloudtag-container">
       {loop="tags"}
         <a href="?searchtags={$key|urlencode} {$search_tags|urlencode}" style="font-size:{$value.size}em;">{$key}</a
-        ><a href="?addtag={$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value.count}</a>
+        ><a href="./add-tag/{$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value.count}</a>
         {loop="$value.tag_plugin"}
           {$value}
         {/loop}
index dbc5ee3a01eeacf9d09a0ad8615210df07a28680..01b7a642b30577194edf7bbcbd34e52aa54d112c 100644 (file)
@@ -56,7 +56,7 @@
               </a>
             {/if}
 
-            <a href="?addtag={$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value}</a>
+            <a href="./add-tag/{$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value}</a>
             <a href="?searchtags={$key|urlencode} {$search_tags|urlencode}" class="tag-link">{$key}</a>
 
             {loop="$value.tag_plugin"}
index dcb14e908042f6a6088ca118f820f19551cac47a..8f1ded95303b5204cef5954443fb58a3901d94cf 100644 (file)
                 <a href="{$value.real_url}"><span class="linkurl" title="Short link">{$value.url}</span></a><br>
                 {if="$value.tags"}
                     <div class="linktaglist">
-                    {loop="$value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value}</a></span> {/loop}
+                    {loop="$value.taglist"}<span class="linktag" title="Add tag"><a href="./add-tag/{$value|urlencode}">{$value}</a></span> {/loop}
                     </div>
                 {/if}
 
index d93bf4f9db94b8cdbbd4b97f3358025652320a72..23aa381eb7c0a2f5dfe800288c22c63bff16de3e 100644 (file)
@@ -12,7 +12,7 @@
 
     <div id="cloudtag">
         {loop="$tags"}
-            <a href="?addtag={$key|urlencode}" class="count">{$value.count}</a><a
+            <a href="./add-tag/{$key|urlencode}" class="count">{$value.count}</a><a
                 href="?searchtags={$key|urlencode}" style="font-size:{$value.size}em;">{$key}</a>
             {loop="$value.tag_plugin"}
                 {$value}