diff options
author | ArthurHoaro <arthur@hoa.ro> | 2018-07-28 11:07:55 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2018-07-28 11:07:55 +0200 |
commit | 83faedadff76c5bdca036f39f13943f63b27e164 (patch) | |
tree | 6f44cede16ec6a60f10b9699e211e0818f06d2c8 /application/api/controllers/Links.php | |
parent | 1d9eb22a3df85b67fe6652c0876cd7382c2fb525 (diff) | |
parent | 658988f3aeba7a5a938783249ccf2765251e5597 (diff) | |
download | Shaarli-83faedadff76c5bdca036f39f13943f63b27e164.tar.gz Shaarli-83faedadff76c5bdca036f39f13943f63b27e164.tar.zst Shaarli-83faedadff76c5bdca036f39f13943f63b27e164.zip |
Merge tag 'v0.9.7' into stable
Release v0.9.7
Diffstat (limited to 'application/api/controllers/Links.php')
-rw-r--r-- | application/api/controllers/Links.php | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php new file mode 100644 index 00000000..eb78dd26 --- /dev/null +++ b/application/api/controllers/Links.php | |||
@@ -0,0 +1,217 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Shaarli\Api\Controllers; | ||
4 | |||
5 | use Shaarli\Api\ApiUtils; | ||
6 | use Shaarli\Api\Exceptions\ApiBadParametersException; | ||
7 | use Shaarli\Api\Exceptions\ApiLinkNotFoundException; | ||
8 | use Slim\Http\Request; | ||
9 | use Slim\Http\Response; | ||
10 | |||
11 | /** | ||
12 | * Class Links | ||
13 | * | ||
14 | * REST API Controller: all services related to links collection. | ||
15 | * | ||
16 | * @package Api\Controllers | ||
17 | * @see http://shaarli.github.io/api-documentation/#links-links-collection | ||
18 | */ | ||
19 | class Links extends ApiController | ||
20 | { | ||
21 | /** | ||
22 | * @var int Number of links returned if no limit is provided. | ||
23 | */ | ||
24 | public static $DEFAULT_LIMIT = 20; | ||
25 | |||
26 | /** | ||
27 | * Retrieve a list of links, allowing different filters. | ||
28 | * | ||
29 | * @param Request $request Slim request. | ||
30 | * @param Response $response Slim response. | ||
31 | * | ||
32 | * @return Response response. | ||
33 | * | ||
34 | * @throws ApiBadParametersException Invalid parameters. | ||
35 | */ | ||
36 | public function getLinks($request, $response) | ||
37 | { | ||
38 | $private = $request->getParam('visibility'); | ||
39 | $links = $this->linkDb->filterSearch( | ||
40 | [ | ||
41 | 'searchtags' => $request->getParam('searchtags', ''), | ||
42 | 'searchterm' => $request->getParam('searchterm', ''), | ||
43 | ], | ||
44 | false, | ||
45 | $private | ||
46 | ); | ||
47 | |||
48 | // Return links from the {offset}th link, starting from 0. | ||
49 | $offset = $request->getParam('offset'); | ||
50 | if (! empty($offset) && ! ctype_digit($offset)) { | ||
51 | throw new ApiBadParametersException('Invalid offset'); | ||
52 | } | ||
53 | $offset = ! empty($offset) ? intval($offset) : 0; | ||
54 | if ($offset > count($links)) { | ||
55 | return $response->withJson([], 200, $this->jsonStyle); | ||
56 | } | ||
57 | |||
58 | // limit parameter is either a number of links or 'all' for everything. | ||
59 | $limit = $request->getParam('limit'); | ||
60 | if (empty($limit)) { | ||
61 | $limit = self::$DEFAULT_LIMIT; | ||
62 | } else if (ctype_digit($limit)) { | ||
63 | $limit = intval($limit); | ||
64 | } else if ($limit === 'all') { | ||
65 | $limit = count($links); | ||
66 | } else { | ||
67 | throw new ApiBadParametersException('Invalid limit'); | ||
68 | } | ||
69 | |||
70 | // 'environment' is set by Slim and encapsulate $_SERVER. | ||
71 | $index = index_url($this->ci['environment']); | ||
72 | |||
73 | $out = []; | ||
74 | $cpt = 0; | ||
75 | foreach ($links as $link) { | ||
76 | if (count($out) >= $limit) { | ||
77 | break; | ||
78 | } | ||
79 | if ($cpt++ >= $offset) { | ||
80 | $out[] = ApiUtils::formatLink($link, $index); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | return $response->withJson($out, 200, $this->jsonStyle); | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * Return a single formatted link by its ID. | ||
89 | * | ||
90 | * @param Request $request Slim request. | ||
91 | * @param Response $response Slim response. | ||
92 | * @param array $args Path parameters. including the ID. | ||
93 | * | ||
94 | * @return Response containing the link array. | ||
95 | * | ||
96 | * @throws ApiLinkNotFoundException generating a 404 error. | ||
97 | */ | ||
98 | public function getLink($request, $response, $args) | ||
99 | { | ||
100 | if (!isset($this->linkDb[$args['id']])) { | ||
101 | throw new ApiLinkNotFoundException(); | ||
102 | } | ||
103 | $index = index_url($this->ci['environment']); | ||
104 | $out = ApiUtils::formatLink($this->linkDb[$args['id']], $index); | ||
105 | |||
106 | return $response->withJson($out, 200, $this->jsonStyle); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * Creates a new link from posted request body. | ||
111 | * | ||
112 | * @param Request $request Slim request. | ||
113 | * @param Response $response Slim response. | ||
114 | * | ||
115 | * @return Response response. | ||
116 | */ | ||
117 | public function postLink($request, $response) | ||
118 | { | ||
119 | $data = $request->getParsedBody(); | ||
120 | $link = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); | ||
121 | // duplicate by URL, return 409 Conflict | ||
122 | if (! empty($link['url']) && ! empty($dup = $this->linkDb->getLinkFromUrl($link['url']))) { | ||
123 | return $response->withJson( | ||
124 | ApiUtils::formatLink($dup, index_url($this->ci['environment'])), | ||
125 | 409, | ||
126 | $this->jsonStyle | ||
127 | ); | ||
128 | } | ||
129 | |||
130 | $link['id'] = $this->linkDb->getNextId(); | ||
131 | $link['shorturl'] = link_small_hash($link['created'], $link['id']); | ||
132 | |||
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) | ||
148 | ->withJson($out, 201, $this->jsonStyle); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * Updates an existing link from posted request body. | ||
153 | * | ||
154 | * @param Request $request Slim request. | ||
155 | * @param Response $response Slim response. | ||
156 | * @param array $args Path parameters. including the ID. | ||
157 | * | ||
158 | * @return Response response. | ||
159 | * | ||
160 | * @throws ApiLinkNotFoundException generating a 404 error. | ||
161 | */ | ||
162 | public function putLink($request, $response, $args) | ||
163 | { | ||
164 | if (! isset($this->linkDb[$args['id']])) { | ||
165 | throw new ApiLinkNotFoundException(); | ||
166 | } | ||
167 | |||
168 | $index = index_url($this->ci['environment']); | ||
169 | $data = $request->getParsedBody(); | ||
170 | |||
171 | $requestLink = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); | ||
172 | // duplicate URL on a different link, return 409 Conflict | ||
173 | if (! empty($requestLink['url']) | ||
174 | && ! empty($dup = $this->linkDb->getLinkFromUrl($requestLink['url'])) | ||
175 | && $dup['id'] != $args['id'] | ||
176 | ) { | ||
177 | return $response->withJson( | ||
178 | ApiUtils::formatLink($dup, $index), | ||
179 | 409, | ||
180 | $this->jsonStyle | ||
181 | ); | ||
182 | } | ||
183 | |||
184 | $responseLink = $this->linkDb[$args['id']]; | ||
185 | $responseLink = ApiUtils::updateLink($responseLink, $requestLink); | ||
186 | $this->linkDb[$responseLink['id']] = $responseLink; | ||
187 | $this->linkDb->save($this->conf->get('resource.page_cache')); | ||
188 | $this->history->updateLink($responseLink); | ||
189 | |||
190 | $out = ApiUtils::formatLink($responseLink, $index); | ||
191 | return $response->withJson($out, 200, $this->jsonStyle); | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * Delete an existing link by its ID. | ||
196 | * | ||
197 | * @param Request $request Slim request. | ||
198 | * @param Response $response Slim response. | ||
199 | * @param array $args Path parameters. including the ID. | ||
200 | * | ||
201 | * @return Response response. | ||
202 | * | ||
203 | * @throws ApiLinkNotFoundException generating a 404 error. | ||
204 | */ | ||
205 | public function deleteLink($request, $response, $args) | ||
206 | { | ||
207 | if (! isset($this->linkDb[$args['id']])) { | ||
208 | throw new ApiLinkNotFoundException(); | ||
209 | } | ||
210 | $link = $this->linkDb[$args['id']]; | ||
211 | unset($this->linkDb[(int) $args['id']]); | ||
212 | $this->linkDb->save($this->conf->get('resource.page_cache')); | ||
213 | $this->history->deleteLink($link); | ||
214 | |||
215 | return $response->withStatus(204); | ||
216 | } | ||
217 | } | ||