diff options
author | ArthurHoaro <arthur@hoa.ro> | 2020-10-13 12:05:08 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2020-10-13 12:05:08 +0200 |
commit | b6f678a5a1d15acf284ebcec16c905e976671ce1 (patch) | |
tree | 33c7da831482ed79c44896ef19c73c72ada84f2e /application/api | |
parent | b14687036b9b800681197f51fdc47e62f0c88e2e (diff) | |
parent | 1c1520b6b98ab20201bfe15577782a52320339df (diff) | |
download | Shaarli-b6f678a5a1d15acf284ebcec16c905e976671ce1.tar.gz Shaarli-b6f678a5a1d15acf284ebcec16c905e976671ce1.tar.zst Shaarli-b6f678a5a1d15acf284ebcec16c905e976671ce1.zip |
Merge branch 'v0.12' into latest
Diffstat (limited to 'application/api')
-rw-r--r-- | application/api/ApiMiddleware.php | 30 | ||||
-rw-r--r-- | application/api/ApiUtils.php | 83 | ||||
-rw-r--r-- | application/api/controllers/ApiController.php | 8 | ||||
-rw-r--r-- | application/api/controllers/HistoryController.php | 2 | ||||
-rw-r--r-- | application/api/controllers/Info.php | 5 | ||||
-rw-r--r-- | application/api/controllers/Links.php | 79 | ||||
-rw-r--r-- | application/api/controllers/Tags.php | 44 |
7 files changed, 130 insertions, 121 deletions
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php index 2d55bda6..f5b53b01 100644 --- a/application/api/ApiMiddleware.php +++ b/application/api/ApiMiddleware.php | |||
@@ -3,6 +3,7 @@ namespace Shaarli\Api; | |||
3 | 3 | ||
4 | use Shaarli\Api\Exceptions\ApiAuthorizationException; | 4 | use Shaarli\Api\Exceptions\ApiAuthorizationException; |
5 | use Shaarli\Api\Exceptions\ApiException; | 5 | use Shaarli\Api\Exceptions\ApiException; |
6 | use Shaarli\Bookmark\BookmarkFileService; | ||
6 | use Shaarli\Config\ConfigManager; | 7 | use Shaarli\Config\ConfigManager; |
7 | use Slim\Container; | 8 | use Slim\Container; |
8 | use Slim\Http\Request; | 9 | use Slim\Http\Request; |
@@ -70,7 +71,14 @@ class ApiMiddleware | |||
70 | $response = $e->getApiResponse(); | 71 | $response = $e->getApiResponse(); |
71 | } | 72 | } |
72 | 73 | ||
73 | return $response; | 74 | return $response |
75 | ->withHeader('Access-Control-Allow-Origin', '*') | ||
76 | ->withHeader( | ||
77 | 'Access-Control-Allow-Headers', | ||
78 | 'X-Requested-With, Content-Type, Accept, Origin, Authorization' | ||
79 | ) | ||
80 | ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') | ||
81 | ; | ||
74 | } | 82 | } |
75 | 83 | ||
76 | /** | 84 | /** |
@@ -99,7 +107,9 @@ class ApiMiddleware | |||
99 | */ | 107 | */ |
100 | protected function checkToken($request) | 108 | protected function checkToken($request) |
101 | { | 109 | { |
102 | if (! $request->hasHeader('Authorization')) { | 110 | if (!$request->hasHeader('Authorization') |
111 | && !isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION']) | ||
112 | ) { | ||
103 | throw new ApiAuthorizationException('JWT token not provided'); | 113 | throw new ApiAuthorizationException('JWT token not provided'); |
104 | } | 114 | } |
105 | 115 | ||
@@ -107,7 +117,11 @@ class ApiMiddleware | |||
107 | throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); | 117 | throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); |
108 | } | 118 | } |
109 | 119 | ||
110 | $authorization = $request->getHeaderLine('Authorization'); | 120 | if (isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])) { |
121 | $authorization = $this->container->environment['REDIRECT_HTTP_AUTHORIZATION']; | ||
122 | } else { | ||
123 | $authorization = $request->getHeaderLine('Authorization'); | ||
124 | } | ||
111 | 125 | ||
112 | if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { | 126 | if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { |
113 | throw new ApiAuthorizationException('Invalid JWT header'); | 127 | throw new ApiAuthorizationException('Invalid JWT header'); |
@@ -117,7 +131,7 @@ class ApiMiddleware | |||
117 | } | 131 | } |
118 | 132 | ||
119 | /** | 133 | /** |
120 | * Instantiate a new LinkDB including private links, | 134 | * Instantiate a new LinkDB including private bookmarks, |
121 | * and load in the Slim container. | 135 | * and load in the Slim container. |
122 | * | 136 | * |
123 | * FIXME! LinkDB could use a refactoring to avoid this trick. | 137 | * FIXME! LinkDB could use a refactoring to avoid this trick. |
@@ -126,10 +140,10 @@ class ApiMiddleware | |||
126 | */ | 140 | */ |
127 | protected function setLinkDb($conf) | 141 | protected function setLinkDb($conf) |
128 | { | 142 | { |
129 | $linkDb = new \Shaarli\Bookmark\LinkDB( | 143 | $linkDb = new BookmarkFileService( |
130 | $conf->get('resource.datastore'), | 144 | $conf, |
131 | true, | 145 | $this->container->get('history'), |
132 | $conf->get('privacy.hide_public_links') | 146 | true |
133 | ); | 147 | ); |
134 | $this->container['db'] = $linkDb; | 148 | $this->container['db'] = $linkDb; |
135 | } | 149 | } |
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php index 1e3ac02e..faebb8f5 100644 --- a/application/api/ApiUtils.php +++ b/application/api/ApiUtils.php | |||
@@ -2,6 +2,7 @@ | |||
2 | namespace Shaarli\Api; | 2 | namespace Shaarli\Api; |
3 | 3 | ||
4 | use Shaarli\Api\Exceptions\ApiAuthorizationException; | 4 | use Shaarli\Api\Exceptions\ApiAuthorizationException; |
5 | use Shaarli\Bookmark\Bookmark; | ||
5 | use Shaarli\Http\Base64Url; | 6 | use Shaarli\Http\Base64Url; |
6 | 7 | ||
7 | /** | 8 | /** |
@@ -15,6 +16,8 @@ class ApiUtils | |||
15 | * @param string $token JWT token extracted from the headers. | 16 | * @param string $token JWT token extracted from the headers. |
16 | * @param string $secret API secret set in the settings. | 17 | * @param string $secret API secret set in the settings. |
17 | * | 18 | * |
19 | * @return bool true on success | ||
20 | * | ||
18 | * @throws ApiAuthorizationException the token is not valid. | 21 | * @throws ApiAuthorizationException the token is not valid. |
19 | */ | 22 | */ |
20 | public static function validateJwtToken($token, $secret) | 23 | public static function validateJwtToken($token, $secret) |
@@ -45,33 +48,35 @@ class ApiUtils | |||
45 | ) { | 48 | ) { |
46 | throw new ApiAuthorizationException('Invalid JWT issued time'); | 49 | throw new ApiAuthorizationException('Invalid JWT issued time'); |
47 | } | 50 | } |
51 | |||
52 | return true; | ||
48 | } | 53 | } |
49 | 54 | ||
50 | /** | 55 | /** |
51 | * Format a Link for the REST API. | 56 | * Format a Link for the REST API. |
52 | * | 57 | * |
53 | * @param array $link Link data read from the datastore. | 58 | * @param Bookmark $bookmark Bookmark data read from the datastore. |
54 | * @param string $indexUrl Shaarli's index URL (used for relative URL). | 59 | * @param string $indexUrl Shaarli's index URL (used for relative URL). |
55 | * | 60 | * |
56 | * @return array Link data formatted for the REST API. | 61 | * @return array Link data formatted for the REST API. |
57 | */ | 62 | */ |
58 | public static function formatLink($link, $indexUrl) | 63 | public static function formatLink($bookmark, $indexUrl) |
59 | { | 64 | { |
60 | $out['id'] = $link['id']; | 65 | $out['id'] = $bookmark->getId(); |
61 | // Not an internal link | 66 | // Not an internal link |
62 | if (! is_note($link['url'])) { | 67 | if (! $bookmark->isNote()) { |
63 | $out['url'] = $link['url']; | 68 | $out['url'] = $bookmark->getUrl(); |
64 | } else { | 69 | } else { |
65 | $out['url'] = $indexUrl . $link['url']; | 70 | $out['url'] = rtrim($indexUrl, '/') . '/' . ltrim($bookmark->getUrl(), '/'); |
66 | } | 71 | } |
67 | $out['shorturl'] = $link['shorturl']; | 72 | $out['shorturl'] = $bookmark->getShortUrl(); |
68 | $out['title'] = $link['title']; | 73 | $out['title'] = $bookmark->getTitle(); |
69 | $out['description'] = $link['description']; | 74 | $out['description'] = $bookmark->getDescription(); |
70 | $out['tags'] = preg_split('/\s+/', $link['tags'], -1, PREG_SPLIT_NO_EMPTY); | 75 | $out['tags'] = $bookmark->getTags(); |
71 | $out['private'] = $link['private'] == true; | 76 | $out['private'] = $bookmark->isPrivate(); |
72 | $out['created'] = $link['created']->format(\DateTime::ATOM); | 77 | $out['created'] = $bookmark->getCreated()->format(\DateTime::ATOM); |
73 | if (! empty($link['updated'])) { | 78 | if (! empty($bookmark->getUpdated())) { |
74 | $out['updated'] = $link['updated']->format(\DateTime::ATOM); | 79 | $out['updated'] = $bookmark->getUpdated()->format(\DateTime::ATOM); |
75 | } else { | 80 | } else { |
76 | $out['updated'] = ''; | 81 | $out['updated'] = ''; |
77 | } | 82 | } |
@@ -79,7 +84,7 @@ class ApiUtils | |||
79 | } | 84 | } |
80 | 85 | ||
81 | /** | 86 | /** |
82 | * Convert a link given through a request, to a valid link for LinkDB. | 87 | * Convert a link given through a request, to a valid Bookmark for the datastore. |
83 | * | 88 | * |
84 | * If no URL is provided, it will generate a local note URL. | 89 | * If no URL is provided, it will generate a local note URL. |
85 | * If no title is provided, it will use the URL as title. | 90 | * If no title is provided, it will use the URL as title. |
@@ -87,50 +92,42 @@ class ApiUtils | |||
87 | * @param array $input Request Link. | 92 | * @param array $input Request Link. |
88 | * @param bool $defaultPrivate Request Link. | 93 | * @param bool $defaultPrivate Request Link. |
89 | * | 94 | * |
90 | * @return array Formatted link. | 95 | * @return Bookmark instance. |
91 | */ | 96 | */ |
92 | public static function buildLinkFromRequest($input, $defaultPrivate) | 97 | public static function buildLinkFromRequest($input, $defaultPrivate) |
93 | { | 98 | { |
94 | $input['url'] = ! empty($input['url']) ? cleanup_url($input['url']) : ''; | 99 | $bookmark = new Bookmark(); |
100 | $url = ! empty($input['url']) ? cleanup_url($input['url']) : ''; | ||
95 | if (isset($input['private'])) { | 101 | if (isset($input['private'])) { |
96 | $private = filter_var($input['private'], FILTER_VALIDATE_BOOLEAN); | 102 | $private = filter_var($input['private'], FILTER_VALIDATE_BOOLEAN); |
97 | } else { | 103 | } else { |
98 | $private = $defaultPrivate; | 104 | $private = $defaultPrivate; |
99 | } | 105 | } |
100 | 106 | ||
101 | $link = [ | 107 | $bookmark->setTitle(! empty($input['title']) ? $input['title'] : ''); |
102 | 'title' => ! empty($input['title']) ? $input['title'] : $input['url'], | 108 | $bookmark->setUrl($url); |
103 | 'url' => $input['url'], | 109 | $bookmark->setDescription(! empty($input['description']) ? $input['description'] : ''); |
104 | 'description' => ! empty($input['description']) ? $input['description'] : '', | 110 | $bookmark->setTags(! empty($input['tags']) ? $input['tags'] : []); |
105 | 'tags' => ! empty($input['tags']) ? implode(' ', $input['tags']) : '', | 111 | $bookmark->setPrivate($private); |
106 | 'private' => $private, | 112 | |
107 | 'created' => new \DateTime(), | 113 | return $bookmark; |
108 | ]; | ||
109 | return $link; | ||
110 | } | 114 | } |
111 | 115 | ||
112 | /** | 116 | /** |
113 | * Update link fields using an updated link object. | 117 | * Update link fields using an updated link object. |
114 | * | 118 | * |
115 | * @param array $oldLink data | 119 | * @param Bookmark $oldLink data |
116 | * @param array $newLink data | 120 | * @param Bookmark $newLink data |
117 | * | 121 | * |
118 | * @return array $oldLink updated with $newLink values | 122 | * @return Bookmark $oldLink updated with $newLink values |
119 | */ | 123 | */ |
120 | public static function updateLink($oldLink, $newLink) | 124 | public static function updateLink($oldLink, $newLink) |
121 | { | 125 | { |
122 | foreach (['title', 'url', 'description', 'tags', 'private'] as $field) { | 126 | $oldLink->setTitle($newLink->getTitle()); |
123 | $oldLink[$field] = $newLink[$field]; | 127 | $oldLink->setUrl($newLink->getUrl()); |
124 | } | 128 | $oldLink->setDescription($newLink->getDescription()); |
125 | $oldLink['updated'] = new \DateTime(); | 129 | $oldLink->setTags($newLink->getTags()); |
126 | 130 | $oldLink->setPrivate($newLink->isPrivate()); | |
127 | if (empty($oldLink['url'])) { | ||
128 | $oldLink['url'] = '?' . $oldLink['shorturl']; | ||
129 | } | ||
130 | |||
131 | if (empty($oldLink['title'])) { | ||
132 | $oldLink['title'] = $oldLink['url']; | ||
133 | } | ||
134 | 131 | ||
135 | return $oldLink; | 132 | return $oldLink; |
136 | } | 133 | } |
@@ -139,7 +136,7 @@ class ApiUtils | |||
139 | * Format a Tag for the REST API. | 136 | * Format a Tag for the REST API. |
140 | * | 137 | * |
141 | * @param string $tag Tag name | 138 | * @param string $tag Tag name |
142 | * @param int $occurrences Number of links using this tag | 139 | * @param int $occurrences Number of bookmarks using this tag |
143 | * | 140 | * |
144 | * @return array Link data formatted for the REST API. | 141 | * @return array Link data formatted for the REST API. |
145 | */ | 142 | */ |
diff --git a/application/api/controllers/ApiController.php b/application/api/controllers/ApiController.php index a6e7cbab..c4b3d0c3 100644 --- a/application/api/controllers/ApiController.php +++ b/application/api/controllers/ApiController.php | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | namespace Shaarli\Api\Controllers; | 3 | namespace Shaarli\Api\Controllers; |
4 | 4 | ||
5 | use Shaarli\Bookmark\LinkDB; | 5 | use Shaarli\Bookmark\BookmarkServiceInterface; |
6 | use Shaarli\Config\ConfigManager; | 6 | use Shaarli\Config\ConfigManager; |
7 | use Slim\Container; | 7 | use Slim\Container; |
8 | 8 | ||
@@ -26,9 +26,9 @@ abstract class ApiController | |||
26 | protected $conf; | 26 | protected $conf; |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * @var LinkDB | 29 | * @var BookmarkServiceInterface |
30 | */ | 30 | */ |
31 | protected $linkDb; | 31 | protected $bookmarkService; |
32 | 32 | ||
33 | /** | 33 | /** |
34 | * @var HistoryController | 34 | * @var HistoryController |
@@ -51,7 +51,7 @@ abstract class ApiController | |||
51 | { | 51 | { |
52 | $this->ci = $ci; | 52 | $this->ci = $ci; |
53 | $this->conf = $ci->get('conf'); | 53 | $this->conf = $ci->get('conf'); |
54 | $this->linkDb = $ci->get('db'); | 54 | $this->bookmarkService = $ci->get('db'); |
55 | $this->history = $ci->get('history'); | 55 | $this->history = $ci->get('history'); |
56 | if ($this->conf->get('dev.debug', false)) { | 56 | if ($this->conf->get('dev.debug', false)) { |
57 | $this->jsonStyle = JSON_PRETTY_PRINT; | 57 | $this->jsonStyle = JSON_PRETTY_PRINT; |
diff --git a/application/api/controllers/HistoryController.php b/application/api/controllers/HistoryController.php index 9afcfa26..505647a9 100644 --- a/application/api/controllers/HistoryController.php +++ b/application/api/controllers/HistoryController.php | |||
@@ -41,7 +41,7 @@ class HistoryController extends ApiController | |||
41 | throw new ApiBadParametersException('Invalid offset'); | 41 | throw new ApiBadParametersException('Invalid offset'); |
42 | } | 42 | } |
43 | 43 | ||
44 | // limit parameter is either a number of links or 'all' for everything. | 44 | // limit parameter is either a number of bookmarks or 'all' for everything. |
45 | $limit = $request->getParam('limit'); | 45 | $limit = $request->getParam('limit'); |
46 | if (empty($limit)) { | 46 | if (empty($limit)) { |
47 | $limit = count($history); | 47 | $limit = count($history); |
diff --git a/application/api/controllers/Info.php b/application/api/controllers/Info.php index f37dcae5..12f6b2f0 100644 --- a/application/api/controllers/Info.php +++ b/application/api/controllers/Info.php | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | namespace Shaarli\Api\Controllers; | 3 | namespace Shaarli\Api\Controllers; |
4 | 4 | ||
5 | use Shaarli\Bookmark\BookmarkFilter; | ||
5 | use Slim\Http\Request; | 6 | use Slim\Http\Request; |
6 | use Slim\Http\Response; | 7 | use Slim\Http\Response; |
7 | 8 | ||
@@ -26,8 +27,8 @@ class Info extends ApiController | |||
26 | public function getInfo($request, $response) | 27 | public function getInfo($request, $response) |
27 | { | 28 | { |
28 | $info = [ | 29 | $info = [ |
29 | 'global_counter' => count($this->linkDb), | 30 | 'global_counter' => $this->bookmarkService->count(), |
30 | 'private_counter' => count_private($this->linkDb), | 31 | 'private_counter' => $this->bookmarkService->count(BookmarkFilter::$PRIVATE), |
31 | 'settings' => array( | 32 | 'settings' => array( |
32 | 'title' => $this->conf->get('general.title', 'Shaarli'), | 33 | 'title' => $this->conf->get('general.title', 'Shaarli'), |
33 | 'header_link' => $this->conf->get('general.header_link', '?'), | 34 | 'header_link' => $this->conf->get('general.header_link', '?'), |
diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php index ffcfd4c7..29247950 100644 --- a/application/api/controllers/Links.php +++ b/application/api/controllers/Links.php | |||
@@ -11,7 +11,7 @@ use Slim\Http\Response; | |||
11 | /** | 11 | /** |
12 | * Class Links | 12 | * Class Links |
13 | * | 13 | * |
14 | * REST API Controller: all services related to links collection. | 14 | * REST API Controller: all services related to bookmarks collection. |
15 | * | 15 | * |
16 | * @package Api\Controllers | 16 | * @package Api\Controllers |
17 | * @see http://shaarli.github.io/api-documentation/#links-links-collection | 17 | * @see http://shaarli.github.io/api-documentation/#links-links-collection |
@@ -19,12 +19,12 @@ use Slim\Http\Response; | |||
19 | class Links extends ApiController | 19 | class Links extends ApiController |
20 | { | 20 | { |
21 | /** | 21 | /** |
22 | * @var int Number of links returned if no limit is provided. | 22 | * @var int Number of bookmarks returned if no limit is provided. |
23 | */ | 23 | */ |
24 | public static $DEFAULT_LIMIT = 20; | 24 | public static $DEFAULT_LIMIT = 20; |
25 | 25 | ||
26 | /** | 26 | /** |
27 | * Retrieve a list of links, allowing different filters. | 27 | * Retrieve a list of bookmarks, allowing different filters. |
28 | * | 28 | * |
29 | * @param Request $request Slim request. | 29 | * @param Request $request Slim request. |
30 | * @param Response $response Slim response. | 30 | * @param Response $response Slim response. |
@@ -36,33 +36,32 @@ class Links extends ApiController | |||
36 | public function getLinks($request, $response) | 36 | public function getLinks($request, $response) |
37 | { | 37 | { |
38 | $private = $request->getParam('visibility'); | 38 | $private = $request->getParam('visibility'); |
39 | $links = $this->linkDb->filterSearch( | 39 | $bookmarks = $this->bookmarkService->search( |
40 | [ | 40 | [ |
41 | 'searchtags' => $request->getParam('searchtags', ''), | 41 | 'searchtags' => $request->getParam('searchtags', ''), |
42 | 'searchterm' => $request->getParam('searchterm', ''), | 42 | 'searchterm' => $request->getParam('searchterm', ''), |
43 | ], | 43 | ], |
44 | false, | ||
45 | $private | 44 | $private |
46 | ); | 45 | ); |
47 | 46 | ||
48 | // Return links from the {offset}th link, starting from 0. | 47 | // Return bookmarks from the {offset}th link, starting from 0. |
49 | $offset = $request->getParam('offset'); | 48 | $offset = $request->getParam('offset'); |
50 | if (! empty($offset) && ! ctype_digit($offset)) { | 49 | if (! empty($offset) && ! ctype_digit($offset)) { |
51 | throw new ApiBadParametersException('Invalid offset'); | 50 | throw new ApiBadParametersException('Invalid offset'); |
52 | } | 51 | } |
53 | $offset = ! empty($offset) ? intval($offset) : 0; | 52 | $offset = ! empty($offset) ? intval($offset) : 0; |
54 | if ($offset > count($links)) { | 53 | if ($offset > count($bookmarks)) { |
55 | return $response->withJson([], 200, $this->jsonStyle); | 54 | return $response->withJson([], 200, $this->jsonStyle); |
56 | } | 55 | } |
57 | 56 | ||
58 | // limit parameter is either a number of links or 'all' for everything. | 57 | // limit parameter is either a number of bookmarks or 'all' for everything. |
59 | $limit = $request->getParam('limit'); | 58 | $limit = $request->getParam('limit'); |
60 | if (empty($limit)) { | 59 | if (empty($limit)) { |
61 | $limit = self::$DEFAULT_LIMIT; | 60 | $limit = self::$DEFAULT_LIMIT; |
62 | } elseif (ctype_digit($limit)) { | 61 | } elseif (ctype_digit($limit)) { |
63 | $limit = intval($limit); | 62 | $limit = intval($limit); |
64 | } elseif ($limit === 'all') { | 63 | } elseif ($limit === 'all') { |
65 | $limit = count($links); | 64 | $limit = count($bookmarks); |
66 | } else { | 65 | } else { |
67 | throw new ApiBadParametersException('Invalid limit'); | 66 | throw new ApiBadParametersException('Invalid limit'); |
68 | } | 67 | } |
@@ -72,12 +71,12 @@ class Links extends ApiController | |||
72 | 71 | ||
73 | $out = []; | 72 | $out = []; |
74 | $index = 0; | 73 | $index = 0; |
75 | foreach ($links as $link) { | 74 | foreach ($bookmarks as $bookmark) { |
76 | if (count($out) >= $limit) { | 75 | if (count($out) >= $limit) { |
77 | break; | 76 | break; |
78 | } | 77 | } |
79 | if ($index++ >= $offset) { | 78 | if ($index++ >= $offset) { |
80 | $out[] = ApiUtils::formatLink($link, $indexUrl); | 79 | $out[] = ApiUtils::formatLink($bookmark, $indexUrl); |
81 | } | 80 | } |
82 | } | 81 | } |
83 | 82 | ||
@@ -97,11 +96,11 @@ class Links extends ApiController | |||
97 | */ | 96 | */ |
98 | public function getLink($request, $response, $args) | 97 | public function getLink($request, $response, $args) |
99 | { | 98 | { |
100 | if (!isset($this->linkDb[$args['id']])) { | 99 | if (!$this->bookmarkService->exists($args['id'])) { |
101 | throw new ApiLinkNotFoundException(); | 100 | throw new ApiLinkNotFoundException(); |
102 | } | 101 | } |
103 | $index = index_url($this->ci['environment']); | 102 | $index = index_url($this->ci['environment']); |
104 | $out = ApiUtils::formatLink($this->linkDb[$args['id']], $index); | 103 | $out = ApiUtils::formatLink($this->bookmarkService->get($args['id']), $index); |
105 | 104 | ||
106 | return $response->withJson($out, 200, $this->jsonStyle); | 105 | return $response->withJson($out, 200, $this->jsonStyle); |
107 | } | 106 | } |
@@ -117,9 +116,11 @@ class Links extends ApiController | |||
117 | public function postLink($request, $response) | 116 | public function postLink($request, $response) |
118 | { | 117 | { |
119 | $data = $request->getParsedBody(); | 118 | $data = $request->getParsedBody(); |
120 | $link = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); | 119 | $bookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); |
121 | // duplicate by URL, return 409 Conflict | 120 | // duplicate by URL, return 409 Conflict |
122 | if (! empty($link['url']) && ! empty($dup = $this->linkDb->getLinkFromUrl($link['url']))) { | 121 | if (! empty($bookmark->getUrl()) |
122 | && ! empty($dup = $this->bookmarkService->findByUrl($bookmark->getUrl())) | ||
123 | ) { | ||
123 | return $response->withJson( | 124 | return $response->withJson( |
124 | ApiUtils::formatLink($dup, index_url($this->ci['environment'])), | 125 | ApiUtils::formatLink($dup, index_url($this->ci['environment'])), |
125 | 409, | 126 | 409, |
@@ -127,23 +128,9 @@ class Links extends ApiController | |||
127 | ); | 128 | ); |
128 | } | 129 | } |
129 | 130 | ||
130 | $link['id'] = $this->linkDb->getNextId(); | 131 | $this->bookmarkService->add($bookmark); |
131 | $link['shorturl'] = link_small_hash($link['created'], $link['id']); | 132 | $out = ApiUtils::formatLink($bookmark, index_url($this->ci['environment'])); |
132 | 133 | $redirect = $this->ci->router->relativePathFor('getLink', ['id' => $bookmark->getId()]); | |
133 | // note: general relative URL | ||
134 | if (empty($link['url'])) { | ||
135 | $link['url'] = '?' . $link['shorturl']; | ||
136 | } | ||
137 | |||
138 | if (empty($link['title'])) { | ||
139 | $link['title'] = $link['url']; | ||
140 | } | ||
141 | |||
142 | $this->linkDb[$link['id']] = $link; | ||
143 | $this->linkDb->save($this->conf->get('resource.page_cache')); | ||
144 | $this->history->addLink($link); | ||
145 | $out = ApiUtils::formatLink($link, index_url($this->ci['environment'])); | ||
146 | $redirect = $this->ci->router->relativePathFor('getLink', ['id' => $link['id']]); | ||
147 | return $response->withAddedHeader('Location', $redirect) | 134 | return $response->withAddedHeader('Location', $redirect) |
148 | ->withJson($out, 201, $this->jsonStyle); | 135 | ->withJson($out, 201, $this->jsonStyle); |
149 | } | 136 | } |
@@ -161,18 +148,18 @@ class Links extends ApiController | |||
161 | */ | 148 | */ |
162 | public function putLink($request, $response, $args) | 149 | public function putLink($request, $response, $args) |
163 | { | 150 | { |
164 | if (! isset($this->linkDb[$args['id']])) { | 151 | if (! $this->bookmarkService->exists($args['id'])) { |
165 | throw new ApiLinkNotFoundException(); | 152 | throw new ApiLinkNotFoundException(); |
166 | } | 153 | } |
167 | 154 | ||
168 | $index = index_url($this->ci['environment']); | 155 | $index = index_url($this->ci['environment']); |
169 | $data = $request->getParsedBody(); | 156 | $data = $request->getParsedBody(); |
170 | 157 | ||
171 | $requestLink = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); | 158 | $requestBookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); |
172 | // duplicate URL on a different link, return 409 Conflict | 159 | // duplicate URL on a different link, return 409 Conflict |
173 | if (! empty($requestLink['url']) | 160 | if (! empty($requestBookmark->getUrl()) |
174 | && ! empty($dup = $this->linkDb->getLinkFromUrl($requestLink['url'])) | 161 | && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl())) |
175 | && $dup['id'] != $args['id'] | 162 | && $dup->getId() != $args['id'] |
176 | ) { | 163 | ) { |
177 | return $response->withJson( | 164 | return $response->withJson( |
178 | ApiUtils::formatLink($dup, $index), | 165 | ApiUtils::formatLink($dup, $index), |
@@ -181,13 +168,11 @@ class Links extends ApiController | |||
181 | ); | 168 | ); |
182 | } | 169 | } |
183 | 170 | ||
184 | $responseLink = $this->linkDb[$args['id']]; | 171 | $responseBookmark = $this->bookmarkService->get($args['id']); |
185 | $responseLink = ApiUtils::updateLink($responseLink, $requestLink); | 172 | $responseBookmark = ApiUtils::updateLink($responseBookmark, $requestBookmark); |
186 | $this->linkDb[$responseLink['id']] = $responseLink; | 173 | $this->bookmarkService->set($responseBookmark); |
187 | $this->linkDb->save($this->conf->get('resource.page_cache')); | ||
188 | $this->history->updateLink($responseLink); | ||
189 | 174 | ||
190 | $out = ApiUtils::formatLink($responseLink, $index); | 175 | $out = ApiUtils::formatLink($responseBookmark, $index); |
191 | return $response->withJson($out, 200, $this->jsonStyle); | 176 | return $response->withJson($out, 200, $this->jsonStyle); |
192 | } | 177 | } |
193 | 178 | ||
@@ -204,13 +189,11 @@ class Links extends ApiController | |||
204 | */ | 189 | */ |
205 | public function deleteLink($request, $response, $args) | 190 | public function deleteLink($request, $response, $args) |
206 | { | 191 | { |
207 | if (! isset($this->linkDb[$args['id']])) { | 192 | if (! $this->bookmarkService->exists($args['id'])) { |
208 | throw new ApiLinkNotFoundException(); | 193 | throw new ApiLinkNotFoundException(); |
209 | } | 194 | } |
210 | $link = $this->linkDb[$args['id']]; | 195 | $bookmark = $this->bookmarkService->get($args['id']); |
211 | unset($this->linkDb[(int) $args['id']]); | 196 | $this->bookmarkService->remove($bookmark); |
212 | $this->linkDb->save($this->conf->get('resource.page_cache')); | ||
213 | $this->history->deleteLink($link); | ||
214 | 197 | ||
215 | return $response->withStatus(204); | 198 | return $response->withStatus(204); |
216 | } | 199 | } |
diff --git a/application/api/controllers/Tags.php b/application/api/controllers/Tags.php index 82f3ef74..e60e00a7 100644 --- a/application/api/controllers/Tags.php +++ b/application/api/controllers/Tags.php | |||
@@ -5,6 +5,7 @@ namespace Shaarli\Api\Controllers; | |||
5 | use Shaarli\Api\ApiUtils; | 5 | use Shaarli\Api\ApiUtils; |
6 | use Shaarli\Api\Exceptions\ApiBadParametersException; | 6 | use Shaarli\Api\Exceptions\ApiBadParametersException; |
7 | use Shaarli\Api\Exceptions\ApiTagNotFoundException; | 7 | use Shaarli\Api\Exceptions\ApiTagNotFoundException; |
8 | use Shaarli\Bookmark\BookmarkFilter; | ||
8 | use Slim\Http\Request; | 9 | use Slim\Http\Request; |
9 | use Slim\Http\Response; | 10 | use Slim\Http\Response; |
10 | 11 | ||
@@ -18,7 +19,7 @@ use Slim\Http\Response; | |||
18 | class Tags extends ApiController | 19 | class Tags extends ApiController |
19 | { | 20 | { |
20 | /** | 21 | /** |
21 | * @var int Number of links returned if no limit is provided. | 22 | * @var int Number of bookmarks returned if no limit is provided. |
22 | */ | 23 | */ |
23 | public static $DEFAULT_LIMIT = 'all'; | 24 | public static $DEFAULT_LIMIT = 'all'; |
24 | 25 | ||
@@ -35,7 +36,7 @@ class Tags extends ApiController | |||
35 | public function getTags($request, $response) | 36 | public function getTags($request, $response) |
36 | { | 37 | { |
37 | $visibility = $request->getParam('visibility'); | 38 | $visibility = $request->getParam('visibility'); |
38 | $tags = $this->linkDb->linksCountPerTag([], $visibility); | 39 | $tags = $this->bookmarkService->bookmarksCountPerTag([], $visibility); |
39 | 40 | ||
40 | // Return tags from the {offset}th tag, starting from 0. | 41 | // Return tags from the {offset}th tag, starting from 0. |
41 | $offset = $request->getParam('offset'); | 42 | $offset = $request->getParam('offset'); |
@@ -47,7 +48,7 @@ class Tags extends ApiController | |||
47 | return $response->withJson([], 200, $this->jsonStyle); | 48 | return $response->withJson([], 200, $this->jsonStyle); |
48 | } | 49 | } |
49 | 50 | ||
50 | // limit parameter is either a number of links or 'all' for everything. | 51 | // limit parameter is either a number of bookmarks or 'all' for everything. |
51 | $limit = $request->getParam('limit'); | 52 | $limit = $request->getParam('limit'); |
52 | if (empty($limit)) { | 53 | if (empty($limit)) { |
53 | $limit = self::$DEFAULT_LIMIT; | 54 | $limit = self::$DEFAULT_LIMIT; |
@@ -87,7 +88,7 @@ class Tags extends ApiController | |||
87 | */ | 88 | */ |
88 | public function getTag($request, $response, $args) | 89 | public function getTag($request, $response, $args) |
89 | { | 90 | { |
90 | $tags = $this->linkDb->linksCountPerTag(); | 91 | $tags = $this->bookmarkService->bookmarksCountPerTag(); |
91 | if (!isset($tags[$args['tagName']])) { | 92 | if (!isset($tags[$args['tagName']])) { |
92 | throw new ApiTagNotFoundException(); | 93 | throw new ApiTagNotFoundException(); |
93 | } | 94 | } |
@@ -111,7 +112,7 @@ class Tags extends ApiController | |||
111 | */ | 112 | */ |
112 | public function putTag($request, $response, $args) | 113 | public function putTag($request, $response, $args) |
113 | { | 114 | { |
114 | $tags = $this->linkDb->linksCountPerTag(); | 115 | $tags = $this->bookmarkService->bookmarksCountPerTag(); |
115 | if (! isset($tags[$args['tagName']])) { | 116 | if (! isset($tags[$args['tagName']])) { |
116 | throw new ApiTagNotFoundException(); | 117 | throw new ApiTagNotFoundException(); |
117 | } | 118 | } |
@@ -121,13 +122,19 @@ class Tags extends ApiController | |||
121 | throw new ApiBadParametersException('New tag name is required in the request body'); | 122 | throw new ApiBadParametersException('New tag name is required in the request body'); |
122 | } | 123 | } |
123 | 124 | ||
124 | $updated = $this->linkDb->renameTag($args['tagName'], $data['name']); | 125 | $bookmarks = $this->bookmarkService->search( |
125 | $this->linkDb->save($this->conf->get('resource.page_cache')); | 126 | ['searchtags' => $args['tagName']], |
126 | foreach ($updated as $link) { | 127 | BookmarkFilter::$ALL, |
127 | $this->history->updateLink($link); | 128 | true |
129 | ); | ||
130 | foreach ($bookmarks as $bookmark) { | ||
131 | $bookmark->renameTag($args['tagName'], $data['name']); | ||
132 | $this->bookmarkService->set($bookmark, false); | ||
133 | $this->history->updateLink($bookmark); | ||
128 | } | 134 | } |
135 | $this->bookmarkService->save(); | ||
129 | 136 | ||
130 | $tags = $this->linkDb->linksCountPerTag(); | 137 | $tags = $this->bookmarkService->bookmarksCountPerTag(); |
131 | $out = ApiUtils::formatTag($data['name'], $tags[$data['name']]); | 138 | $out = ApiUtils::formatTag($data['name'], $tags[$data['name']]); |
132 | return $response->withJson($out, 200, $this->jsonStyle); | 139 | return $response->withJson($out, 200, $this->jsonStyle); |
133 | } | 140 | } |
@@ -145,15 +152,22 @@ class Tags extends ApiController | |||
145 | */ | 152 | */ |
146 | public function deleteTag($request, $response, $args) | 153 | public function deleteTag($request, $response, $args) |
147 | { | 154 | { |
148 | $tags = $this->linkDb->linksCountPerTag(); | 155 | $tags = $this->bookmarkService->bookmarksCountPerTag(); |
149 | if (! isset($tags[$args['tagName']])) { | 156 | if (! isset($tags[$args['tagName']])) { |
150 | throw new ApiTagNotFoundException(); | 157 | throw new ApiTagNotFoundException(); |
151 | } | 158 | } |
152 | $updated = $this->linkDb->renameTag($args['tagName'], null); | 159 | |
153 | $this->linkDb->save($this->conf->get('resource.page_cache')); | 160 | $bookmarks = $this->bookmarkService->search( |
154 | foreach ($updated as $link) { | 161 | ['searchtags' => $args['tagName']], |
155 | $this->history->updateLink($link); | 162 | BookmarkFilter::$ALL, |
163 | true | ||
164 | ); | ||
165 | foreach ($bookmarks as $bookmark) { | ||
166 | $bookmark->deleteTag($args['tagName']); | ||
167 | $this->bookmarkService->set($bookmark, false); | ||
168 | $this->history->updateLink($bookmark); | ||
156 | } | 169 | } |
170 | $this->bookmarkService->save(); | ||
157 | 171 | ||
158 | return $response->withStatus(204); | 172 | return $response->withStatus(204); |
159 | } | 173 | } |