]> git.immae.eu Git - github/wallabag/wallabag.git/blame - src/Wallabag/ApiBundle/Controller/WallabagRestController.php
Merge pull request #2052 from danbartram/feature-filter-unread
[github/wallabag/wallabag.git] / src / Wallabag / ApiBundle / Controller / WallabagRestController.php
CommitLineData
f8bf8952
NL
1<?php
2
769e19dc 3namespace Wallabag\ApiBundle\Controller;
f8bf8952 4
fcb1fba5 5use FOS\RestBundle\Controller\FOSRestController;
619cc453
JB
6use Hateoas\Configuration\Route;
7use Hateoas\Representation\Factory\PagerfantaFactory;
f8bf8952 8use Nelmio\ApiDocBundle\Annotation\ApiDoc;
27f15aa4 9use Symfony\Component\HttpFoundation\Request;
b0cce9e6 10use Symfony\Component\HttpFoundation\Response;
1d76102a 11use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
b0b893ea 12use Symfony\Component\Security\Core\Exception\AccessDeniedException;
be463487 13use Wallabag\CoreBundle\Entity\Entry;
653e8be4 14use Wallabag\CoreBundle\Entity\Tag;
f8bf8952 15
fcb1fba5 16class WallabagRestController extends FOSRestController
f8bf8952 17{
77273253
NL
18 private function validateAuthentication()
19 {
18f8f32f 20 if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
77273253
NL
21 throw new AccessDeniedException();
22 }
23 }
24
f8bf8952 25 /**
a8c90c5c 26 * Retrieve all entries. It could be filtered by many options.
f8bf8952
NL
27 *
28 * @ApiDoc(
a8c90c5c 29 * parameters={
189ef634
TC
30 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."},
31 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."},
a8c90c5c
NL
32 * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."},
33 * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."},
34 * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."},
35 * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."},
189ef634 36 * {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."},
a8c90c5c 37 * }
f8bf8952 38 * )
4346a860 39 *
8eedc8cf 40 * @return Response
f8bf8952 41 */
27f15aa4 42 public function getEntriesAction(Request $request)
f8bf8952 43 {
77273253
NL
44 $this->validateAuthentication();
45
0135c98b
NL
46 $isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive');
47 $isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred');
8ce32af6
JB
48 $sort = $request->query->get('sort', 'created');
49 $order = $request->query->get('order', 'desc');
50 $page = (int) $request->query->get('page', 1);
51 $perPage = (int) $request->query->get('perPage', 30);
a8c90c5c 52
fc732227 53 $pager = $this->getDoctrine()
be463487 54 ->getRepository('WallabagCoreBundle:Entry')
5c3ca4fe 55 ->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order);
a8c90c5c 56
6e22bd73
WD
57 $pager->setCurrentPage($page);
58 $pager->setMaxPerPage($perPage);
59
8ce32af6 60 $pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
6e22bd73
WD
61 $paginatedCollection = $pagerfantaFactory->createRepresentation(
62 $pager,
1d76102a 63 new Route('api_get_entries', [], UrlGeneratorInterface::ABSOLUTE_URL)
6e22bd73
WD
64 );
65
66 $json = $this->get('serializer')->serialize($paginatedCollection, 'json');
0f006880 67
769e19dc 68 return $this->renderJsonResponse($json);
f8bf8952
NL
69 }
70
71 /**
4346a860 72 * Retrieve a single entry.
f8bf8952
NL
73 *
74 * @ApiDoc(
75 * requirements={
76 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
77 * }
78 * )
4346a860 79 *
8eedc8cf 80 * @return Response
f8bf8952 81 */
be463487 82 public function getEntryAction(Entry $entry)
f8bf8952 83 {
77273253 84 $this->validateAuthentication();
fcb1fba5 85 $this->validateUserAccess($entry->getUser()->getId());
092ca707 86
aa4d6562 87 $json = $this->get('serializer')->serialize($entry, 'json');
0f006880 88
769e19dc 89 return $this->renderJsonResponse($json);
f8bf8952
NL
90 }
91
92 /**
4346a860 93 * Create an entry.
f8bf8952
NL
94 *
95 * @ApiDoc(
a8c90c5c
NL
96 * parameters={
97 * {"name"="url", "dataType"="string", "required"=true, "format"="http://www.test.com/article.html", "description"="Url for the entry."},
98 * {"name"="title", "dataType"="string", "required"=false, "description"="Optional, we'll get the title from the page."},
99 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
189ef634
TC
100 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already starred"},
101 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already archived"},
a8c90c5c 102 * }
f8bf8952 103 * )
4346a860 104 *
8eedc8cf 105 * @return Response
f8bf8952 106 */
843dbe51 107 public function postEntriesAction(Request $request)
f8bf8952 108 {
77273253
NL
109 $this->validateAuthentication();
110
c3235553 111 $url = $request->request->get('url');
51a15609 112 $title = $request->request->get('title');
873e3806
YE
113 $isArchived = $request->request->get('archive');
114 $isStarred = $request->request->get('starred');
c3235553 115
3107f92a
TC
116 $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($url, $this->getUser()->getId());
117
118 if (false === $entry) {
119 $entry = $this->get('wallabag_core.content_proxy')->updateEntry(
120 new Entry($this->getUser()),
121 $url
122 );
123 }
092ca707 124
51a15609
NL
125 if (!is_null($title)) {
126 $entry->setTitle($title);
127 }
128
0ca374e6
NL
129 $tags = $request->request->get('tags', '');
130 if (!empty($tags)) {
c2656f96 131 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
0ca374e6 132 }
092ca707 133
bc2b947c
TC
134 if (!is_null($isStarred)) {
135 $entry->setStarred((bool) $isStarred);
136 }
816ad405 137
bc2b947c
TC
138 if (!is_null($isArchived)) {
139 $entry->setArchived((bool) $isArchived);
140 }
816ad405 141
843dbe51
NL
142 $em = $this->getDoctrine()->getManager();
143 $em->persist($entry);
816ad405 144
843dbe51
NL
145 $em->flush();
146
aa4d6562
NL
147 $json = $this->get('serializer')->serialize($entry, 'json');
148
769e19dc 149 return $this->renderJsonResponse($json);
f8bf8952
NL
150 }
151
152 /**
4346a860 153 * Change several properties of an entry.
f8bf8952
NL
154 *
155 * @ApiDoc(
156 * requirements={
157 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
a8c90c5c
NL
158 * },
159 * parameters={
160 * {"name"="title", "dataType"="string", "required"=false},
161 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
189ef634
TC
162 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="archived the entry."},
163 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="starred the entry."},
1d147791 164 * }
f8bf8952 165 * )
4346a860 166 *
8eedc8cf 167 * @return Response
f8bf8952 168 */
be463487 169 public function patchEntriesAction(Entry $entry, Request $request)
f8bf8952 170 {
77273253 171 $this->validateAuthentication();
fcb1fba5 172 $this->validateUserAccess($entry->getUser()->getId());
092ca707 173
8ce32af6 174 $title = $request->request->get('title');
614a0bfd
YE
175 $isArchived = $request->request->get('archive');
176 $isStarred = $request->request->get('starred');
2c093b03
NL
177
178 if (!is_null($title)) {
179 $entry->setTitle($title);
180 }
181
182 if (!is_null($isArchived)) {
189ef634 183 $entry->setArchived((bool) $isArchived);
2c093b03
NL
184 }
185
2c093b03 186 if (!is_null($isStarred)) {
189ef634 187 $entry->setStarred((bool) $isStarred);
2c093b03
NL
188 }
189
0ca374e6
NL
190 $tags = $request->request->get('tags', '');
191 if (!empty($tags)) {
c2656f96 192 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
0ca374e6 193 }
092ca707 194
2c093b03 195 $em = $this->getDoctrine()->getManager();
2c093b03
NL
196 $em->flush();
197
0ca374e6
NL
198 $json = $this->get('serializer')->serialize($entry, 'json');
199
769e19dc 200 return $this->renderJsonResponse($json);
f8bf8952
NL
201 }
202
203 /**
4346a860 204 * Delete **permanently** an entry.
f8bf8952
NL
205 *
206 * @ApiDoc(
a8c90c5c
NL
207 * requirements={
208 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
209 * }
f8bf8952 210 * )
4346a860 211 *
8eedc8cf 212 * @return Response
f8bf8952 213 */
be463487 214 public function deleteEntriesAction(Entry $entry)
f8bf8952 215 {
77273253 216 $this->validateAuthentication();
fcb1fba5 217 $this->validateUserAccess($entry->getUser()->getId());
092ca707 218
42a90646 219 $em = $this->getDoctrine()->getManager();
1d147791 220 $em->remove($entry);
42a90646
NL
221 $em->flush();
222
1d147791
NL
223 $json = $this->get('serializer')->serialize($entry, 'json');
224
769e19dc 225 return $this->renderJsonResponse($json);
f8bf8952
NL
226 }
227
228 /**
4346a860 229 * Retrieve all tags for an entry.
f8bf8952
NL
230 *
231 * @ApiDoc(
232 * requirements={
233 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
234 * }
235 * )
8eedc8cf
JB
236 *
237 * @return Response
f8bf8952 238 */
be463487 239 public function getEntriesTagsAction(Entry $entry)
7df80cb3 240 {
77273253 241 $this->validateAuthentication();
fcb1fba5 242 $this->validateUserAccess($entry->getUser()->getId());
092ca707 243
1bd12b62 244 $json = $this->get('serializer')->serialize($entry->getTags(), 'json');
0a018fe0 245
769e19dc 246 return $this->renderJsonResponse($json);
f8bf8952
NL
247 }
248
249 /**
4346a860 250 * Add one or more tags to an entry.
f8bf8952
NL
251 *
252 * @ApiDoc(
253 * requirements={
254 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
a8c90c5c
NL
255 * },
256 * parameters={
257 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
258 * }
f8bf8952 259 * )
8eedc8cf
JB
260 *
261 * @return Response
f8bf8952 262 */
a36737f4 263 public function postEntriesTagsAction(Request $request, Entry $entry)
7df80cb3 264 {
77273253 265 $this->validateAuthentication();
fcb1fba5 266 $this->validateUserAccess($entry->getUser()->getId());
a36737f4 267
0ca374e6
NL
268 $tags = $request->request->get('tags', '');
269 if (!empty($tags)) {
c2656f96 270 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
0ca374e6 271 }
092ca707 272
a36737f4
NL
273 $em = $this->getDoctrine()->getManager();
274 $em->persist($entry);
275 $em->flush();
276
277 $json = $this->get('serializer')->serialize($entry, 'json');
278
769e19dc 279 return $this->renderJsonResponse($json);
f8bf8952
NL
280 }
281
282 /**
4346a860 283 * Permanently remove one tag for an entry.
f8bf8952
NL
284 *
285 * @ApiDoc(
286 * requirements={
769e19dc 287 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag ID"},
f8bf8952
NL
288 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
289 * }
290 * )
8eedc8cf
JB
291 *
292 * @return Response
f8bf8952 293 */
653e8be4 294 public function deleteEntriesTagsAction(Entry $entry, Tag $tag)
f8bf8952 295 {
77273253 296 $this->validateAuthentication();
fcb1fba5 297 $this->validateUserAccess($entry->getUser()->getId());
092ca707
NL
298
299 $entry->removeTag($tag);
300 $em = $this->getDoctrine()->getManager();
301 $em->persist($entry);
302 $em->flush();
303
304 $json = $this->get('serializer')->serialize($entry, 'json');
305
769e19dc 306 return $this->renderJsonResponse($json);
f8bf8952
NL
307 }
308
309 /**
4346a860 310 * Retrieve all tags.
f8bf8952 311 *
092ca707 312 * @ApiDoc()
8eedc8cf
JB
313 *
314 * @return Response
f8bf8952 315 */
092ca707 316 public function getTagsAction()
7df80cb3 317 {
77273253 318 $this->validateAuthentication();
fc732227
JB
319
320 $tags = $this->getDoctrine()
321 ->getRepository('WallabagCoreBundle:Tag')
322 ->findAllTags($this->getUser()->getId());
323
324 $json = $this->get('serializer')->serialize($tags, 'json');
092ca707 325
769e19dc 326 return $this->renderJsonResponse($json);
f8bf8952
NL
327 }
328
f8bf8952 329 /**
4346a860 330 * Permanently remove one tag from **every** entry.
f8bf8952
NL
331 *
332 * @ApiDoc(
333 * requirements={
769e19dc 334 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"}
f8bf8952
NL
335 * }
336 * )
8eedc8cf
JB
337 *
338 * @return Response
f8bf8952 339 */
653e8be4 340 public function deleteTagAction(Tag $tag)
f8bf8952 341 {
77273253 342 $this->validateAuthentication();
fc732227
JB
343
344 $this->getDoctrine()
345 ->getRepository('WallabagCoreBundle:Entry')
346 ->removeTag($this->getUser()->getId(), $tag);
092ca707 347
092ca707
NL
348 $json = $this->get('serializer')->serialize($tag, 'json');
349
769e19dc
J
350 return $this->renderJsonResponse($json);
351 }
2b477030 352 /**
6f8310b4
TC
353 * Retrieve version number.
354 *
355 * @ApiDoc()
2b477030
V
356 *
357 * @return Response
358 */
359 public function getVersionAction()
360 {
361 $version = $this->container->getParameter('wallabag_core.version');
362
363 $json = $this->get('serializer')->serialize($version, 'json');
364
365 return $this->renderJsonResponse($json);
366 }
769e19dc
J
367
368 /**
369 * Validate that the first id is equal to the second one.
4346a860 370 * If not, throw exception. It means a user try to access information from an other user.
769e19dc 371 *
4346a860 372 * @param int $requestUserId User id from the requested source
769e19dc 373 */
fcb1fba5 374 private function validateUserAccess($requestUserId)
769e19dc 375 {
18f8f32f 376 $user = $this->get('security.token_storage')->getToken()->getUser();
fcb1fba5
NL
377 if ($requestUserId != $user->getId()) {
378 throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$user->getId());
769e19dc
J
379 }
380 }
381
382 /**
383 * Send a JSON Response.
4346a860 384 * We don't use the Symfony JsonRespone, because it takes an array as parameter instead of a JSON string.
769e19dc
J
385 *
386 * @param string $json
387 *
388 * @return Response
389 */
390 private function renderJsonResponse($json)
391 {
4094ea47 392 return new Response($json, 200, ['application/json']);
f8bf8952 393 }
7df80cb3 394}