]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
API: POST/PUT Link - properly parse tags string 1672/head
authorArthurHoaro <arthur@hoa.ro>
Tue, 29 Dec 2020 11:50:23 +0000 (12:50 +0100)
committerArthurHoaro <arthur@hoa.ro>
Tue, 29 Dec 2020 12:01:04 +0000 (13:01 +0100)
Even though the documentation specify that tags should be passed as an array, tags string is actually allowed. So this adds a proper parsing with configured separator.

Related to #1651

application/api/ApiUtils.php
application/api/controllers/Links.php
tests/api/controllers/links/PostLinkTest.php
tests/api/controllers/links/PutLinkTest.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 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']);
+    }
 }