3 namespace Wallabag\ApiBundle\Controller
;
5 use FOS\RestBundle\Controller\FOSRestController
;
6 use Hateoas\Configuration\Route
as HateoasRoute
;
7 use Hateoas\Representation\Factory\PagerfantaFactory
;
8 use Nelmio\ApiDocBundle\Annotation\ApiDoc
;
9 use Symfony\Component\HttpFoundation\Request
;
10 use Symfony\Component\HttpFoundation\JsonResponse
;
11 use Symfony\Component\Routing\Generator\UrlGeneratorInterface
;
12 use Symfony\Component\Security\Core\Exception\AccessDeniedException
;
13 use Wallabag\CoreBundle\Entity\Entry
;
14 use Wallabag\CoreBundle\Entity\Tag
;
15 use FOS\RestBundle\Controller\Annotations\Route
;
17 class WallabagRestController
extends FOSRestController
19 private function validateAuthentication()
21 if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
22 throw new AccessDeniedException();
27 * Check if an entry exist by url.
31 * {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}
35 * @return JsonResponse
37 public function getEntriesExistsAction(Request
$request)
39 $this->validateAuthentication();
41 $url = $request->query
->get('url', '');
44 throw $this->createAccessDeniedException('URL is empty?, logged user id: '.$this->getUser()->getId());
47 $res = $this->getDoctrine()
48 ->getRepository('WallabagCoreBundle:Entry')
49 ->findByUrlAndUserId($url, $this->getUser()->getId());
51 $exists = false === $res ? false : true;
53 $json = $this->get('serializer')->serialize(['exists' => $exists], 'json');
55 return (new JsonResponse())->setJson($json);
59 * Retrieve all entries. It could be filtered by many options.
63 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."},
64 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."},
65 * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."},
66 * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."},
67 * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."},
68 * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."},
69 * {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."},
70 * {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."},
74 * @return JsonResponse
76 public function getEntriesAction(Request
$request)
78 $this->validateAuthentication();
80 $isArchived = (null === $request->query
->get('archive')) ? null : (bool) $request->query
->get('archive');
81 $isStarred = (null === $request->query
->get('starred')) ? null : (bool) $request->query
->get('starred');
82 $sort = $request->query
->get('sort', 'created');
83 $order = $request->query
->get('order', 'desc');
84 $page = (int) $request->query
->get('page', 1);
85 $perPage = (int) $request->query
->get('perPage', 30);
86 $tags = $request->query
->get('tags', '');
87 $since = $request->query
->get('since', 0);
89 $pager = $this->getDoctrine()
90 ->getRepository('WallabagCoreBundle:Entry')
91 ->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order, $since, $tags);
93 $pager->setCurrentPage($page);
94 $pager->setMaxPerPage($perPage);
96 $pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
97 $paginatedCollection = $pagerfantaFactory->createRepresentation(
102 'archive' => $isArchived,
103 'starred' => $isStarred,
107 'perPage' => $perPage,
111 UrlGeneratorInterface
::ABSOLUTE_URL
115 $json = $this->get('serializer')->serialize($paginatedCollection, 'json');
117 return (new JsonResponse())->setJson($json);
121 * Retrieve a single entry.
125 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
129 * @return JsonResponse
131 public function getEntryAction(Entry
$entry)
133 $this->validateAuthentication();
134 $this->validateUserAccess($entry->getUser()->getId());
136 $json = $this->get('serializer')->serialize($entry, 'json');
138 return (new JsonResponse())->setJson($json);
142 * Retrieve a single entry as a predefined format.
146 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
150 * @Route(requirements={"_format"="epub|mobi|pdf|txt|csv"})
154 public function getEntryExportAction(Entry
$entry, Request
$request)
156 $this->validateAuthentication();
157 $this->validateUserAccess($entry->getUser()->getId());
159 return $this->get('wallabag_core.helper.entries_export')
161 ->updateTitle('entry')
162 ->exportAs($request->attributes
->get('_format'));
170 * {"name"="url", "dataType"="string", "required"=true, "format"="http://www.test.com/article.html", "description"="Url for the entry."},
171 * {"name"="title", "dataType"="string", "required"=false, "description"="Optional, we'll get the title from the page."},
172 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
173 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already starred"},
174 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already archived"},
178 * @return JsonResponse
180 public function postEntriesAction(Request
$request)
182 $this->validateAuthentication();
184 $url = $request->request
->get('url');
185 $title = $request->request
->get('title');
186 $isArchived = $request->request
->get('archive');
187 $isStarred = $request->request
->get('starred');
189 $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($url, $this->getUser()->getId());
191 if (false === $entry) {
192 $entry = $this->get('wallabag_core.content_proxy')->updateEntry(
193 new Entry($this->getUser()),
198 if (!is_null($title)) {
199 $entry->setTitle($title);
202 $tags = $request->request
->get('tags', '');
204 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
207 if (!is_null($isStarred)) {
208 $entry->setStarred((bool) $isStarred);
211 if (!is_null($isArchived)) {
212 $entry->setArchived((bool) $isArchived);
215 $em = $this->getDoctrine()->getManager();
216 $em->persist($entry);
220 $json = $this->get('serializer')->serialize($entry, 'json');
222 return (new JsonResponse())->setJson($json);
226 * Change several properties of an entry.
230 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
233 * {"name"="title", "dataType"="string", "required"=false},
234 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
235 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="archived the entry."},
236 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="starred the entry."},
240 * @return JsonResponse
242 public function patchEntriesAction(Entry
$entry, Request
$request)
244 $this->validateAuthentication();
245 $this->validateUserAccess($entry->getUser()->getId());
247 $title = $request->request
->get('title');
248 $isArchived = $request->request
->get('archive');
249 $isStarred = $request->request
->get('starred');
251 if (!is_null($title)) {
252 $entry->setTitle($title);
255 if (!is_null($isArchived)) {
256 $entry->setArchived((bool) $isArchived);
259 if (!is_null($isStarred)) {
260 $entry->setStarred((bool) $isStarred);
263 $tags = $request->request
->get('tags', '');
265 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
268 $em = $this->getDoctrine()->getManager();
271 $json = $this->get('serializer')->serialize($entry, 'json');
273 return (new JsonResponse())->setJson($json);
277 * Delete **permanently** an entry.
281 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
285 * @return JsonResponse
287 public function deleteEntriesAction(Entry
$entry)
289 $this->validateAuthentication();
290 $this->validateUserAccess($entry->getUser()->getId());
292 $em = $this->getDoctrine()->getManager();
296 $json = $this->get('serializer')->serialize($entry, 'json');
298 return (new JsonResponse())->setJson($json);
302 * Retrieve all tags for an entry.
306 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
310 * @return JsonResponse
312 public function getEntriesTagsAction(Entry
$entry)
314 $this->validateAuthentication();
315 $this->validateUserAccess($entry->getUser()->getId());
317 $json = $this->get('serializer')->serialize($entry->getTags(), 'json');
319 return (new JsonResponse())->setJson($json);
323 * Add one or more tags to an entry.
327 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
330 * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."},
334 * @return JsonResponse
336 public function postEntriesTagsAction(Request
$request, Entry
$entry)
338 $this->validateAuthentication();
339 $this->validateUserAccess($entry->getUser()->getId());
341 $tags = $request->request
->get('tags', '');
343 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
346 $em = $this->getDoctrine()->getManager();
347 $em->persist($entry);
350 $json = $this->get('serializer')->serialize($entry, 'json');
352 return (new JsonResponse())->setJson($json);
356 * Permanently remove one tag for an entry.
360 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag ID"},
361 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
365 * @return JsonResponse
367 public function deleteEntriesTagsAction(Entry
$entry, Tag
$tag)
369 $this->validateAuthentication();
370 $this->validateUserAccess($entry->getUser()->getId());
372 $entry->removeTag($tag);
373 $em = $this->getDoctrine()->getManager();
374 $em->persist($entry);
377 $json = $this->get('serializer')->serialize($entry, 'json');
379 return (new JsonResponse())->setJson($json);
387 * @return JsonResponse
389 public function getTagsAction()
391 $this->validateAuthentication();
393 $tags = $this->getDoctrine()
394 ->getRepository('WallabagCoreBundle:Tag')
395 ->findAllTagsWithEntries($this->getUser()->getId());
397 $json = $this->get('serializer')->serialize($tags, 'json');
399 return (new JsonResponse())->setJson($json);
403 * Permanently remove one tag from **every** entry.
407 * {"name"="tag", "dataType"="string", "required"=true, "requirement"="\w+", "description"="Tag as a string"}
411 * @return JsonResponse
413 public function deleteTagLabelAction(Request
$request)
415 $this->validateAuthentication();
416 $label = $request->request
->get('tag', '');
418 $tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label);
421 throw $this->createNotFoundException('Tag not found');
425 ->getRepository('WallabagCoreBundle:Entry')
426 ->removeTag($this->getUser()->getId(), $tag);
428 $json = $this->get('serializer')->serialize($tag, 'json');
430 return (new JsonResponse())->setJson($json);
434 * Permanently remove some tags from **every** entry.
438 * {"name"="tags", "dataType"="string", "required"=true, "format"="tag1,tag2", "description"="Tags as strings (comma splitted)"}
442 * @return JsonResponse
444 public function deleteTagsLabelAction(Request
$request)
446 $this->validateAuthentication();
448 $tagsLabels = $request->request
->get('tags', '');
452 foreach (explode(',', $tagsLabels) as $tagLabel) {
453 $tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel);
455 if (!empty($tagEntity)) {
456 $tags[] = $tagEntity;
461 throw $this->createNotFoundException('Tags not found');
465 ->getRepository('WallabagCoreBundle:Entry')
466 ->removeTags($this->getUser()->getId(), $tags);
468 $json = $this->get('serializer')->serialize($tags, 'json');
470 return (new JsonResponse())->setJson($json);
474 * Permanently remove one tag from **every** entry.
478 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"}
482 * @return JsonResponse
484 public function deleteTagAction(Tag
$tag)
486 $this->validateAuthentication();
489 ->getRepository('WallabagCoreBundle:Entry')
490 ->removeTag($this->getUser()->getId(), $tag);
492 $json = $this->get('serializer')->serialize($tag, 'json');
494 return (new JsonResponse())->setJson($json);
498 * Retrieve version number.
502 * @return JsonResponse
504 public function getVersionAction()
506 $version = $this->container
->getParameter('wallabag_core.version');
508 $json = $this->get('serializer')->serialize($version, 'json');
510 return (new JsonResponse())->setJson($json);
514 * Validate that the first id is equal to the second one.
515 * If not, throw exception. It means a user try to access information from an other user.
517 * @param int $requestUserId User id from the requested source
519 private function validateUserAccess($requestUserId)
521 $user = $this->get('security.token_storage')->getToken()->getUser();
522 if ($requestUserId != $user->getId()) {
523 throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$user->getId());