]> git.immae.eu Git - github/wallabag/wallabag.git/blame - src/Wallabag/ApiBundle/Controller/WallabagRestController.php
API: getEntry can return EPUB
[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;
60faee00 10use Symfony\Component\HttpFoundation\JsonResponse;
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
6273fefd 25 /**
3583cadf 26 * Check if an entry exist by url.
6273fefd
JB
27 *
28 * @ApiDoc(
29 * parameters={
30 * {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}
31 * }
32 * )
33 *
34 * @return JsonResponse
35 */
36 public function getEntriesExistsAction(Request $request)
37 {
38 $this->validateAuthentication();
39
40 $url = $request->query->get('url', '');
41
42 if (empty($url)) {
0b174d69 43 throw $this->createAccessDeniedException('URL is empty?, logged user id: '.$this->getUser()->getId());
6273fefd
JB
44 }
45
46 $res = $this->getDoctrine()
47 ->getRepository('WallabagCoreBundle:Entry')
48 ->findByUrlAndUserId($url, $this->getUser()->getId());
49
50 $exists = false === $res ? false : true;
51
52 $json = $this->get('serializer')->serialize(['exists' => $exists], 'json');
53
54 return (new JsonResponse())->setJson($json);
55 }
56
f8bf8952 57 /**
a8c90c5c 58 * Retrieve all entries. It could be filtered by many options.
f8bf8952
NL
59 *
60 * @ApiDoc(
a8c90c5c 61 * parameters={
189ef634
TC
62 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."},
63 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."},
a8c90c5c
NL
64 * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."},
65 * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."},
66 * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."},
67 * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."},
189ef634 68 * {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."},
e5fb89e5 69 * {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."},
a8c90c5c 70 * }
f8bf8952 71 * )
4346a860 72 *
60faee00 73 * @return JsonResponse
f8bf8952 74 */
27f15aa4 75 public function getEntriesAction(Request $request)
f8bf8952 76 {
77273253
NL
77 $this->validateAuthentication();
78
0135c98b
NL
79 $isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive');
80 $isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred');
8ce32af6
JB
81 $sort = $request->query->get('sort', 'created');
82 $order = $request->query->get('order', 'desc');
83 $page = (int) $request->query->get('page', 1);
84 $perPage = (int) $request->query->get('perPage', 30);
28803f10 85 $tags = $request->query->get('tags', '');
c3f8b428 86 $since = $request->query->get('since', 0);
a8c90c5c 87
fc732227 88 $pager = $this->getDoctrine()
be463487 89 ->getRepository('WallabagCoreBundle:Entry')
28803f10 90 ->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order, $since, $tags);
a8c90c5c 91
6e22bd73
WD
92 $pager->setCurrentPage($page);
93 $pager->setMaxPerPage($perPage);
94
8ce32af6 95 $pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
6e22bd73
WD
96 $paginatedCollection = $pagerfantaFactory->createRepresentation(
97 $pager,
c3f8b428
JB
98 new Route(
99 'api_get_entries',
100 [
101 'archive' => $isArchived,
102 'starred' => $isStarred,
103 'sort' => $sort,
104 'order' => $order,
105 'page' => $page,
106 'perPage' => $perPage,
107 'tags' => $tags,
108 'since' => $since,
109 ],
110 UrlGeneratorInterface::ABSOLUTE_URL
111 )
6e22bd73
WD
112 );
113
114 $json = $this->get('serializer')->serialize($paginatedCollection, 'json');
0f006880 115
60faee00 116 return (new JsonResponse())->setJson($json);
f8bf8952
NL
117 }
118
119 /**
4346a860 120 * Retrieve a single entry.
f8bf8952
NL
121 *
122 * @ApiDoc(
123 * requirements={
124 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
125 * }
126 * )
4346a860 127 *
60faee00 128 * @return JsonResponse
f8bf8952 129 */
24de8665 130 public function getEntryAction(Entry $entry, $_format)
f8bf8952 131 {
77273253 132 $this->validateAuthentication();
fcb1fba5 133 $this->validateUserAccess($entry->getUser()->getId());
092ca707 134
24de8665
PM
135 if ($_format === 'epub') {
136 return $this->get('wallabag_core.helper.entries_export')
137 ->setEntries($entry)
138 ->updateTitle('entry')
139 ->exportAs($_format);
140 }
141
aa4d6562 142 $json = $this->get('serializer')->serialize($entry, 'json');
0f006880 143
60faee00 144 return (new JsonResponse())->setJson($json);
f8bf8952
NL
145 }
146
147 /**
4346a860 148 * Create an entry.
f8bf8952
NL
149 *
150 * @ApiDoc(
a8c90c5c
NL
151 * parameters={
152 * {"name"="url", "dataType"="string", "required"=true, "format"="http://www.test.com/article.html", "description"="Url for the entry."},
153 * {"name"="title", "dataType"="string", "required"=false, "description"="Optional, we'll get the title from the page."},
154 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
189ef634
TC
155 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already starred"},
156 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already archived"},
a8c90c5c 157 * }
f8bf8952 158 * )
4346a860 159 *
60faee00 160 * @return JsonResponse
f8bf8952 161 */
843dbe51 162 public function postEntriesAction(Request $request)
f8bf8952 163 {
77273253
NL
164 $this->validateAuthentication();
165
c3235553 166 $url = $request->request->get('url');
51a15609 167 $title = $request->request->get('title');
873e3806
YE
168 $isArchived = $request->request->get('archive');
169 $isStarred = $request->request->get('starred');
c3235553 170
3107f92a
TC
171 $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($url, $this->getUser()->getId());
172
173 if (false === $entry) {
174 $entry = $this->get('wallabag_core.content_proxy')->updateEntry(
175 new Entry($this->getUser()),
176 $url
177 );
178 }
092ca707 179
51a15609
NL
180 if (!is_null($title)) {
181 $entry->setTitle($title);
182 }
183
0ca374e6
NL
184 $tags = $request->request->get('tags', '');
185 if (!empty($tags)) {
c2656f96 186 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
0ca374e6 187 }
092ca707 188
bc2b947c
TC
189 if (!is_null($isStarred)) {
190 $entry->setStarred((bool) $isStarred);
191 }
816ad405 192
bc2b947c
TC
193 if (!is_null($isArchived)) {
194 $entry->setArchived((bool) $isArchived);
195 }
816ad405 196
843dbe51
NL
197 $em = $this->getDoctrine()->getManager();
198 $em->persist($entry);
816ad405 199
843dbe51
NL
200 $em->flush();
201
aa4d6562
NL
202 $json = $this->get('serializer')->serialize($entry, 'json');
203
60faee00 204 return (new JsonResponse())->setJson($json);
f8bf8952
NL
205 }
206
207 /**
4346a860 208 * Change several properties of an entry.
f8bf8952
NL
209 *
210 * @ApiDoc(
211 * requirements={
212 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
a8c90c5c
NL
213 * },
214 * parameters={
215 * {"name"="title", "dataType"="string", "required"=false},
216 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
189ef634
TC
217 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="archived the entry."},
218 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="starred the entry."},
1d147791 219 * }
f8bf8952 220 * )
4346a860 221 *
60faee00 222 * @return JsonResponse
f8bf8952 223 */
be463487 224 public function patchEntriesAction(Entry $entry, Request $request)
f8bf8952 225 {
77273253 226 $this->validateAuthentication();
fcb1fba5 227 $this->validateUserAccess($entry->getUser()->getId());
092ca707 228
8ce32af6 229 $title = $request->request->get('title');
614a0bfd
YE
230 $isArchived = $request->request->get('archive');
231 $isStarred = $request->request->get('starred');
2c093b03
NL
232
233 if (!is_null($title)) {
234 $entry->setTitle($title);
235 }
236
237 if (!is_null($isArchived)) {
189ef634 238 $entry->setArchived((bool) $isArchived);
2c093b03
NL
239 }
240
2c093b03 241 if (!is_null($isStarred)) {
189ef634 242 $entry->setStarred((bool) $isStarred);
2c093b03
NL
243 }
244
0ca374e6
NL
245 $tags = $request->request->get('tags', '');
246 if (!empty($tags)) {
c2656f96 247 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
0ca374e6 248 }
092ca707 249
2c093b03 250 $em = $this->getDoctrine()->getManager();
2c093b03
NL
251 $em->flush();
252
0ca374e6
NL
253 $json = $this->get('serializer')->serialize($entry, 'json');
254
60faee00 255 return (new JsonResponse())->setJson($json);
f8bf8952
NL
256 }
257
258 /**
4346a860 259 * Delete **permanently** an entry.
f8bf8952
NL
260 *
261 * @ApiDoc(
a8c90c5c
NL
262 * requirements={
263 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
264 * }
f8bf8952 265 * )
4346a860 266 *
60faee00 267 * @return JsonResponse
f8bf8952 268 */
be463487 269 public function deleteEntriesAction(Entry $entry)
f8bf8952 270 {
77273253 271 $this->validateAuthentication();
fcb1fba5 272 $this->validateUserAccess($entry->getUser()->getId());
092ca707 273
42a90646 274 $em = $this->getDoctrine()->getManager();
1d147791 275 $em->remove($entry);
42a90646
NL
276 $em->flush();
277
1d147791
NL
278 $json = $this->get('serializer')->serialize($entry, 'json');
279
60faee00 280 return (new JsonResponse())->setJson($json);
f8bf8952
NL
281 }
282
283 /**
4346a860 284 * Retrieve all tags for an entry.
f8bf8952
NL
285 *
286 * @ApiDoc(
287 * requirements={
288 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
289 * }
290 * )
8eedc8cf 291 *
60faee00 292 * @return JsonResponse
f8bf8952 293 */
be463487 294 public function getEntriesTagsAction(Entry $entry)
7df80cb3 295 {
77273253 296 $this->validateAuthentication();
fcb1fba5 297 $this->validateUserAccess($entry->getUser()->getId());
092ca707 298
1bd12b62 299 $json = $this->get('serializer')->serialize($entry->getTags(), 'json');
0a018fe0 300
60faee00 301 return (new JsonResponse())->setJson($json);
f8bf8952
NL
302 }
303
304 /**
4346a860 305 * Add one or more tags to an entry.
f8bf8952
NL
306 *
307 * @ApiDoc(
308 * requirements={
309 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
a8c90c5c
NL
310 * },
311 * parameters={
312 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
313 * }
f8bf8952 314 * )
8eedc8cf 315 *
60faee00 316 * @return JsonResponse
f8bf8952 317 */
a36737f4 318 public function postEntriesTagsAction(Request $request, Entry $entry)
7df80cb3 319 {
77273253 320 $this->validateAuthentication();
fcb1fba5 321 $this->validateUserAccess($entry->getUser()->getId());
a36737f4 322
0ca374e6
NL
323 $tags = $request->request->get('tags', '');
324 if (!empty($tags)) {
c2656f96 325 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
0ca374e6 326 }
092ca707 327
a36737f4
NL
328 $em = $this->getDoctrine()->getManager();
329 $em->persist($entry);
330 $em->flush();
331
332 $json = $this->get('serializer')->serialize($entry, 'json');
333
60faee00 334 return (new JsonResponse())->setJson($json);
f8bf8952
NL
335 }
336
337 /**
4346a860 338 * Permanently remove one tag for an entry.
f8bf8952
NL
339 *
340 * @ApiDoc(
341 * requirements={
769e19dc 342 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag ID"},
f8bf8952
NL
343 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
344 * }
345 * )
8eedc8cf 346 *
60faee00 347 * @return JsonResponse
f8bf8952 348 */
653e8be4 349 public function deleteEntriesTagsAction(Entry $entry, Tag $tag)
f8bf8952 350 {
77273253 351 $this->validateAuthentication();
fcb1fba5 352 $this->validateUserAccess($entry->getUser()->getId());
092ca707
NL
353
354 $entry->removeTag($tag);
355 $em = $this->getDoctrine()->getManager();
356 $em->persist($entry);
357 $em->flush();
358
359 $json = $this->get('serializer')->serialize($entry, 'json');
360
60faee00 361 return (new JsonResponse())->setJson($json);
f8bf8952
NL
362 }
363
364 /**
4346a860 365 * Retrieve all tags.
f8bf8952 366 *
092ca707 367 * @ApiDoc()
8eedc8cf 368 *
60faee00 369 * @return JsonResponse
f8bf8952 370 */
092ca707 371 public function getTagsAction()
7df80cb3 372 {
77273253 373 $this->validateAuthentication();
fc732227
JB
374
375 $tags = $this->getDoctrine()
376 ->getRepository('WallabagCoreBundle:Tag')
faa86e06 377 ->findAllTagsWithEntries($this->getUser()->getId());
fc732227
JB
378
379 $json = $this->get('serializer')->serialize($tags, 'json');
092ca707 380
60faee00 381 return (new JsonResponse())->setJson($json);
f8bf8952
NL
382 }
383
f8bf8952 384 /**
4346a860 385 * Permanently remove one tag from **every** entry.
f8bf8952
NL
386 *
387 * @ApiDoc(
388 * requirements={
a0e1eafc 389 * {"name"="tag", "dataType"="string", "required"=true, "requirement"="\w+", "description"="Tag as a string"}
f8bf8952
NL
390 * }
391 * )
8eedc8cf 392 *
60faee00 393 * @return JsonResponse
f8bf8952 394 */
a0e1eafc 395 public function deleteTagLabelAction(Request $request)
f8bf8952 396 {
77273253 397 $this->validateAuthentication();
a0e1eafc
JB
398 $label = $request->request->get('tag', '');
399
400 $tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label);
401
402 if (empty($tag)) {
403 throw $this->createNotFoundException('Tag not found');
404 }
fc732227
JB
405
406 $this->getDoctrine()
407 ->getRepository('WallabagCoreBundle:Entry')
408 ->removeTag($this->getUser()->getId(), $tag);
092ca707 409
092ca707
NL
410 $json = $this->get('serializer')->serialize($tag, 'json');
411
60faee00 412 return (new JsonResponse())->setJson($json);
769e19dc 413 }
4da01f49
TC
414
415 /**
a0e1eafc 416 * Permanently remove some tags from **every** entry.
4da01f49
TC
417 *
418 * @ApiDoc(
419 * requirements={
a0e1eafc 420 * {"name"="tags", "dataType"="string", "required"=true, "format"="tag1,tag2", "description"="Tags as strings (comma splitted)"}
4da01f49
TC
421 * }
422 * )
423 *
60faee00 424 * @return JsonResponse
4da01f49 425 */
a0e1eafc 426 public function deleteTagsLabelAction(Request $request)
4da01f49
TC
427 {
428 $this->validateAuthentication();
4da01f49 429
a0e1eafc
JB
430 $tagsLabels = $request->request->get('tags', '');
431
432 $tags = [];
433
434 foreach (explode(',', $tagsLabels) as $tagLabel) {
435 $tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel);
436
437 if (!empty($tagEntity)) {
438 $tags[] = $tagEntity;
439 }
440 }
441
442 if (empty($tags)) {
443 throw $this->createNotFoundException('Tags not found');
444 }
445
4da01f49
TC
446 $this->getDoctrine()
447 ->getRepository('WallabagCoreBundle:Entry')
a0e1eafc 448 ->removeTags($this->getUser()->getId(), $tags);
4da01f49 449
a0e1eafc 450 $json = $this->get('serializer')->serialize($tags, 'json');
4da01f49 451
60faee00 452 return (new JsonResponse())->setJson($json);
4da01f49
TC
453 }
454
455 /**
a0e1eafc 456 * Permanently remove one tag from **every** entry.
4da01f49
TC
457 *
458 * @ApiDoc(
459 * requirements={
a0e1eafc 460 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"}
4da01f49
TC
461 * }
462 * )
463 *
60faee00 464 * @return JsonResponse
4da01f49 465 */
a0e1eafc 466 public function deleteTagAction(Tag $tag)
4da01f49
TC
467 {
468 $this->validateAuthentication();
469
4da01f49
TC
470 $this->getDoctrine()
471 ->getRepository('WallabagCoreBundle:Entry')
a0e1eafc 472 ->removeTag($this->getUser()->getId(), $tag);
4da01f49 473
a0e1eafc 474 $json = $this->get('serializer')->serialize($tag, 'json');
4da01f49 475
60faee00 476 return (new JsonResponse())->setJson($json);
4da01f49
TC
477 }
478
2b477030 479 /**
6f8310b4
TC
480 * Retrieve version number.
481 *
482 * @ApiDoc()
2b477030 483 *
60faee00 484 * @return JsonResponse
2b477030
V
485 */
486 public function getVersionAction()
487 {
488 $version = $this->container->getParameter('wallabag_core.version');
489
490 $json = $this->get('serializer')->serialize($version, 'json');
491
60faee00 492 return (new JsonResponse())->setJson($json);
2b477030 493 }
769e19dc
J
494
495 /**
496 * Validate that the first id is equal to the second one.
4346a860 497 * If not, throw exception. It means a user try to access information from an other user.
769e19dc 498 *
4346a860 499 * @param int $requestUserId User id from the requested source
769e19dc 500 */
fcb1fba5 501 private function validateUserAccess($requestUserId)
769e19dc 502 {
18f8f32f 503 $user = $this->get('security.token_storage')->getToken()->getUser();
fcb1fba5
NL
504 if ($requestUserId != $user->getId()) {
505 throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$user->getId());
769e19dc
J
506 }
507 }
7df80cb3 508}