diff options
7 files changed, 1386 insertions, 1341 deletions
diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php new file mode 100644 index 00000000..24fa7b3b --- /dev/null +++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php | |||
@@ -0,0 +1,367 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Controller; | ||
4 | |||
5 | use Hateoas\Configuration\Route; | ||
6 | use Hateoas\Representation\Factory\PagerfantaFactory; | ||
7 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | ||
8 | use Symfony\Component\HttpFoundation\Request; | ||
9 | use Symfony\Component\HttpFoundation\JsonResponse; | ||
10 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | ||
11 | use Wallabag\CoreBundle\Entity\Entry; | ||
12 | use Wallabag\CoreBundle\Entity\Tag; | ||
13 | |||
14 | class EntryRestController extends WallabagRestController | ||
15 | { | ||
16 | /** | ||
17 | * Check if an entry exist by url. | ||
18 | * | ||
19 | * @ApiDoc( | ||
20 | * parameters={ | ||
21 | * {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}, | ||
22 | * {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="Urls (as an array) to check if it exists"} | ||
23 | * } | ||
24 | * ) | ||
25 | * | ||
26 | * @return JsonResponse | ||
27 | */ | ||
28 | public function getEntriesExistsAction(Request $request) | ||
29 | { | ||
30 | $this->validateAuthentication(); | ||
31 | |||
32 | $urls = $request->query->get('urls', []); | ||
33 | |||
34 | // handle multiple urls first | ||
35 | if (!empty($urls)) { | ||
36 | $results = []; | ||
37 | foreach ($urls as $url) { | ||
38 | $res = $this->getDoctrine() | ||
39 | ->getRepository('WallabagCoreBundle:Entry') | ||
40 | ->findByUrlAndUserId($url, $this->getUser()->getId()); | ||
41 | |||
42 | $results[$url] = false === $res ? false : true; | ||
43 | } | ||
44 | |||
45 | $json = $this->get('serializer')->serialize($results, 'json'); | ||
46 | |||
47 | return (new JsonResponse())->setJson($json); | ||
48 | } | ||
49 | |||
50 | // let's see if it is a simple url? | ||
51 | $url = $request->query->get('url', ''); | ||
52 | |||
53 | if (empty($url)) { | ||
54 | throw $this->createAccessDeniedException('URL is empty?, logged user id: '.$this->getUser()->getId()); | ||
55 | } | ||
56 | |||
57 | $res = $this->getDoctrine() | ||
58 | ->getRepository('WallabagCoreBundle:Entry') | ||
59 | ->findByUrlAndUserId($url, $this->getUser()->getId()); | ||
60 | |||
61 | $exists = false === $res ? false : true; | ||
62 | |||
63 | $json = $this->get('serializer')->serialize(['exists' => $exists], 'json'); | ||
64 | |||
65 | return (new JsonResponse())->setJson($json); | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * Retrieve all entries. It could be filtered by many options. | ||
70 | * | ||
71 | * @ApiDoc( | ||
72 | * parameters={ | ||
73 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."}, | ||
74 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."}, | ||
75 | * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."}, | ||
76 | * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."}, | ||
77 | * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."}, | ||
78 | * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."}, | ||
79 | * {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."}, | ||
80 | * {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."}, | ||
81 | * } | ||
82 | * ) | ||
83 | * | ||
84 | * @return JsonResponse | ||
85 | */ | ||
86 | public function getEntriesAction(Request $request) | ||
87 | { | ||
88 | $this->validateAuthentication(); | ||
89 | |||
90 | $isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive'); | ||
91 | $isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred'); | ||
92 | $sort = $request->query->get('sort', 'created'); | ||
93 | $order = $request->query->get('order', 'desc'); | ||
94 | $page = (int) $request->query->get('page', 1); | ||
95 | $perPage = (int) $request->query->get('perPage', 30); | ||
96 | $tags = $request->query->get('tags', ''); | ||
97 | $since = $request->query->get('since', 0); | ||
98 | |||
99 | $pager = $this->getDoctrine() | ||
100 | ->getRepository('WallabagCoreBundle:Entry') | ||
101 | ->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order, $since, $tags); | ||
102 | |||
103 | $pager->setCurrentPage($page); | ||
104 | $pager->setMaxPerPage($perPage); | ||
105 | |||
106 | $pagerfantaFactory = new PagerfantaFactory('page', 'perPage'); | ||
107 | $paginatedCollection = $pagerfantaFactory->createRepresentation( | ||
108 | $pager, | ||
109 | new Route( | ||
110 | 'api_get_entries', | ||
111 | [ | ||
112 | 'archive' => $isArchived, | ||
113 | 'starred' => $isStarred, | ||
114 | 'sort' => $sort, | ||
115 | 'order' => $order, | ||
116 | 'page' => $page, | ||
117 | 'perPage' => $perPage, | ||
118 | 'tags' => $tags, | ||
119 | 'since' => $since, | ||
120 | ], | ||
121 | UrlGeneratorInterface::ABSOLUTE_URL | ||
122 | ) | ||
123 | ); | ||
124 | |||
125 | $json = $this->get('serializer')->serialize($paginatedCollection, 'json'); | ||
126 | |||
127 | return (new JsonResponse())->setJson($json); | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * Retrieve a single entry. | ||
132 | * | ||
133 | * @ApiDoc( | ||
134 | * requirements={ | ||
135 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
136 | * } | ||
137 | * ) | ||
138 | * | ||
139 | * @return JsonResponse | ||
140 | */ | ||
141 | public function getEntryAction(Entry $entry) | ||
142 | { | ||
143 | $this->validateAuthentication(); | ||
144 | $this->validateUserAccess($entry->getUser()->getId()); | ||
145 | |||
146 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
147 | |||
148 | return (new JsonResponse())->setJson($json); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * Create an entry. | ||
153 | * | ||
154 | * @ApiDoc( | ||
155 | * parameters={ | ||
156 | * {"name"="url", "dataType"="string", "required"=true, "format"="http://www.test.com/article.html", "description"="Url for the entry."}, | ||
157 | * {"name"="title", "dataType"="string", "required"=false, "description"="Optional, we'll get the title from the page."}, | ||
158 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, | ||
159 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already starred"}, | ||
160 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already archived"}, | ||
161 | * } | ||
162 | * ) | ||
163 | * | ||
164 | * @return JsonResponse | ||
165 | */ | ||
166 | public function postEntriesAction(Request $request) | ||
167 | { | ||
168 | $this->validateAuthentication(); | ||
169 | |||
170 | $url = $request->request->get('url'); | ||
171 | $title = $request->request->get('title'); | ||
172 | $isArchived = $request->request->get('archive'); | ||
173 | $isStarred = $request->request->get('starred'); | ||
174 | |||
175 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($url, $this->getUser()->getId()); | ||
176 | |||
177 | if (false === $entry) { | ||
178 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry( | ||
179 | new Entry($this->getUser()), | ||
180 | $url | ||
181 | ); | ||
182 | } | ||
183 | |||
184 | if (!is_null($title)) { | ||
185 | $entry->setTitle($title); | ||
186 | } | ||
187 | |||
188 | $tags = $request->request->get('tags', ''); | ||
189 | if (!empty($tags)) { | ||
190 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); | ||
191 | } | ||
192 | |||
193 | if (!is_null($isStarred)) { | ||
194 | $entry->setStarred((bool) $isStarred); | ||
195 | } | ||
196 | |||
197 | if (!is_null($isArchived)) { | ||
198 | $entry->setArchived((bool) $isArchived); | ||
199 | } | ||
200 | |||
201 | $em = $this->getDoctrine()->getManager(); | ||
202 | $em->persist($entry); | ||
203 | |||
204 | $em->flush(); | ||
205 | |||
206 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
207 | |||
208 | return (new JsonResponse())->setJson($json); | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * Change several properties of an entry. | ||
213 | * | ||
214 | * @ApiDoc( | ||
215 | * requirements={ | ||
216 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
217 | * }, | ||
218 | * parameters={ | ||
219 | * {"name"="title", "dataType"="string", "required"=false}, | ||
220 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, | ||
221 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="archived the entry."}, | ||
222 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="starred the entry."}, | ||
223 | * } | ||
224 | * ) | ||
225 | * | ||
226 | * @return JsonResponse | ||
227 | */ | ||
228 | public function patchEntriesAction(Entry $entry, Request $request) | ||
229 | { | ||
230 | $this->validateAuthentication(); | ||
231 | $this->validateUserAccess($entry->getUser()->getId()); | ||
232 | |||
233 | $title = $request->request->get('title'); | ||
234 | $isArchived = $request->request->get('archive'); | ||
235 | $isStarred = $request->request->get('starred'); | ||
236 | |||
237 | if (!is_null($title)) { | ||
238 | $entry->setTitle($title); | ||
239 | } | ||
240 | |||
241 | if (!is_null($isArchived)) { | ||
242 | $entry->setArchived((bool) $isArchived); | ||
243 | } | ||
244 | |||
245 | if (!is_null($isStarred)) { | ||
246 | $entry->setStarred((bool) $isStarred); | ||
247 | } | ||
248 | |||
249 | $tags = $request->request->get('tags', ''); | ||
250 | if (!empty($tags)) { | ||
251 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); | ||
252 | } | ||
253 | |||
254 | $em = $this->getDoctrine()->getManager(); | ||
255 | $em->flush(); | ||
256 | |||
257 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
258 | |||
259 | return (new JsonResponse())->setJson($json); | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * Delete **permanently** an entry. | ||
264 | * | ||
265 | * @ApiDoc( | ||
266 | * requirements={ | ||
267 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
268 | * } | ||
269 | * ) | ||
270 | * | ||
271 | * @return JsonResponse | ||
272 | */ | ||
273 | public function deleteEntriesAction(Entry $entry) | ||
274 | { | ||
275 | $this->validateAuthentication(); | ||
276 | $this->validateUserAccess($entry->getUser()->getId()); | ||
277 | |||
278 | $em = $this->getDoctrine()->getManager(); | ||
279 | $em->remove($entry); | ||
280 | $em->flush(); | ||
281 | |||
282 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
283 | |||
284 | return (new JsonResponse())->setJson($json); | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * Retrieve all tags for an entry. | ||
289 | * | ||
290 | * @ApiDoc( | ||
291 | * requirements={ | ||
292 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
293 | * } | ||
294 | * ) | ||
295 | * | ||
296 | * @return JsonResponse | ||
297 | */ | ||
298 | public function getEntriesTagsAction(Entry $entry) | ||
299 | { | ||
300 | $this->validateAuthentication(); | ||
301 | $this->validateUserAccess($entry->getUser()->getId()); | ||
302 | |||
303 | $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); | ||
304 | |||
305 | return (new JsonResponse())->setJson($json); | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * Add one or more tags to an entry. | ||
310 | * | ||
311 | * @ApiDoc( | ||
312 | * requirements={ | ||
313 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
314 | * }, | ||
315 | * parameters={ | ||
316 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, | ||
317 | * } | ||
318 | * ) | ||
319 | * | ||
320 | * @return JsonResponse | ||
321 | */ | ||
322 | public function postEntriesTagsAction(Request $request, Entry $entry) | ||
323 | { | ||
324 | $this->validateAuthentication(); | ||
325 | $this->validateUserAccess($entry->getUser()->getId()); | ||
326 | |||
327 | $tags = $request->request->get('tags', ''); | ||
328 | if (!empty($tags)) { | ||
329 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); | ||
330 | } | ||
331 | |||
332 | $em = $this->getDoctrine()->getManager(); | ||
333 | $em->persist($entry); | ||
334 | $em->flush(); | ||
335 | |||
336 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
337 | |||
338 | return (new JsonResponse())->setJson($json); | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * Permanently remove one tag for an entry. | ||
343 | * | ||
344 | * @ApiDoc( | ||
345 | * requirements={ | ||
346 | * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag ID"}, | ||
347 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
348 | * } | ||
349 | * ) | ||
350 | * | ||
351 | * @return JsonResponse | ||
352 | */ | ||
353 | public function deleteEntriesTagsAction(Entry $entry, Tag $tag) | ||
354 | { | ||
355 | $this->validateAuthentication(); | ||
356 | $this->validateUserAccess($entry->getUser()->getId()); | ||
357 | |||
358 | $entry->removeTag($tag); | ||
359 | $em = $this->getDoctrine()->getManager(); | ||
360 | $em->persist($entry); | ||
361 | $em->flush(); | ||
362 | |||
363 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
364 | |||
365 | return (new JsonResponse())->setJson($json); | ||
366 | } | ||
367 | } | ||
diff --git a/src/Wallabag/ApiBundle/Controller/TagRestController.php b/src/Wallabag/ApiBundle/Controller/TagRestController.php new file mode 100644 index 00000000..4e7ddc66 --- /dev/null +++ b/src/Wallabag/ApiBundle/Controller/TagRestController.php | |||
@@ -0,0 +1,171 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Controller; | ||
4 | |||
5 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | ||
6 | use Symfony\Component\HttpFoundation\Request; | ||
7 | use Symfony\Component\HttpFoundation\JsonResponse; | ||
8 | use Wallabag\CoreBundle\Entity\Entry; | ||
9 | use Wallabag\CoreBundle\Entity\Tag; | ||
10 | |||
11 | class TagRestController extends WallabagRestController | ||
12 | { | ||
13 | /** | ||
14 | * Retrieve all tags. | ||
15 | * | ||
16 | * @ApiDoc() | ||
17 | * | ||
18 | * @return JsonResponse | ||
19 | */ | ||
20 | public function getTagsAction() | ||
21 | { | ||
22 | $this->validateAuthentication(); | ||
23 | |||
24 | $tags = $this->getDoctrine() | ||
25 | ->getRepository('WallabagCoreBundle:Tag') | ||
26 | ->findAllTags($this->getUser()->getId()); | ||
27 | |||
28 | $json = $this->get('serializer')->serialize($tags, 'json'); | ||
29 | |||
30 | return (new JsonResponse())->setJson($json); | ||
31 | } | ||
32 | |||
33 | /** | ||
34 | * Permanently remove one tag from **every** entry. | ||
35 | * | ||
36 | * @ApiDoc( | ||
37 | * requirements={ | ||
38 | * {"name"="tag", "dataType"="string", "required"=true, "requirement"="\w+", "description"="Tag as a string"} | ||
39 | * } | ||
40 | * ) | ||
41 | * | ||
42 | * @return JsonResponse | ||
43 | */ | ||
44 | public function deleteTagLabelAction(Request $request) | ||
45 | { | ||
46 | $this->validateAuthentication(); | ||
47 | $label = $request->request->get('tag', ''); | ||
48 | |||
49 | $tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label); | ||
50 | |||
51 | if (empty($tag)) { | ||
52 | throw $this->createNotFoundException('Tag not found'); | ||
53 | } | ||
54 | |||
55 | $this->getDoctrine() | ||
56 | ->getRepository('WallabagCoreBundle:Entry') | ||
57 | ->removeTag($this->getUser()->getId(), $tag); | ||
58 | |||
59 | $this->cleanOrphanTag($tag); | ||
60 | |||
61 | $json = $this->get('serializer')->serialize($tag, 'json'); | ||
62 | |||
63 | return (new JsonResponse())->setJson($json); | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Permanently remove some tags from **every** entry. | ||
68 | * | ||
69 | * @ApiDoc( | ||
70 | * requirements={ | ||
71 | * {"name"="tags", "dataType"="string", "required"=true, "format"="tag1,tag2", "description"="Tags as strings (comma splitted)"} | ||
72 | * } | ||
73 | * ) | ||
74 | * | ||
75 | * @return JsonResponse | ||
76 | */ | ||
77 | public function deleteTagsLabelAction(Request $request) | ||
78 | { | ||
79 | $this->validateAuthentication(); | ||
80 | |||
81 | $tagsLabels = $request->request->get('tags', ''); | ||
82 | |||
83 | $tags = []; | ||
84 | |||
85 | foreach (explode(',', $tagsLabels) as $tagLabel) { | ||
86 | $tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel); | ||
87 | |||
88 | if (!empty($tagEntity)) { | ||
89 | $tags[] = $tagEntity; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (empty($tags)) { | ||
94 | throw $this->createNotFoundException('Tags not found'); | ||
95 | } | ||
96 | |||
97 | $this->getDoctrine() | ||
98 | ->getRepository('WallabagCoreBundle:Entry') | ||
99 | ->removeTags($this->getUser()->getId(), $tags); | ||
100 | |||
101 | $this->cleanOrphanTag($tags); | ||
102 | |||
103 | $json = $this->get('serializer')->serialize($tags, 'json'); | ||
104 | |||
105 | return (new JsonResponse())->setJson($json); | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * Permanently remove one tag from **every** entry. | ||
110 | * | ||
111 | * @ApiDoc( | ||
112 | * requirements={ | ||
113 | * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"} | ||
114 | * } | ||
115 | * ) | ||
116 | * | ||
117 | * @return JsonResponse | ||
118 | */ | ||
119 | public function deleteTagAction(Tag $tag) | ||
120 | { | ||
121 | $this->validateAuthentication(); | ||
122 | |||
123 | $this->getDoctrine() | ||
124 | ->getRepository('WallabagCoreBundle:Entry') | ||
125 | ->removeTag($this->getUser()->getId(), $tag); | ||
126 | |||
127 | $this->cleanOrphanTag($tag); | ||
128 | |||
129 | $json = $this->get('serializer')->serialize($tag, 'json'); | ||
130 | |||
131 | return (new JsonResponse())->setJson($json); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * Retrieve version number. | ||
136 | * | ||
137 | * @ApiDoc() | ||
138 | * | ||
139 | * @return JsonResponse | ||
140 | */ | ||
141 | public function getVersionAction() | ||
142 | { | ||
143 | $version = $this->container->getParameter('wallabag_core.version'); | ||
144 | |||
145 | $json = $this->get('serializer')->serialize($version, 'json'); | ||
146 | |||
147 | return (new JsonResponse())->setJson($json); | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Remove orphan tag in case no entries are associated to it. | ||
152 | * | ||
153 | * @param Tag|array $tags | ||
154 | */ | ||
155 | private function cleanOrphanTag($tags) | ||
156 | { | ||
157 | if (!is_array($tags)) { | ||
158 | $tags = [$tags]; | ||
159 | } | ||
160 | |||
161 | $em = $this->getDoctrine()->getManager(); | ||
162 | |||
163 | foreach ($tags as $tag) { | ||
164 | if (count($tag->getEntries()) === 0) { | ||
165 | $em->remove($tag); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | $em->flush(); | ||
170 | } | ||
171 | } | ||
diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php index 9997913d..e927a890 100644 --- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php | |||
@@ -3,19 +3,12 @@ | |||
3 | namespace Wallabag\ApiBundle\Controller; | 3 | namespace Wallabag\ApiBundle\Controller; |
4 | 4 | ||
5 | use FOS\RestBundle\Controller\FOSRestController; | 5 | use FOS\RestBundle\Controller\FOSRestController; |
6 | use Hateoas\Configuration\Route; | ||
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; | 6 | use Symfony\Component\Security\Core\Exception\AccessDeniedException; |
13 | use Wallabag\CoreBundle\Entity\Entry; | 7 | use Wallabag\CoreBundle\Entity\Entry; |
14 | use Wallabag\CoreBundle\Entity\Tag; | ||
15 | 8 | ||
16 | class WallabagRestController extends FOSRestController | 9 | class WallabagRestController extends FOSRestController |
17 | { | 10 | { |
18 | private function validateAuthentication() | 11 | protected function validateAuthentication() |
19 | { | 12 | { |
20 | if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { | 13 | if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { |
21 | throw new AccessDeniedException(); | 14 | throw new AccessDeniedException(); |
@@ -23,523 +16,12 @@ class WallabagRestController extends FOSRestController | |||
23 | } | 16 | } |
24 | 17 | ||
25 | /** | 18 | /** |
26 | * Check if an entry exist by url. | ||
27 | * | ||
28 | * @ApiDoc( | ||
29 | * parameters={ | ||
30 | * {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}, | ||
31 | * {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="Urls (as an array) to check if it exists"} | ||
32 | * } | ||
33 | * ) | ||
34 | * | ||
35 | * @return JsonResponse | ||
36 | */ | ||
37 | public function getEntriesExistsAction(Request $request) | ||
38 | { | ||
39 | $this->validateAuthentication(); | ||
40 | |||
41 | $urls = $request->query->get('urls', []); | ||
42 | |||
43 | // handle multiple urls first | ||
44 | if (!empty($urls)) { | ||
45 | $results = []; | ||
46 | foreach ($urls as $url) { | ||
47 | $res = $this->getDoctrine() | ||
48 | ->getRepository('WallabagCoreBundle:Entry') | ||
49 | ->findByUrlAndUserId($url, $this->getUser()->getId()); | ||
50 | |||
51 | $results[$url] = false === $res ? false : true; | ||
52 | } | ||
53 | |||
54 | $json = $this->get('serializer')->serialize($results, 'json'); | ||
55 | |||
56 | return (new JsonResponse())->setJson($json); | ||
57 | } | ||
58 | |||
59 | // let's see if it is a simple url? | ||
60 | $url = $request->query->get('url', ''); | ||
61 | |||
62 | if (empty($url)) { | ||
63 | throw $this->createAccessDeniedException('URL is empty?, logged user id: '.$this->getUser()->getId()); | ||
64 | } | ||
65 | |||
66 | $res = $this->getDoctrine() | ||
67 | ->getRepository('WallabagCoreBundle:Entry') | ||
68 | ->findByUrlAndUserId($url, $this->getUser()->getId()); | ||
69 | |||
70 | $exists = false === $res ? false : true; | ||
71 | |||
72 | $json = $this->get('serializer')->serialize(['exists' => $exists], 'json'); | ||
73 | |||
74 | return (new JsonResponse())->setJson($json); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Retrieve all entries. It could be filtered by many options. | ||
79 | * | ||
80 | * @ApiDoc( | ||
81 | * parameters={ | ||
82 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."}, | ||
83 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."}, | ||
84 | * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."}, | ||
85 | * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."}, | ||
86 | * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."}, | ||
87 | * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."}, | ||
88 | * {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."}, | ||
89 | * {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."}, | ||
90 | * } | ||
91 | * ) | ||
92 | * | ||
93 | * @return JsonResponse | ||
94 | */ | ||
95 | public function getEntriesAction(Request $request) | ||
96 | { | ||
97 | $this->validateAuthentication(); | ||
98 | |||
99 | $isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive'); | ||
100 | $isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred'); | ||
101 | $sort = $request->query->get('sort', 'created'); | ||
102 | $order = $request->query->get('order', 'desc'); | ||
103 | $page = (int) $request->query->get('page', 1); | ||
104 | $perPage = (int) $request->query->get('perPage', 30); | ||
105 | $tags = $request->query->get('tags', ''); | ||
106 | $since = $request->query->get('since', 0); | ||
107 | |||
108 | $pager = $this->getDoctrine() | ||
109 | ->getRepository('WallabagCoreBundle:Entry') | ||
110 | ->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order, $since, $tags); | ||
111 | |||
112 | $pager->setCurrentPage($page); | ||
113 | $pager->setMaxPerPage($perPage); | ||
114 | |||
115 | $pagerfantaFactory = new PagerfantaFactory('page', 'perPage'); | ||
116 | $paginatedCollection = $pagerfantaFactory->createRepresentation( | ||
117 | $pager, | ||
118 | new Route( | ||
119 | 'api_get_entries', | ||
120 | [ | ||
121 | 'archive' => $isArchived, | ||
122 | 'starred' => $isStarred, | ||
123 | 'sort' => $sort, | ||
124 | 'order' => $order, | ||
125 | 'page' => $page, | ||
126 | 'perPage' => $perPage, | ||
127 | 'tags' => $tags, | ||
128 | 'since' => $since, | ||
129 | ], | ||
130 | UrlGeneratorInterface::ABSOLUTE_URL | ||
131 | ) | ||
132 | ); | ||
133 | |||
134 | $json = $this->get('serializer')->serialize($paginatedCollection, 'json'); | ||
135 | |||
136 | return (new JsonResponse())->setJson($json); | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * Retrieve a single entry. | ||
141 | * | ||
142 | * @ApiDoc( | ||
143 | * requirements={ | ||
144 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
145 | * } | ||
146 | * ) | ||
147 | * | ||
148 | * @return JsonResponse | ||
149 | */ | ||
150 | public function getEntryAction(Entry $entry) | ||
151 | { | ||
152 | $this->validateAuthentication(); | ||
153 | $this->validateUserAccess($entry->getUser()->getId()); | ||
154 | |||
155 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
156 | |||
157 | return (new JsonResponse())->setJson($json); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * Create an entry. | ||
162 | * | ||
163 | * @ApiDoc( | ||
164 | * parameters={ | ||
165 | * {"name"="url", "dataType"="string", "required"=true, "format"="http://www.test.com/article.html", "description"="Url for the entry."}, | ||
166 | * {"name"="title", "dataType"="string", "required"=false, "description"="Optional, we'll get the title from the page."}, | ||
167 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, | ||
168 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already starred"}, | ||
169 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already archived"}, | ||
170 | * } | ||
171 | * ) | ||
172 | * | ||
173 | * @return JsonResponse | ||
174 | */ | ||
175 | public function postEntriesAction(Request $request) | ||
176 | { | ||
177 | $this->validateAuthentication(); | ||
178 | |||
179 | $url = $request->request->get('url'); | ||
180 | $title = $request->request->get('title'); | ||
181 | $isArchived = $request->request->get('archive'); | ||
182 | $isStarred = $request->request->get('starred'); | ||
183 | |||
184 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($url, $this->getUser()->getId()); | ||
185 | |||
186 | if (false === $entry) { | ||
187 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry( | ||
188 | new Entry($this->getUser()), | ||
189 | $url | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | if (!is_null($title)) { | ||
194 | $entry->setTitle($title); | ||
195 | } | ||
196 | |||
197 | $tags = $request->request->get('tags', ''); | ||
198 | if (!empty($tags)) { | ||
199 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); | ||
200 | } | ||
201 | |||
202 | if (!is_null($isStarred)) { | ||
203 | $entry->setStarred((bool) $isStarred); | ||
204 | } | ||
205 | |||
206 | if (!is_null($isArchived)) { | ||
207 | $entry->setArchived((bool) $isArchived); | ||
208 | } | ||
209 | |||
210 | $em = $this->getDoctrine()->getManager(); | ||
211 | $em->persist($entry); | ||
212 | |||
213 | $em->flush(); | ||
214 | |||
215 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
216 | |||
217 | return (new JsonResponse())->setJson($json); | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * Change several properties of an entry. | ||
222 | * | ||
223 | * @ApiDoc( | ||
224 | * requirements={ | ||
225 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
226 | * }, | ||
227 | * parameters={ | ||
228 | * {"name"="title", "dataType"="string", "required"=false}, | ||
229 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, | ||
230 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="archived the entry."}, | ||
231 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="starred the entry."}, | ||
232 | * } | ||
233 | * ) | ||
234 | * | ||
235 | * @return JsonResponse | ||
236 | */ | ||
237 | public function patchEntriesAction(Entry $entry, Request $request) | ||
238 | { | ||
239 | $this->validateAuthentication(); | ||
240 | $this->validateUserAccess($entry->getUser()->getId()); | ||
241 | |||
242 | $title = $request->request->get('title'); | ||
243 | $isArchived = $request->request->get('archive'); | ||
244 | $isStarred = $request->request->get('starred'); | ||
245 | |||
246 | if (!is_null($title)) { | ||
247 | $entry->setTitle($title); | ||
248 | } | ||
249 | |||
250 | if (!is_null($isArchived)) { | ||
251 | $entry->setArchived((bool) $isArchived); | ||
252 | } | ||
253 | |||
254 | if (!is_null($isStarred)) { | ||
255 | $entry->setStarred((bool) $isStarred); | ||
256 | } | ||
257 | |||
258 | $tags = $request->request->get('tags', ''); | ||
259 | if (!empty($tags)) { | ||
260 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); | ||
261 | } | ||
262 | |||
263 | $em = $this->getDoctrine()->getManager(); | ||
264 | $em->flush(); | ||
265 | |||
266 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
267 | |||
268 | return (new JsonResponse())->setJson($json); | ||
269 | } | ||
270 | |||
271 | /** | ||
272 | * Delete **permanently** an entry. | ||
273 | * | ||
274 | * @ApiDoc( | ||
275 | * requirements={ | ||
276 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
277 | * } | ||
278 | * ) | ||
279 | * | ||
280 | * @return JsonResponse | ||
281 | */ | ||
282 | public function deleteEntriesAction(Entry $entry) | ||
283 | { | ||
284 | $this->validateAuthentication(); | ||
285 | $this->validateUserAccess($entry->getUser()->getId()); | ||
286 | |||
287 | $em = $this->getDoctrine()->getManager(); | ||
288 | $em->remove($entry); | ||
289 | $em->flush(); | ||
290 | |||
291 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
292 | |||
293 | return (new JsonResponse())->setJson($json); | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * Retrieve all tags for an entry. | ||
298 | * | ||
299 | * @ApiDoc( | ||
300 | * requirements={ | ||
301 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
302 | * } | ||
303 | * ) | ||
304 | * | ||
305 | * @return JsonResponse | ||
306 | */ | ||
307 | public function getEntriesTagsAction(Entry $entry) | ||
308 | { | ||
309 | $this->validateAuthentication(); | ||
310 | $this->validateUserAccess($entry->getUser()->getId()); | ||
311 | |||
312 | $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); | ||
313 | |||
314 | return (new JsonResponse())->setJson($json); | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * Add one or more tags to an entry. | ||
319 | * | ||
320 | * @ApiDoc( | ||
321 | * requirements={ | ||
322 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
323 | * }, | ||
324 | * parameters={ | ||
325 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, | ||
326 | * } | ||
327 | * ) | ||
328 | * | ||
329 | * @return JsonResponse | ||
330 | */ | ||
331 | public function postEntriesTagsAction(Request $request, Entry $entry) | ||
332 | { | ||
333 | $this->validateAuthentication(); | ||
334 | $this->validateUserAccess($entry->getUser()->getId()); | ||
335 | |||
336 | $tags = $request->request->get('tags', ''); | ||
337 | if (!empty($tags)) { | ||
338 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); | ||
339 | } | ||
340 | |||
341 | $em = $this->getDoctrine()->getManager(); | ||
342 | $em->persist($entry); | ||
343 | $em->flush(); | ||
344 | |||
345 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
346 | |||
347 | return (new JsonResponse())->setJson($json); | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * Permanently remove one tag for an entry. | ||
352 | * | ||
353 | * @ApiDoc( | ||
354 | * requirements={ | ||
355 | * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag ID"}, | ||
356 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | ||
357 | * } | ||
358 | * ) | ||
359 | * | ||
360 | * @return JsonResponse | ||
361 | */ | ||
362 | public function deleteEntriesTagsAction(Entry $entry, Tag $tag) | ||
363 | { | ||
364 | $this->validateAuthentication(); | ||
365 | $this->validateUserAccess($entry->getUser()->getId()); | ||
366 | |||
367 | $entry->removeTag($tag); | ||
368 | $em = $this->getDoctrine()->getManager(); | ||
369 | $em->persist($entry); | ||
370 | $em->flush(); | ||
371 | |||
372 | $json = $this->get('serializer')->serialize($entry, 'json'); | ||
373 | |||
374 | return (new JsonResponse())->setJson($json); | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * Retrieve all tags. | ||
379 | * | ||
380 | * @ApiDoc() | ||
381 | * | ||
382 | * @return JsonResponse | ||
383 | */ | ||
384 | public function getTagsAction() | ||
385 | { | ||
386 | $this->validateAuthentication(); | ||
387 | |||
388 | $tags = $this->getDoctrine() | ||
389 | ->getRepository('WallabagCoreBundle:Tag') | ||
390 | ->findAllTags($this->getUser()->getId()); | ||
391 | |||
392 | $json = $this->get('serializer')->serialize($tags, 'json'); | ||
393 | |||
394 | return (new JsonResponse())->setJson($json); | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * Permanently remove one tag from **every** entry. | ||
399 | * | ||
400 | * @ApiDoc( | ||
401 | * requirements={ | ||
402 | * {"name"="tag", "dataType"="string", "required"=true, "requirement"="\w+", "description"="Tag as a string"} | ||
403 | * } | ||
404 | * ) | ||
405 | * | ||
406 | * @return JsonResponse | ||
407 | */ | ||
408 | public function deleteTagLabelAction(Request $request) | ||
409 | { | ||
410 | $this->validateAuthentication(); | ||
411 | $label = $request->request->get('tag', ''); | ||
412 | |||
413 | $tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label); | ||
414 | |||
415 | if (empty($tag)) { | ||
416 | throw $this->createNotFoundException('Tag not found'); | ||
417 | } | ||
418 | |||
419 | $this->getDoctrine() | ||
420 | ->getRepository('WallabagCoreBundle:Entry') | ||
421 | ->removeTag($this->getUser()->getId(), $tag); | ||
422 | |||
423 | $this->cleanOrphanTag($tag); | ||
424 | |||
425 | $json = $this->get('serializer')->serialize($tag, 'json'); | ||
426 | |||
427 | return (new JsonResponse())->setJson($json); | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * Permanently remove some tags from **every** entry. | ||
432 | * | ||
433 | * @ApiDoc( | ||
434 | * requirements={ | ||
435 | * {"name"="tags", "dataType"="string", "required"=true, "format"="tag1,tag2", "description"="Tags as strings (comma splitted)"} | ||
436 | * } | ||
437 | * ) | ||
438 | * | ||
439 | * @return JsonResponse | ||
440 | */ | ||
441 | public function deleteTagsLabelAction(Request $request) | ||
442 | { | ||
443 | $this->validateAuthentication(); | ||
444 | |||
445 | $tagsLabels = $request->request->get('tags', ''); | ||
446 | |||
447 | $tags = []; | ||
448 | |||
449 | foreach (explode(',', $tagsLabels) as $tagLabel) { | ||
450 | $tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel); | ||
451 | |||
452 | if (!empty($tagEntity)) { | ||
453 | $tags[] = $tagEntity; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | if (empty($tags)) { | ||
458 | throw $this->createNotFoundException('Tags not found'); | ||
459 | } | ||
460 | |||
461 | $this->getDoctrine() | ||
462 | ->getRepository('WallabagCoreBundle:Entry') | ||
463 | ->removeTags($this->getUser()->getId(), $tags); | ||
464 | |||
465 | $this->cleanOrphanTag($tags); | ||
466 | |||
467 | $json = $this->get('serializer')->serialize($tags, 'json'); | ||
468 | |||
469 | return (new JsonResponse())->setJson($json); | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * Permanently remove one tag from **every** entry. | ||
474 | * | ||
475 | * @ApiDoc( | ||
476 | * requirements={ | ||
477 | * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"} | ||
478 | * } | ||
479 | * ) | ||
480 | * | ||
481 | * @return JsonResponse | ||
482 | */ | ||
483 | public function deleteTagAction(Tag $tag) | ||
484 | { | ||
485 | $this->validateAuthentication(); | ||
486 | |||
487 | $this->getDoctrine() | ||
488 | ->getRepository('WallabagCoreBundle:Entry') | ||
489 | ->removeTag($this->getUser()->getId(), $tag); | ||
490 | |||
491 | $this->cleanOrphanTag($tag); | ||
492 | |||
493 | $json = $this->get('serializer')->serialize($tag, 'json'); | ||
494 | |||
495 | return (new JsonResponse())->setJson($json); | ||
496 | } | ||
497 | |||
498 | /** | ||
499 | * Retrieve version number. | ||
500 | * | ||
501 | * @ApiDoc() | ||
502 | * | ||
503 | * @return JsonResponse | ||
504 | */ | ||
505 | public function getVersionAction() | ||
506 | { | ||
507 | $version = $this->container->getParameter('wallabag_core.version'); | ||
508 | |||
509 | $json = $this->get('serializer')->serialize($version, 'json'); | ||
510 | |||
511 | return (new JsonResponse())->setJson($json); | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * Remove orphan tag in case no entries are associated to it. | ||
516 | * | ||
517 | * @param Tag|array $tags | ||
518 | */ | ||
519 | private function cleanOrphanTag($tags) | ||
520 | { | ||
521 | if (!is_array($tags)) { | ||
522 | $tags = [$tags]; | ||
523 | } | ||
524 | |||
525 | $em = $this->getDoctrine()->getManager(); | ||
526 | |||
527 | foreach ($tags as $tag) { | ||
528 | if (count($tag->getEntries()) === 0) { | ||
529 | $em->remove($tag); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | $em->flush(); | ||
534 | } | ||
535 | |||
536 | /** | ||
537 | * Validate that the first id is equal to the second one. | 19 | * Validate that the first id is equal to the second one. |
538 | * If not, throw exception. It means a user try to access information from an other user. | 20 | * If not, throw exception. It means a user try to access information from an other user. |
539 | * | 21 | * |
540 | * @param int $requestUserId User id from the requested source | 22 | * @param int $requestUserId User id from the requested source |
541 | */ | 23 | */ |
542 | private function validateUserAccess($requestUserId) | 24 | protected function validateUserAccess($requestUserId) |
543 | { | 25 | { |
544 | $user = $this->get('security.token_storage')->getToken()->getUser(); | 26 | $user = $this->get('security.token_storage')->getToken()->getUser(); |
545 | if ($requestUserId != $user->getId()) { | 27 | if ($requestUserId != $user->getId()) { |
diff --git a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml index 5f43f971..901cf449 100644 --- a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml +++ b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml | |||
@@ -1,4 +1,14 @@ | |||
1 | entries: | 1 | api: |
2 | type: rest | 2 | type: rest |
3 | resource: "WallabagApiBundle:WallabagRest" | 3 | resource: "WallabagApiBundle:WallabagRest" |
4 | name_prefix: api_ | 4 | name_prefix: api_ |
5 | |||
6 | entries: | ||
7 | type: rest | ||
8 | resource: "WallabagApiBundle:EntryRest" | ||
9 | name_prefix: api_ | ||
10 | |||
11 | tags: | ||
12 | type: rest | ||
13 | resource: "WallabagApiBundle:TagRest" | ||
14 | name_prefix: api_ | ||
diff --git a/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php new file mode 100644 index 00000000..825f8f7a --- /dev/null +++ b/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php | |||
@@ -0,0 +1,673 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Tests\Wallabag\ApiBundle\Controller; | ||
4 | |||
5 | use Tests\Wallabag\ApiBundle\WallabagApiTestCase; | ||
6 | use Wallabag\CoreBundle\Entity\Tag; | ||
7 | |||
8 | class EntryRestControllerTest extends WallabagApiTestCase | ||
9 | { | ||
10 | public function testGetOneEntry() | ||
11 | { | ||
12 | $entry = $this->client->getContainer() | ||
13 | ->get('doctrine.orm.entity_manager') | ||
14 | ->getRepository('WallabagCoreBundle:Entry') | ||
15 | ->findOneBy(['user' => 1, 'isArchived' => false]); | ||
16 | |||
17 | if (!$entry) { | ||
18 | $this->markTestSkipped('No content found in db.'); | ||
19 | } | ||
20 | |||
21 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); | ||
22 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
23 | |||
24 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
25 | |||
26 | $this->assertEquals($entry->getTitle(), $content['title']); | ||
27 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
28 | $this->assertCount(count($entry->getTags()), $content['tags']); | ||
29 | $this->assertEquals($entry->getUserName(), $content['user_name']); | ||
30 | $this->assertEquals($entry->getUserEmail(), $content['user_email']); | ||
31 | $this->assertEquals($entry->getUserId(), $content['user_id']); | ||
32 | |||
33 | $this->assertTrue( | ||
34 | $this->client->getResponse()->headers->contains( | ||
35 | 'Content-Type', | ||
36 | 'application/json' | ||
37 | ) | ||
38 | ); | ||
39 | } | ||
40 | |||
41 | public function testGetOneEntryWrongUser() | ||
42 | { | ||
43 | $entry = $this->client->getContainer() | ||
44 | ->get('doctrine.orm.entity_manager') | ||
45 | ->getRepository('WallabagCoreBundle:Entry') | ||
46 | ->findOneBy(['user' => 2, 'isArchived' => false]); | ||
47 | |||
48 | if (!$entry) { | ||
49 | $this->markTestSkipped('No content found in db.'); | ||
50 | } | ||
51 | |||
52 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); | ||
53 | |||
54 | $this->assertEquals(403, $this->client->getResponse()->getStatusCode()); | ||
55 | } | ||
56 | |||
57 | public function testGetEntries() | ||
58 | { | ||
59 | $this->client->request('GET', '/api/entries'); | ||
60 | |||
61 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
62 | |||
63 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
64 | |||
65 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
66 | $this->assertNotEmpty($content['_embedded']['items']); | ||
67 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
68 | $this->assertEquals(1, $content['page']); | ||
69 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
70 | |||
71 | $this->assertTrue( | ||
72 | $this->client->getResponse()->headers->contains( | ||
73 | 'Content-Type', | ||
74 | 'application/json' | ||
75 | ) | ||
76 | ); | ||
77 | } | ||
78 | |||
79 | public function testGetEntriesWithFullOptions() | ||
80 | { | ||
81 | $this->client->request('GET', '/api/entries', [ | ||
82 | 'archive' => 1, | ||
83 | 'starred' => 1, | ||
84 | 'sort' => 'updated', | ||
85 | 'order' => 'asc', | ||
86 | 'page' => 1, | ||
87 | 'perPage' => 2, | ||
88 | 'tags' => 'foo', | ||
89 | 'since' => 1443274283, | ||
90 | ]); | ||
91 | |||
92 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
93 | |||
94 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
95 | |||
96 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
97 | $this->assertArrayHasKey('items', $content['_embedded']); | ||
98 | $this->assertGreaterThanOrEqual(0, $content['total']); | ||
99 | $this->assertEquals(1, $content['page']); | ||
100 | $this->assertEquals(2, $content['limit']); | ||
101 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
102 | |||
103 | $this->assertArrayHasKey('_links', $content); | ||
104 | $this->assertArrayHasKey('self', $content['_links']); | ||
105 | $this->assertArrayHasKey('first', $content['_links']); | ||
106 | $this->assertArrayHasKey('last', $content['_links']); | ||
107 | |||
108 | foreach (['self', 'first', 'last'] as $link) { | ||
109 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
110 | $this->assertContains('archive=1', $content['_links'][$link]['href']); | ||
111 | $this->assertContains('starred=1', $content['_links'][$link]['href']); | ||
112 | $this->assertContains('sort=updated', $content['_links'][$link]['href']); | ||
113 | $this->assertContains('order=asc', $content['_links'][$link]['href']); | ||
114 | $this->assertContains('tags=foo', $content['_links'][$link]['href']); | ||
115 | $this->assertContains('since=1443274283', $content['_links'][$link]['href']); | ||
116 | } | ||
117 | |||
118 | $this->assertTrue( | ||
119 | $this->client->getResponse()->headers->contains( | ||
120 | 'Content-Type', | ||
121 | 'application/json' | ||
122 | ) | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | public function testGetStarredEntries() | ||
127 | { | ||
128 | $this->client->request('GET', '/api/entries', ['starred' => 1, 'sort' => 'updated']); | ||
129 | |||
130 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
131 | |||
132 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
133 | |||
134 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
135 | $this->assertNotEmpty($content['_embedded']['items']); | ||
136 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
137 | $this->assertEquals(1, $content['page']); | ||
138 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
139 | |||
140 | $this->assertArrayHasKey('_links', $content); | ||
141 | $this->assertArrayHasKey('self', $content['_links']); | ||
142 | $this->assertArrayHasKey('first', $content['_links']); | ||
143 | $this->assertArrayHasKey('last', $content['_links']); | ||
144 | |||
145 | foreach (['self', 'first', 'last'] as $link) { | ||
146 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
147 | $this->assertContains('starred=1', $content['_links'][$link]['href']); | ||
148 | $this->assertContains('sort=updated', $content['_links'][$link]['href']); | ||
149 | } | ||
150 | |||
151 | $this->assertTrue( | ||
152 | $this->client->getResponse()->headers->contains( | ||
153 | 'Content-Type', | ||
154 | 'application/json' | ||
155 | ) | ||
156 | ); | ||
157 | } | ||
158 | |||
159 | public function testGetArchiveEntries() | ||
160 | { | ||
161 | $this->client->request('GET', '/api/entries', ['archive' => 1]); | ||
162 | |||
163 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
164 | |||
165 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
166 | |||
167 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
168 | $this->assertNotEmpty($content['_embedded']['items']); | ||
169 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
170 | $this->assertEquals(1, $content['page']); | ||
171 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
172 | |||
173 | $this->assertArrayHasKey('_links', $content); | ||
174 | $this->assertArrayHasKey('self', $content['_links']); | ||
175 | $this->assertArrayHasKey('first', $content['_links']); | ||
176 | $this->assertArrayHasKey('last', $content['_links']); | ||
177 | |||
178 | foreach (['self', 'first', 'last'] as $link) { | ||
179 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
180 | $this->assertContains('archive=1', $content['_links'][$link]['href']); | ||
181 | } | ||
182 | |||
183 | $this->assertTrue( | ||
184 | $this->client->getResponse()->headers->contains( | ||
185 | 'Content-Type', | ||
186 | 'application/json' | ||
187 | ) | ||
188 | ); | ||
189 | } | ||
190 | |||
191 | public function testGetTaggedEntries() | ||
192 | { | ||
193 | $this->client->request('GET', '/api/entries', ['tags' => 'foo,bar']); | ||
194 | |||
195 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
196 | |||
197 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
198 | |||
199 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
200 | $this->assertNotEmpty($content['_embedded']['items']); | ||
201 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
202 | $this->assertEquals(1, $content['page']); | ||
203 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
204 | |||
205 | $this->assertArrayHasKey('_links', $content); | ||
206 | $this->assertArrayHasKey('self', $content['_links']); | ||
207 | $this->assertArrayHasKey('first', $content['_links']); | ||
208 | $this->assertArrayHasKey('last', $content['_links']); | ||
209 | |||
210 | foreach (['self', 'first', 'last'] as $link) { | ||
211 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
212 | $this->assertContains('tags='.urlencode('foo,bar'), $content['_links'][$link]['href']); | ||
213 | } | ||
214 | |||
215 | $this->assertTrue( | ||
216 | $this->client->getResponse()->headers->contains( | ||
217 | 'Content-Type', | ||
218 | 'application/json' | ||
219 | ) | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | public function testGetDatedEntries() | ||
224 | { | ||
225 | $this->client->request('GET', '/api/entries', ['since' => 1443274283]); | ||
226 | |||
227 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
228 | |||
229 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
230 | |||
231 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
232 | $this->assertNotEmpty($content['_embedded']['items']); | ||
233 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
234 | $this->assertEquals(1, $content['page']); | ||
235 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
236 | |||
237 | $this->assertArrayHasKey('_links', $content); | ||
238 | $this->assertArrayHasKey('self', $content['_links']); | ||
239 | $this->assertArrayHasKey('first', $content['_links']); | ||
240 | $this->assertArrayHasKey('last', $content['_links']); | ||
241 | |||
242 | foreach (['self', 'first', 'last'] as $link) { | ||
243 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
244 | $this->assertContains('since=1443274283', $content['_links'][$link]['href']); | ||
245 | } | ||
246 | |||
247 | $this->assertTrue( | ||
248 | $this->client->getResponse()->headers->contains( | ||
249 | 'Content-Type', | ||
250 | 'application/json' | ||
251 | ) | ||
252 | ); | ||
253 | } | ||
254 | |||
255 | public function testGetDatedSupEntries() | ||
256 | { | ||
257 | $future = new \DateTime(date('Y-m-d H:i:s')); | ||
258 | $this->client->request('GET', '/api/entries', ['since' => $future->getTimestamp() + 1000]); | ||
259 | |||
260 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
261 | |||
262 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
263 | |||
264 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
265 | $this->assertEmpty($content['_embedded']['items']); | ||
266 | $this->assertEquals(0, $content['total']); | ||
267 | $this->assertEquals(1, $content['page']); | ||
268 | $this->assertEquals(1, $content['pages']); | ||
269 | |||
270 | $this->assertArrayHasKey('_links', $content); | ||
271 | $this->assertArrayHasKey('self', $content['_links']); | ||
272 | $this->assertArrayHasKey('first', $content['_links']); | ||
273 | $this->assertArrayHasKey('last', $content['_links']); | ||
274 | |||
275 | foreach (['self', 'first', 'last'] as $link) { | ||
276 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
277 | $this->assertContains('since='.($future->getTimestamp() + 1000), $content['_links'][$link]['href']); | ||
278 | } | ||
279 | |||
280 | $this->assertTrue( | ||
281 | $this->client->getResponse()->headers->contains( | ||
282 | 'Content-Type', | ||
283 | 'application/json' | ||
284 | ) | ||
285 | ); | ||
286 | } | ||
287 | |||
288 | public function testDeleteEntry() | ||
289 | { | ||
290 | $entry = $this->client->getContainer() | ||
291 | ->get('doctrine.orm.entity_manager') | ||
292 | ->getRepository('WallabagCoreBundle:Entry') | ||
293 | ->findOneByUser(1); | ||
294 | |||
295 | if (!$entry) { | ||
296 | $this->markTestSkipped('No content found in db.'); | ||
297 | } | ||
298 | |||
299 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); | ||
300 | |||
301 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
302 | |||
303 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
304 | |||
305 | $this->assertEquals($entry->getTitle(), $content['title']); | ||
306 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
307 | |||
308 | // We'll try to delete this entry again | ||
309 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); | ||
310 | |||
311 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); | ||
312 | } | ||
313 | |||
314 | public function testPostEntry() | ||
315 | { | ||
316 | $this->client->request('POST', '/api/entries.json', [ | ||
317 | 'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', | ||
318 | 'tags' => 'google', | ||
319 | 'title' => 'New title for my article', | ||
320 | ]); | ||
321 | |||
322 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
323 | |||
324 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
325 | |||
326 | $this->assertGreaterThan(0, $content['id']); | ||
327 | $this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); | ||
328 | $this->assertEquals(false, $content['is_archived']); | ||
329 | $this->assertEquals(false, $content['is_starred']); | ||
330 | $this->assertEquals('New title for my article', $content['title']); | ||
331 | $this->assertEquals(1, $content['user_id']); | ||
332 | $this->assertCount(1, $content['tags']); | ||
333 | } | ||
334 | |||
335 | public function testPostSameEntry() | ||
336 | { | ||
337 | $this->client->request('POST', '/api/entries.json', [ | ||
338 | 'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', | ||
339 | 'archive' => '1', | ||
340 | 'tags' => 'google, apple', | ||
341 | ]); | ||
342 | |||
343 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
344 | |||
345 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
346 | |||
347 | $this->assertGreaterThan(0, $content['id']); | ||
348 | $this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); | ||
349 | $this->assertEquals(true, $content['is_archived']); | ||
350 | $this->assertEquals(false, $content['is_starred']); | ||
351 | $this->assertCount(2, $content['tags']); | ||
352 | } | ||
353 | |||
354 | public function testPostArchivedAndStarredEntry() | ||
355 | { | ||
356 | $this->client->request('POST', '/api/entries.json', [ | ||
357 | 'url' => 'http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', | ||
358 | 'archive' => '1', | ||
359 | 'starred' => '1', | ||
360 | ]); | ||
361 | |||
362 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
363 | |||
364 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
365 | |||
366 | $this->assertGreaterThan(0, $content['id']); | ||
367 | $this->assertEquals('http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', $content['url']); | ||
368 | $this->assertEquals(true, $content['is_archived']); | ||
369 | $this->assertEquals(true, $content['is_starred']); | ||
370 | $this->assertEquals(1, $content['user_id']); | ||
371 | } | ||
372 | |||
373 | public function testPostArchivedAndStarredEntryWithoutQuotes() | ||
374 | { | ||
375 | $this->client->request('POST', '/api/entries.json', [ | ||
376 | 'url' => 'http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', | ||
377 | 'archive' => 0, | ||
378 | 'starred' => 1, | ||
379 | ]); | ||
380 | |||
381 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
382 | |||
383 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
384 | |||
385 | $this->assertGreaterThan(0, $content['id']); | ||
386 | $this->assertEquals('http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', $content['url']); | ||
387 | $this->assertEquals(false, $content['is_archived']); | ||
388 | $this->assertEquals(true, $content['is_starred']); | ||
389 | } | ||
390 | |||
391 | public function testPatchEntry() | ||
392 | { | ||
393 | $entry = $this->client->getContainer() | ||
394 | ->get('doctrine.orm.entity_manager') | ||
395 | ->getRepository('WallabagCoreBundle:Entry') | ||
396 | ->findOneByUser(1); | ||
397 | |||
398 | if (!$entry) { | ||
399 | $this->markTestSkipped('No content found in db.'); | ||
400 | } | ||
401 | |||
402 | // hydrate the tags relations | ||
403 | $nbTags = count($entry->getTags()); | ||
404 | |||
405 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
406 | 'title' => 'New awesome title', | ||
407 | 'tags' => 'new tag '.uniqid(), | ||
408 | 'starred' => '1', | ||
409 | 'archive' => '0', | ||
410 | ]); | ||
411 | |||
412 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
413 | |||
414 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
415 | |||
416 | $this->assertEquals($entry->getId(), $content['id']); | ||
417 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
418 | $this->assertEquals('New awesome title', $content['title']); | ||
419 | $this->assertGreaterThan($nbTags, count($content['tags'])); | ||
420 | $this->assertEquals(1, $content['user_id']); | ||
421 | } | ||
422 | |||
423 | public function testPatchEntryWithoutQuotes() | ||
424 | { | ||
425 | $entry = $this->client->getContainer() | ||
426 | ->get('doctrine.orm.entity_manager') | ||
427 | ->getRepository('WallabagCoreBundle:Entry') | ||
428 | ->findOneByUser(1); | ||
429 | |||
430 | if (!$entry) { | ||
431 | $this->markTestSkipped('No content found in db.'); | ||
432 | } | ||
433 | |||
434 | // hydrate the tags relations | ||
435 | $nbTags = count($entry->getTags()); | ||
436 | |||
437 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
438 | 'title' => 'New awesome title', | ||
439 | 'tags' => 'new tag '.uniqid(), | ||
440 | 'starred' => 1, | ||
441 | 'archive' => 0, | ||
442 | ]); | ||
443 | |||
444 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
445 | |||
446 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
447 | |||
448 | $this->assertEquals($entry->getId(), $content['id']); | ||
449 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
450 | $this->assertEquals('New awesome title', $content['title']); | ||
451 | $this->assertGreaterThan($nbTags, count($content['tags'])); | ||
452 | } | ||
453 | |||
454 | public function testGetTagsEntry() | ||
455 | { | ||
456 | $entry = $this->client->getContainer() | ||
457 | ->get('doctrine.orm.entity_manager') | ||
458 | ->getRepository('WallabagCoreBundle:Entry') | ||
459 | ->findOneWithTags($this->user->getId()); | ||
460 | |||
461 | $entry = $entry[0]; | ||
462 | |||
463 | if (!$entry) { | ||
464 | $this->markTestSkipped('No content found in db.'); | ||
465 | } | ||
466 | |||
467 | $tags = []; | ||
468 | foreach ($entry->getTags() as $tag) { | ||
469 | $tags[] = ['id' => $tag->getId(), 'label' => $tag->getLabel(), 'slug' => $tag->getSlug()]; | ||
470 | } | ||
471 | |||
472 | $this->client->request('GET', '/api/entries/'.$entry->getId().'/tags'); | ||
473 | |||
474 | $this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $this->client->getResponse()->getContent()); | ||
475 | } | ||
476 | |||
477 | public function testPostTagsOnEntry() | ||
478 | { | ||
479 | $entry = $this->client->getContainer() | ||
480 | ->get('doctrine.orm.entity_manager') | ||
481 | ->getRepository('WallabagCoreBundle:Entry') | ||
482 | ->findOneByUser(1); | ||
483 | |||
484 | if (!$entry) { | ||
485 | $this->markTestSkipped('No content found in db.'); | ||
486 | } | ||
487 | |||
488 | $nbTags = count($entry->getTags()); | ||
489 | |||
490 | $newTags = 'tag1,tag2,tag3'; | ||
491 | |||
492 | $this->client->request('POST', '/api/entries/'.$entry->getId().'/tags', ['tags' => $newTags]); | ||
493 | |||
494 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
495 | |||
496 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
497 | |||
498 | $this->assertArrayHasKey('tags', $content); | ||
499 | $this->assertEquals($nbTags + 3, count($content['tags'])); | ||
500 | |||
501 | $entryDB = $this->client->getContainer() | ||
502 | ->get('doctrine.orm.entity_manager') | ||
503 | ->getRepository('WallabagCoreBundle:Entry') | ||
504 | ->find($entry->getId()); | ||
505 | |||
506 | $tagsInDB = []; | ||
507 | foreach ($entryDB->getTags()->toArray() as $tag) { | ||
508 | $tagsInDB[$tag->getId()] = $tag->getLabel(); | ||
509 | } | ||
510 | |||
511 | foreach (explode(',', $newTags) as $tag) { | ||
512 | $this->assertContains($tag, $tagsInDB); | ||
513 | } | ||
514 | } | ||
515 | |||
516 | public function testDeleteOneTagEntry() | ||
517 | { | ||
518 | $entry = $this->client->getContainer() | ||
519 | ->get('doctrine.orm.entity_manager') | ||
520 | ->getRepository('WallabagCoreBundle:Entry') | ||
521 | ->findOneWithTags($this->user->getId()); | ||
522 | $entry = $entry[0]; | ||
523 | |||
524 | if (!$entry) { | ||
525 | $this->markTestSkipped('No content found in db.'); | ||
526 | } | ||
527 | |||
528 | // hydrate the tags relations | ||
529 | $nbTags = count($entry->getTags()); | ||
530 | $tag = $entry->getTags()[0]; | ||
531 | |||
532 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json'); | ||
533 | |||
534 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
535 | |||
536 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
537 | |||
538 | $this->assertArrayHasKey('tags', $content); | ||
539 | $this->assertEquals($nbTags - 1, count($content['tags'])); | ||
540 | } | ||
541 | |||
542 | public function testSaveIsArchivedAfterPost() | ||
543 | { | ||
544 | $entry = $this->client->getContainer() | ||
545 | ->get('doctrine.orm.entity_manager') | ||
546 | ->getRepository('WallabagCoreBundle:Entry') | ||
547 | ->findOneBy(['user' => 1, 'isArchived' => true]); | ||
548 | |||
549 | if (!$entry) { | ||
550 | $this->markTestSkipped('No content found in db.'); | ||
551 | } | ||
552 | |||
553 | $this->client->request('POST', '/api/entries.json', [ | ||
554 | 'url' => $entry->getUrl(), | ||
555 | ]); | ||
556 | |||
557 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
558 | |||
559 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
560 | |||
561 | $this->assertEquals(true, $content['is_archived']); | ||
562 | } | ||
563 | |||
564 | public function testSaveIsStarredAfterPost() | ||
565 | { | ||
566 | $entry = $this->client->getContainer() | ||
567 | ->get('doctrine.orm.entity_manager') | ||
568 | ->getRepository('WallabagCoreBundle:Entry') | ||
569 | ->findOneBy(['user' => 1, 'isStarred' => true]); | ||
570 | |||
571 | if (!$entry) { | ||
572 | $this->markTestSkipped('No content found in db.'); | ||
573 | } | ||
574 | |||
575 | $this->client->request('POST', '/api/entries.json', [ | ||
576 | 'url' => $entry->getUrl(), | ||
577 | ]); | ||
578 | |||
579 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
580 | |||
581 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
582 | |||
583 | $this->assertEquals(true, $content['is_starred']); | ||
584 | } | ||
585 | |||
586 | public function testSaveIsArchivedAfterPatch() | ||
587 | { | ||
588 | $entry = $this->client->getContainer() | ||
589 | ->get('doctrine.orm.entity_manager') | ||
590 | ->getRepository('WallabagCoreBundle:Entry') | ||
591 | ->findOneBy(['user' => 1, 'isArchived' => true]); | ||
592 | |||
593 | if (!$entry) { | ||
594 | $this->markTestSkipped('No content found in db.'); | ||
595 | } | ||
596 | |||
597 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
598 | 'title' => $entry->getTitle().'++', | ||
599 | ]); | ||
600 | |||
601 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
602 | |||
603 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
604 | |||
605 | $this->assertEquals(true, $content['is_archived']); | ||
606 | } | ||
607 | |||
608 | public function testSaveIsStarredAfterPatch() | ||
609 | { | ||
610 | $entry = $this->client->getContainer() | ||
611 | ->get('doctrine.orm.entity_manager') | ||
612 | ->getRepository('WallabagCoreBundle:Entry') | ||
613 | ->findOneBy(['user' => 1, 'isStarred' => true]); | ||
614 | |||
615 | if (!$entry) { | ||
616 | $this->markTestSkipped('No content found in db.'); | ||
617 | } | ||
618 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
619 | 'title' => $entry->getTitle().'++', | ||
620 | ]); | ||
621 | |||
622 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
623 | |||
624 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
625 | |||
626 | $this->assertEquals(true, $content['is_starred']); | ||
627 | } | ||
628 | |||
629 | public function testGetEntriesExists() | ||
630 | { | ||
631 | $this->client->request('GET', '/api/entries/exists?url=http://0.0.0.0/entry2'); | ||
632 | |||
633 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
634 | |||
635 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
636 | |||
637 | $this->assertEquals(true, $content['exists']); | ||
638 | } | ||
639 | |||
640 | public function testGetEntriesExistsWithManyUrls() | ||
641 | { | ||
642 | $url1 = 'http://0.0.0.0/entry2'; | ||
643 | $url2 = 'http://0.0.0.0/entry10'; | ||
644 | $this->client->request('GET', '/api/entries/exists?urls[]='.$url1.'&urls[]='.$url2); | ||
645 | |||
646 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
647 | |||
648 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
649 | |||
650 | $this->assertArrayHasKey($url1, $content); | ||
651 | $this->assertArrayHasKey($url2, $content); | ||
652 | $this->assertEquals(true, $content[$url1]); | ||
653 | $this->assertEquals(false, $content[$url2]); | ||
654 | } | ||
655 | |||
656 | public function testGetEntriesExistsWhichDoesNotExists() | ||
657 | { | ||
658 | $this->client->request('GET', '/api/entries/exists?url=http://google.com/entry2'); | ||
659 | |||
660 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
661 | |||
662 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
663 | |||
664 | $this->assertEquals(false, $content['exists']); | ||
665 | } | ||
666 | |||
667 | public function testGetEntriesExistsWithNoUrl() | ||
668 | { | ||
669 | $this->client->request('GET', '/api/entries/exists?url='); | ||
670 | |||
671 | $this->assertEquals(403, $this->client->getResponse()->getStatusCode()); | ||
672 | } | ||
673 | } | ||
diff --git a/tests/Wallabag/ApiBundle/Controller/TagRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/TagRestControllerTest.php new file mode 100644 index 00000000..bde5251f --- /dev/null +++ b/tests/Wallabag/ApiBundle/Controller/TagRestControllerTest.php | |||
@@ -0,0 +1,162 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Tests\Wallabag\ApiBundle\Controller; | ||
4 | |||
5 | use Tests\Wallabag\ApiBundle\WallabagApiTestCase; | ||
6 | use Wallabag\CoreBundle\Entity\Tag; | ||
7 | |||
8 | class TagRestControllerTest extends WallabagApiTestCase | ||
9 | { | ||
10 | public function testGetUserTags() | ||
11 | { | ||
12 | $this->client->request('GET', '/api/tags.json'); | ||
13 | |||
14 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
15 | |||
16 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
17 | |||
18 | $this->assertGreaterThan(0, $content); | ||
19 | $this->assertArrayHasKey('id', $content[0]); | ||
20 | $this->assertArrayHasKey('label', $content[0]); | ||
21 | |||
22 | return end($content); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @depends testGetUserTags | ||
27 | */ | ||
28 | public function testDeleteUserTag($tag) | ||
29 | { | ||
30 | $tagName = $tag['label']; | ||
31 | |||
32 | $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json'); | ||
33 | |||
34 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
35 | |||
36 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
37 | |||
38 | $this->assertArrayHasKey('label', $content); | ||
39 | $this->assertEquals($tag['label'], $content['label']); | ||
40 | $this->assertEquals($tag['slug'], $content['slug']); | ||
41 | |||
42 | $entries = $this->client->getContainer() | ||
43 | ->get('doctrine.orm.entity_manager') | ||
44 | ->getRepository('WallabagCoreBundle:Entry') | ||
45 | ->findAllByTagId($this->user->getId(), $tag['id']); | ||
46 | |||
47 | $this->assertCount(0, $entries); | ||
48 | |||
49 | $tag = $this->client->getContainer() | ||
50 | ->get('doctrine.orm.entity_manager') | ||
51 | ->getRepository('WallabagCoreBundle:Tag') | ||
52 | ->findOneByLabel($tagName); | ||
53 | |||
54 | $this->assertNull($tag, $tagName.' was removed because it begun an orphan tag'); | ||
55 | } | ||
56 | |||
57 | public function testDeleteTagByLabel() | ||
58 | { | ||
59 | $em = $this->client->getContainer()->get('doctrine.orm.entity_manager'); | ||
60 | $entry = $this->client->getContainer() | ||
61 | ->get('doctrine.orm.entity_manager') | ||
62 | ->getRepository('WallabagCoreBundle:Entry') | ||
63 | ->findOneWithTags($this->user->getId()); | ||
64 | |||
65 | $entry = $entry[0]; | ||
66 | |||
67 | $tag = new Tag(); | ||
68 | $tag->setLabel('Awesome tag for test'); | ||
69 | $em->persist($tag); | ||
70 | |||
71 | $entry->addTag($tag); | ||
72 | |||
73 | $em->persist($entry); | ||
74 | $em->flush(); | ||
75 | |||
76 | $this->client->request('DELETE', '/api/tag/label.json', ['tag' => $tag->getLabel()]); | ||
77 | |||
78 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
79 | |||
80 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
81 | |||
82 | $this->assertArrayHasKey('label', $content); | ||
83 | $this->assertEquals($tag->getLabel(), $content['label']); | ||
84 | $this->assertEquals($tag->getSlug(), $content['slug']); | ||
85 | |||
86 | $entries = $this->client->getContainer() | ||
87 | ->get('doctrine.orm.entity_manager') | ||
88 | ->getRepository('WallabagCoreBundle:Entry') | ||
89 | ->findAllByTagId($this->user->getId(), $tag->getId()); | ||
90 | |||
91 | $this->assertCount(0, $entries); | ||
92 | } | ||
93 | |||
94 | public function testDeleteTagByLabelNotFound() | ||
95 | { | ||
96 | $this->client->request('DELETE', '/api/tag/label.json', ['tag' => 'does not exist']); | ||
97 | |||
98 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); | ||
99 | } | ||
100 | |||
101 | public function testDeleteTagsByLabel() | ||
102 | { | ||
103 | $em = $this->client->getContainer()->get('doctrine.orm.entity_manager'); | ||
104 | $entry = $this->client->getContainer() | ||
105 | ->get('doctrine.orm.entity_manager') | ||
106 | ->getRepository('WallabagCoreBundle:Entry') | ||
107 | ->findOneWithTags($this->user->getId()); | ||
108 | |||
109 | $entry = $entry[0]; | ||
110 | |||
111 | $tag = new Tag(); | ||
112 | $tag->setLabel('Awesome tag for tagsLabel'); | ||
113 | $em->persist($tag); | ||
114 | |||
115 | $tag2 = new Tag(); | ||
116 | $tag2->setLabel('Awesome tag for tagsLabel 2'); | ||
117 | $em->persist($tag2); | ||
118 | |||
119 | $entry->addTag($tag); | ||
120 | $entry->addTag($tag2); | ||
121 | |||
122 | $em->persist($entry); | ||
123 | $em->flush(); | ||
124 | |||
125 | $this->client->request('DELETE', '/api/tags/label.json', ['tags' => $tag->getLabel().','.$tag2->getLabel()]); | ||
126 | |||
127 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
128 | |||
129 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
130 | |||
131 | $this->assertCount(2, $content); | ||
132 | |||
133 | $this->assertArrayHasKey('label', $content[0]); | ||
134 | $this->assertEquals($tag->getLabel(), $content[0]['label']); | ||
135 | $this->assertEquals($tag->getSlug(), $content[0]['slug']); | ||
136 | |||
137 | $this->assertArrayHasKey('label', $content[1]); | ||
138 | $this->assertEquals($tag2->getLabel(), $content[1]['label']); | ||
139 | $this->assertEquals($tag2->getSlug(), $content[1]['slug']); | ||
140 | |||
141 | $entries = $this->client->getContainer() | ||
142 | ->get('doctrine.orm.entity_manager') | ||
143 | ->getRepository('WallabagCoreBundle:Entry') | ||
144 | ->findAllByTagId($this->user->getId(), $tag->getId()); | ||
145 | |||
146 | $this->assertCount(0, $entries); | ||
147 | |||
148 | $entries = $this->client->getContainer() | ||
149 | ->get('doctrine.orm.entity_manager') | ||
150 | ->getRepository('WallabagCoreBundle:Entry') | ||
151 | ->findAllByTagId($this->user->getId(), $tag2->getId()); | ||
152 | |||
153 | $this->assertCount(0, $entries); | ||
154 | } | ||
155 | |||
156 | public function testDeleteTagsByLabelNotFound() | ||
157 | { | ||
158 | $this->client->request('DELETE', '/api/tags/label.json', ['tags' => 'does not exist']); | ||
159 | |||
160 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); | ||
161 | } | ||
162 | } | ||
diff --git a/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php index 5dcb3e00..c87e58de 100644 --- a/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php +++ b/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php | |||
@@ -3,697 +3,9 @@ | |||
3 | namespace Tests\Wallabag\ApiBundle\Controller; | 3 | namespace Tests\Wallabag\ApiBundle\Controller; |
4 | 4 | ||
5 | use Tests\Wallabag\ApiBundle\WallabagApiTestCase; | 5 | use Tests\Wallabag\ApiBundle\WallabagApiTestCase; |
6 | use Wallabag\CoreBundle\Entity\Tag; | ||
7 | 6 | ||
8 | class WallabagRestControllerTest extends WallabagApiTestCase | 7 | class WallabagRestControllerTest extends WallabagApiTestCase |
9 | { | 8 | { |
10 | protected static $salt; | ||
11 | |||
12 | public function testGetOneEntry() | ||
13 | { | ||
14 | $entry = $this->client->getContainer() | ||
15 | ->get('doctrine.orm.entity_manager') | ||
16 | ->getRepository('WallabagCoreBundle:Entry') | ||
17 | ->findOneBy(['user' => 1, 'isArchived' => false]); | ||
18 | |||
19 | if (!$entry) { | ||
20 | $this->markTestSkipped('No content found in db.'); | ||
21 | } | ||
22 | |||
23 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); | ||
24 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
25 | |||
26 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
27 | |||
28 | $this->assertEquals($entry->getTitle(), $content['title']); | ||
29 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
30 | $this->assertCount(count($entry->getTags()), $content['tags']); | ||
31 | $this->assertEquals($entry->getUserName(), $content['user_name']); | ||
32 | $this->assertEquals($entry->getUserEmail(), $content['user_email']); | ||
33 | $this->assertEquals($entry->getUserId(), $content['user_id']); | ||
34 | |||
35 | $this->assertTrue( | ||
36 | $this->client->getResponse()->headers->contains( | ||
37 | 'Content-Type', | ||
38 | 'application/json' | ||
39 | ) | ||
40 | ); | ||
41 | } | ||
42 | |||
43 | public function testGetOneEntryWrongUser() | ||
44 | { | ||
45 | $entry = $this->client->getContainer() | ||
46 | ->get('doctrine.orm.entity_manager') | ||
47 | ->getRepository('WallabagCoreBundle:Entry') | ||
48 | ->findOneBy(['user' => 2, 'isArchived' => false]); | ||
49 | |||
50 | if (!$entry) { | ||
51 | $this->markTestSkipped('No content found in db.'); | ||
52 | } | ||
53 | |||
54 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); | ||
55 | |||
56 | $this->assertEquals(403, $this->client->getResponse()->getStatusCode()); | ||
57 | } | ||
58 | |||
59 | public function testGetEntries() | ||
60 | { | ||
61 | $this->client->request('GET', '/api/entries'); | ||
62 | |||
63 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
64 | |||
65 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
66 | |||
67 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
68 | $this->assertNotEmpty($content['_embedded']['items']); | ||
69 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
70 | $this->assertEquals(1, $content['page']); | ||
71 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
72 | |||
73 | $this->assertTrue( | ||
74 | $this->client->getResponse()->headers->contains( | ||
75 | 'Content-Type', | ||
76 | 'application/json' | ||
77 | ) | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | public function testGetEntriesWithFullOptions() | ||
82 | { | ||
83 | $this->client->request('GET', '/api/entries', [ | ||
84 | 'archive' => 1, | ||
85 | 'starred' => 1, | ||
86 | 'sort' => 'updated', | ||
87 | 'order' => 'asc', | ||
88 | 'page' => 1, | ||
89 | 'perPage' => 2, | ||
90 | 'tags' => 'foo', | ||
91 | 'since' => 1443274283, | ||
92 | ]); | ||
93 | |||
94 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
95 | |||
96 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
97 | |||
98 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
99 | $this->assertArrayHasKey('items', $content['_embedded']); | ||
100 | $this->assertGreaterThanOrEqual(0, $content['total']); | ||
101 | $this->assertEquals(1, $content['page']); | ||
102 | $this->assertEquals(2, $content['limit']); | ||
103 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
104 | |||
105 | $this->assertArrayHasKey('_links', $content); | ||
106 | $this->assertArrayHasKey('self', $content['_links']); | ||
107 | $this->assertArrayHasKey('first', $content['_links']); | ||
108 | $this->assertArrayHasKey('last', $content['_links']); | ||
109 | |||
110 | foreach (['self', 'first', 'last'] as $link) { | ||
111 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
112 | $this->assertContains('archive=1', $content['_links'][$link]['href']); | ||
113 | $this->assertContains('starred=1', $content['_links'][$link]['href']); | ||
114 | $this->assertContains('sort=updated', $content['_links'][$link]['href']); | ||
115 | $this->assertContains('order=asc', $content['_links'][$link]['href']); | ||
116 | $this->assertContains('tags=foo', $content['_links'][$link]['href']); | ||
117 | $this->assertContains('since=1443274283', $content['_links'][$link]['href']); | ||
118 | } | ||
119 | |||
120 | $this->assertTrue( | ||
121 | $this->client->getResponse()->headers->contains( | ||
122 | 'Content-Type', | ||
123 | 'application/json' | ||
124 | ) | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | public function testGetStarredEntries() | ||
129 | { | ||
130 | $this->client->request('GET', '/api/entries', ['starred' => 1, 'sort' => 'updated']); | ||
131 | |||
132 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
133 | |||
134 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
135 | |||
136 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
137 | $this->assertNotEmpty($content['_embedded']['items']); | ||
138 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
139 | $this->assertEquals(1, $content['page']); | ||
140 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
141 | |||
142 | $this->assertArrayHasKey('_links', $content); | ||
143 | $this->assertArrayHasKey('self', $content['_links']); | ||
144 | $this->assertArrayHasKey('first', $content['_links']); | ||
145 | $this->assertArrayHasKey('last', $content['_links']); | ||
146 | |||
147 | foreach (['self', 'first', 'last'] as $link) { | ||
148 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
149 | $this->assertContains('starred=1', $content['_links'][$link]['href']); | ||
150 | $this->assertContains('sort=updated', $content['_links'][$link]['href']); | ||
151 | } | ||
152 | |||
153 | $this->assertTrue( | ||
154 | $this->client->getResponse()->headers->contains( | ||
155 | 'Content-Type', | ||
156 | 'application/json' | ||
157 | ) | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | public function testGetArchiveEntries() | ||
162 | { | ||
163 | $this->client->request('GET', '/api/entries', ['archive' => 1]); | ||
164 | |||
165 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
166 | |||
167 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
168 | |||
169 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
170 | $this->assertNotEmpty($content['_embedded']['items']); | ||
171 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
172 | $this->assertEquals(1, $content['page']); | ||
173 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
174 | |||
175 | $this->assertArrayHasKey('_links', $content); | ||
176 | $this->assertArrayHasKey('self', $content['_links']); | ||
177 | $this->assertArrayHasKey('first', $content['_links']); | ||
178 | $this->assertArrayHasKey('last', $content['_links']); | ||
179 | |||
180 | foreach (['self', 'first', 'last'] as $link) { | ||
181 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
182 | $this->assertContains('archive=1', $content['_links'][$link]['href']); | ||
183 | } | ||
184 | |||
185 | $this->assertTrue( | ||
186 | $this->client->getResponse()->headers->contains( | ||
187 | 'Content-Type', | ||
188 | 'application/json' | ||
189 | ) | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | public function testGetTaggedEntries() | ||
194 | { | ||
195 | $this->client->request('GET', '/api/entries', ['tags' => 'foo,bar']); | ||
196 | |||
197 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
198 | |||
199 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
200 | |||
201 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
202 | $this->assertNotEmpty($content['_embedded']['items']); | ||
203 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
204 | $this->assertEquals(1, $content['page']); | ||
205 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
206 | |||
207 | $this->assertArrayHasKey('_links', $content); | ||
208 | $this->assertArrayHasKey('self', $content['_links']); | ||
209 | $this->assertArrayHasKey('first', $content['_links']); | ||
210 | $this->assertArrayHasKey('last', $content['_links']); | ||
211 | |||
212 | foreach (['self', 'first', 'last'] as $link) { | ||
213 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
214 | $this->assertContains('tags='.urlencode('foo,bar'), $content['_links'][$link]['href']); | ||
215 | } | ||
216 | |||
217 | $this->assertTrue( | ||
218 | $this->client->getResponse()->headers->contains( | ||
219 | 'Content-Type', | ||
220 | 'application/json' | ||
221 | ) | ||
222 | ); | ||
223 | } | ||
224 | |||
225 | public function testGetDatedEntries() | ||
226 | { | ||
227 | $this->client->request('GET', '/api/entries', ['since' => 1443274283]); | ||
228 | |||
229 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
230 | |||
231 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
232 | |||
233 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
234 | $this->assertNotEmpty($content['_embedded']['items']); | ||
235 | $this->assertGreaterThanOrEqual(1, $content['total']); | ||
236 | $this->assertEquals(1, $content['page']); | ||
237 | $this->assertGreaterThanOrEqual(1, $content['pages']); | ||
238 | |||
239 | $this->assertArrayHasKey('_links', $content); | ||
240 | $this->assertArrayHasKey('self', $content['_links']); | ||
241 | $this->assertArrayHasKey('first', $content['_links']); | ||
242 | $this->assertArrayHasKey('last', $content['_links']); | ||
243 | |||
244 | foreach (['self', 'first', 'last'] as $link) { | ||
245 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
246 | $this->assertContains('since=1443274283', $content['_links'][$link]['href']); | ||
247 | } | ||
248 | |||
249 | $this->assertTrue( | ||
250 | $this->client->getResponse()->headers->contains( | ||
251 | 'Content-Type', | ||
252 | 'application/json' | ||
253 | ) | ||
254 | ); | ||
255 | } | ||
256 | |||
257 | public function testGetDatedSupEntries() | ||
258 | { | ||
259 | $future = new \DateTime(date('Y-m-d H:i:s')); | ||
260 | $this->client->request('GET', '/api/entries', ['since' => $future->getTimestamp() + 1000]); | ||
261 | |||
262 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
263 | |||
264 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
265 | |||
266 | $this->assertGreaterThanOrEqual(1, count($content)); | ||
267 | $this->assertEmpty($content['_embedded']['items']); | ||
268 | $this->assertEquals(0, $content['total']); | ||
269 | $this->assertEquals(1, $content['page']); | ||
270 | $this->assertEquals(1, $content['pages']); | ||
271 | |||
272 | $this->assertArrayHasKey('_links', $content); | ||
273 | $this->assertArrayHasKey('self', $content['_links']); | ||
274 | $this->assertArrayHasKey('first', $content['_links']); | ||
275 | $this->assertArrayHasKey('last', $content['_links']); | ||
276 | |||
277 | foreach (['self', 'first', 'last'] as $link) { | ||
278 | $this->assertArrayHasKey('href', $content['_links'][$link]); | ||
279 | $this->assertContains('since='.($future->getTimestamp() + 1000), $content['_links'][$link]['href']); | ||
280 | } | ||
281 | |||
282 | $this->assertTrue( | ||
283 | $this->client->getResponse()->headers->contains( | ||
284 | 'Content-Type', | ||
285 | 'application/json' | ||
286 | ) | ||
287 | ); | ||
288 | } | ||
289 | |||
290 | public function testDeleteEntry() | ||
291 | { | ||
292 | $entry = $this->client->getContainer() | ||
293 | ->get('doctrine.orm.entity_manager') | ||
294 | ->getRepository('WallabagCoreBundle:Entry') | ||
295 | ->findOneByUser(1); | ||
296 | |||
297 | if (!$entry) { | ||
298 | $this->markTestSkipped('No content found in db.'); | ||
299 | } | ||
300 | |||
301 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); | ||
302 | |||
303 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
304 | |||
305 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
306 | |||
307 | $this->assertEquals($entry->getTitle(), $content['title']); | ||
308 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
309 | |||
310 | // We'll try to delete this entry again | ||
311 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); | ||
312 | |||
313 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); | ||
314 | } | ||
315 | |||
316 | public function testPostEntry() | ||
317 | { | ||
318 | $this->client->request('POST', '/api/entries.json', [ | ||
319 | 'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', | ||
320 | 'tags' => 'google', | ||
321 | 'title' => 'New title for my article', | ||
322 | ]); | ||
323 | |||
324 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
325 | |||
326 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
327 | |||
328 | $this->assertGreaterThan(0, $content['id']); | ||
329 | $this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); | ||
330 | $this->assertEquals(false, $content['is_archived']); | ||
331 | $this->assertEquals(false, $content['is_starred']); | ||
332 | $this->assertEquals('New title for my article', $content['title']); | ||
333 | $this->assertEquals(1, $content['user_id']); | ||
334 | $this->assertCount(1, $content['tags']); | ||
335 | } | ||
336 | |||
337 | public function testPostSameEntry() | ||
338 | { | ||
339 | $this->client->request('POST', '/api/entries.json', [ | ||
340 | 'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', | ||
341 | 'archive' => '1', | ||
342 | 'tags' => 'google, apple', | ||
343 | ]); | ||
344 | |||
345 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
346 | |||
347 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
348 | |||
349 | $this->assertGreaterThan(0, $content['id']); | ||
350 | $this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); | ||
351 | $this->assertEquals(true, $content['is_archived']); | ||
352 | $this->assertEquals(false, $content['is_starred']); | ||
353 | $this->assertCount(2, $content['tags']); | ||
354 | } | ||
355 | |||
356 | public function testPostArchivedAndStarredEntry() | ||
357 | { | ||
358 | $this->client->request('POST', '/api/entries.json', [ | ||
359 | 'url' => 'http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', | ||
360 | 'archive' => '1', | ||
361 | 'starred' => '1', | ||
362 | ]); | ||
363 | |||
364 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
365 | |||
366 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
367 | |||
368 | $this->assertGreaterThan(0, $content['id']); | ||
369 | $this->assertEquals('http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', $content['url']); | ||
370 | $this->assertEquals(true, $content['is_archived']); | ||
371 | $this->assertEquals(true, $content['is_starred']); | ||
372 | $this->assertEquals(1, $content['user_id']); | ||
373 | } | ||
374 | |||
375 | public function testPostArchivedAndStarredEntryWithoutQuotes() | ||
376 | { | ||
377 | $this->client->request('POST', '/api/entries.json', [ | ||
378 | 'url' => 'http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', | ||
379 | 'archive' => 0, | ||
380 | 'starred' => 1, | ||
381 | ]); | ||
382 | |||
383 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
384 | |||
385 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
386 | |||
387 | $this->assertGreaterThan(0, $content['id']); | ||
388 | $this->assertEquals('http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', $content['url']); | ||
389 | $this->assertEquals(false, $content['is_archived']); | ||
390 | $this->assertEquals(true, $content['is_starred']); | ||
391 | } | ||
392 | |||
393 | public function testPatchEntry() | ||
394 | { | ||
395 | $entry = $this->client->getContainer() | ||
396 | ->get('doctrine.orm.entity_manager') | ||
397 | ->getRepository('WallabagCoreBundle:Entry') | ||
398 | ->findOneByUser(1); | ||
399 | |||
400 | if (!$entry) { | ||
401 | $this->markTestSkipped('No content found in db.'); | ||
402 | } | ||
403 | |||
404 | // hydrate the tags relations | ||
405 | $nbTags = count($entry->getTags()); | ||
406 | |||
407 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
408 | 'title' => 'New awesome title', | ||
409 | 'tags' => 'new tag '.uniqid(), | ||
410 | 'starred' => '1', | ||
411 | 'archive' => '0', | ||
412 | ]); | ||
413 | |||
414 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
415 | |||
416 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
417 | |||
418 | $this->assertEquals($entry->getId(), $content['id']); | ||
419 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
420 | $this->assertEquals('New awesome title', $content['title']); | ||
421 | $this->assertGreaterThan($nbTags, count($content['tags'])); | ||
422 | $this->assertEquals(1, $content['user_id']); | ||
423 | } | ||
424 | |||
425 | public function testPatchEntryWithoutQuotes() | ||
426 | { | ||
427 | $entry = $this->client->getContainer() | ||
428 | ->get('doctrine.orm.entity_manager') | ||
429 | ->getRepository('WallabagCoreBundle:Entry') | ||
430 | ->findOneByUser(1); | ||
431 | |||
432 | if (!$entry) { | ||
433 | $this->markTestSkipped('No content found in db.'); | ||
434 | } | ||
435 | |||
436 | // hydrate the tags relations | ||
437 | $nbTags = count($entry->getTags()); | ||
438 | |||
439 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
440 | 'title' => 'New awesome title', | ||
441 | 'tags' => 'new tag '.uniqid(), | ||
442 | 'starred' => 1, | ||
443 | 'archive' => 0, | ||
444 | ]); | ||
445 | |||
446 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
447 | |||
448 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
449 | |||
450 | $this->assertEquals($entry->getId(), $content['id']); | ||
451 | $this->assertEquals($entry->getUrl(), $content['url']); | ||
452 | $this->assertEquals('New awesome title', $content['title']); | ||
453 | $this->assertGreaterThan($nbTags, count($content['tags'])); | ||
454 | } | ||
455 | |||
456 | public function testGetTagsEntry() | ||
457 | { | ||
458 | $entry = $this->client->getContainer() | ||
459 | ->get('doctrine.orm.entity_manager') | ||
460 | ->getRepository('WallabagCoreBundle:Entry') | ||
461 | ->findOneWithTags($this->user->getId()); | ||
462 | |||
463 | $entry = $entry[0]; | ||
464 | |||
465 | if (!$entry) { | ||
466 | $this->markTestSkipped('No content found in db.'); | ||
467 | } | ||
468 | |||
469 | $tags = []; | ||
470 | foreach ($entry->getTags() as $tag) { | ||
471 | $tags[] = ['id' => $tag->getId(), 'label' => $tag->getLabel(), 'slug' => $tag->getSlug()]; | ||
472 | } | ||
473 | |||
474 | $this->client->request('GET', '/api/entries/'.$entry->getId().'/tags'); | ||
475 | |||
476 | $this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $this->client->getResponse()->getContent()); | ||
477 | } | ||
478 | |||
479 | public function testPostTagsOnEntry() | ||
480 | { | ||
481 | $entry = $this->client->getContainer() | ||
482 | ->get('doctrine.orm.entity_manager') | ||
483 | ->getRepository('WallabagCoreBundle:Entry') | ||
484 | ->findOneByUser(1); | ||
485 | |||
486 | if (!$entry) { | ||
487 | $this->markTestSkipped('No content found in db.'); | ||
488 | } | ||
489 | |||
490 | $nbTags = count($entry->getTags()); | ||
491 | |||
492 | $newTags = 'tag1,tag2,tag3'; | ||
493 | |||
494 | $this->client->request('POST', '/api/entries/'.$entry->getId().'/tags', ['tags' => $newTags]); | ||
495 | |||
496 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
497 | |||
498 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
499 | |||
500 | $this->assertArrayHasKey('tags', $content); | ||
501 | $this->assertEquals($nbTags + 3, count($content['tags'])); | ||
502 | |||
503 | $entryDB = $this->client->getContainer() | ||
504 | ->get('doctrine.orm.entity_manager') | ||
505 | ->getRepository('WallabagCoreBundle:Entry') | ||
506 | ->find($entry->getId()); | ||
507 | |||
508 | $tagsInDB = []; | ||
509 | foreach ($entryDB->getTags()->toArray() as $tag) { | ||
510 | $tagsInDB[$tag->getId()] = $tag->getLabel(); | ||
511 | } | ||
512 | |||
513 | foreach (explode(',', $newTags) as $tag) { | ||
514 | $this->assertContains($tag, $tagsInDB); | ||
515 | } | ||
516 | } | ||
517 | |||
518 | public function testDeleteOneTagEntry() | ||
519 | { | ||
520 | $entry = $this->client->getContainer() | ||
521 | ->get('doctrine.orm.entity_manager') | ||
522 | ->getRepository('WallabagCoreBundle:Entry') | ||
523 | ->findOneWithTags($this->user->getId()); | ||
524 | $entry = $entry[0]; | ||
525 | |||
526 | if (!$entry) { | ||
527 | $this->markTestSkipped('No content found in db.'); | ||
528 | } | ||
529 | |||
530 | // hydrate the tags relations | ||
531 | $nbTags = count($entry->getTags()); | ||
532 | $tag = $entry->getTags()[0]; | ||
533 | |||
534 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json'); | ||
535 | |||
536 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
537 | |||
538 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
539 | |||
540 | $this->assertArrayHasKey('tags', $content); | ||
541 | $this->assertEquals($nbTags - 1, count($content['tags'])); | ||
542 | } | ||
543 | |||
544 | public function testGetUserTags() | ||
545 | { | ||
546 | $this->client->request('GET', '/api/tags.json'); | ||
547 | |||
548 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
549 | |||
550 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
551 | |||
552 | $this->assertGreaterThan(0, $content); | ||
553 | $this->assertArrayHasKey('id', $content[0]); | ||
554 | $this->assertArrayHasKey('label', $content[0]); | ||
555 | |||
556 | return end($content); | ||
557 | } | ||
558 | |||
559 | /** | ||
560 | * @depends testGetUserTags | ||
561 | */ | ||
562 | public function testDeleteUserTag($tag) | ||
563 | { | ||
564 | $tagName = $tag['label']; | ||
565 | |||
566 | $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json'); | ||
567 | |||
568 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
569 | |||
570 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
571 | |||
572 | $this->assertArrayHasKey('label', $content); | ||
573 | $this->assertEquals($tag['label'], $content['label']); | ||
574 | $this->assertEquals($tag['slug'], $content['slug']); | ||
575 | |||
576 | $entries = $this->client->getContainer() | ||
577 | ->get('doctrine.orm.entity_manager') | ||
578 | ->getRepository('WallabagCoreBundle:Entry') | ||
579 | ->findAllByTagId($this->user->getId(), $tag['id']); | ||
580 | |||
581 | $this->assertCount(0, $entries); | ||
582 | |||
583 | $tag = $this->client->getContainer() | ||
584 | ->get('doctrine.orm.entity_manager') | ||
585 | ->getRepository('WallabagCoreBundle:Tag') | ||
586 | ->findOneByLabel($tagName); | ||
587 | |||
588 | $this->assertNull($tag, $tagName.' was removed because it begun an orphan tag'); | ||
589 | } | ||
590 | |||
591 | public function testDeleteTagByLabel() | ||
592 | { | ||
593 | $em = $this->client->getContainer()->get('doctrine.orm.entity_manager'); | ||
594 | $entry = $this->client->getContainer() | ||
595 | ->get('doctrine.orm.entity_manager') | ||
596 | ->getRepository('WallabagCoreBundle:Entry') | ||
597 | ->findOneWithTags($this->user->getId()); | ||
598 | |||
599 | $entry = $entry[0]; | ||
600 | |||
601 | $tag = new Tag(); | ||
602 | $tag->setLabel('Awesome tag for test'); | ||
603 | $em->persist($tag); | ||
604 | |||
605 | $entry->addTag($tag); | ||
606 | |||
607 | $em->persist($entry); | ||
608 | $em->flush(); | ||
609 | |||
610 | $this->client->request('DELETE', '/api/tag/label.json', ['tag' => $tag->getLabel()]); | ||
611 | |||
612 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
613 | |||
614 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
615 | |||
616 | $this->assertArrayHasKey('label', $content); | ||
617 | $this->assertEquals($tag->getLabel(), $content['label']); | ||
618 | $this->assertEquals($tag->getSlug(), $content['slug']); | ||
619 | |||
620 | $entries = $this->client->getContainer() | ||
621 | ->get('doctrine.orm.entity_manager') | ||
622 | ->getRepository('WallabagCoreBundle:Entry') | ||
623 | ->findAllByTagId($this->user->getId(), $tag->getId()); | ||
624 | |||
625 | $this->assertCount(0, $entries); | ||
626 | } | ||
627 | |||
628 | public function testDeleteTagByLabelNotFound() | ||
629 | { | ||
630 | $this->client->request('DELETE', '/api/tag/label.json', ['tag' => 'does not exist']); | ||
631 | |||
632 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); | ||
633 | } | ||
634 | |||
635 | public function testDeleteTagsByLabel() | ||
636 | { | ||
637 | $em = $this->client->getContainer()->get('doctrine.orm.entity_manager'); | ||
638 | $entry = $this->client->getContainer() | ||
639 | ->get('doctrine.orm.entity_manager') | ||
640 | ->getRepository('WallabagCoreBundle:Entry') | ||
641 | ->findOneWithTags($this->user->getId()); | ||
642 | |||
643 | $entry = $entry[0]; | ||
644 | |||
645 | $tag = new Tag(); | ||
646 | $tag->setLabel('Awesome tag for tagsLabel'); | ||
647 | $em->persist($tag); | ||
648 | |||
649 | $tag2 = new Tag(); | ||
650 | $tag2->setLabel('Awesome tag for tagsLabel 2'); | ||
651 | $em->persist($tag2); | ||
652 | |||
653 | $entry->addTag($tag); | ||
654 | $entry->addTag($tag2); | ||
655 | |||
656 | $em->persist($entry); | ||
657 | $em->flush(); | ||
658 | |||
659 | $this->client->request('DELETE', '/api/tags/label.json', ['tags' => $tag->getLabel().','.$tag2->getLabel()]); | ||
660 | |||
661 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
662 | |||
663 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
664 | |||
665 | $this->assertCount(2, $content); | ||
666 | |||
667 | $this->assertArrayHasKey('label', $content[0]); | ||
668 | $this->assertEquals($tag->getLabel(), $content[0]['label']); | ||
669 | $this->assertEquals($tag->getSlug(), $content[0]['slug']); | ||
670 | |||
671 | $this->assertArrayHasKey('label', $content[1]); | ||
672 | $this->assertEquals($tag2->getLabel(), $content[1]['label']); | ||
673 | $this->assertEquals($tag2->getSlug(), $content[1]['slug']); | ||
674 | |||
675 | $entries = $this->client->getContainer() | ||
676 | ->get('doctrine.orm.entity_manager') | ||
677 | ->getRepository('WallabagCoreBundle:Entry') | ||
678 | ->findAllByTagId($this->user->getId(), $tag->getId()); | ||
679 | |||
680 | $this->assertCount(0, $entries); | ||
681 | |||
682 | $entries = $this->client->getContainer() | ||
683 | ->get('doctrine.orm.entity_manager') | ||
684 | ->getRepository('WallabagCoreBundle:Entry') | ||
685 | ->findAllByTagId($this->user->getId(), $tag2->getId()); | ||
686 | |||
687 | $this->assertCount(0, $entries); | ||
688 | } | ||
689 | |||
690 | public function testDeleteTagsByLabelNotFound() | ||
691 | { | ||
692 | $this->client->request('DELETE', '/api/tags/label.json', ['tags' => 'does not exist']); | ||
693 | |||
694 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); | ||
695 | } | ||
696 | |||
697 | public function testGetVersion() | 9 | public function testGetVersion() |
698 | { | 10 | { |
699 | $this->client->request('GET', '/api/version'); | 11 | $this->client->request('GET', '/api/version'); |
@@ -704,136 +16,4 @@ class WallabagRestControllerTest extends WallabagApiTestCase | |||
704 | 16 | ||
705 | $this->assertEquals($this->client->getContainer()->getParameter('wallabag_core.version'), $content); | 17 | $this->assertEquals($this->client->getContainer()->getParameter('wallabag_core.version'), $content); |
706 | } | 18 | } |
707 | |||
708 | public function testSaveIsArchivedAfterPost() | ||
709 | { | ||
710 | $entry = $this->client->getContainer() | ||
711 | ->get('doctrine.orm.entity_manager') | ||
712 | ->getRepository('WallabagCoreBundle:Entry') | ||
713 | ->findOneBy(['user' => 1, 'isArchived' => true]); | ||
714 | |||
715 | if (!$entry) { | ||
716 | $this->markTestSkipped('No content found in db.'); | ||
717 | } | ||
718 | |||
719 | $this->client->request('POST', '/api/entries.json', [ | ||
720 | 'url' => $entry->getUrl(), | ||
721 | ]); | ||
722 | |||
723 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
724 | |||
725 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
726 | |||
727 | $this->assertEquals(true, $content['is_archived']); | ||
728 | } | ||
729 | |||
730 | public function testSaveIsStarredAfterPost() | ||
731 | { | ||
732 | $entry = $this->client->getContainer() | ||
733 | ->get('doctrine.orm.entity_manager') | ||
734 | ->getRepository('WallabagCoreBundle:Entry') | ||
735 | ->findOneBy(['user' => 1, 'isStarred' => true]); | ||
736 | |||
737 | if (!$entry) { | ||
738 | $this->markTestSkipped('No content found in db.'); | ||
739 | } | ||
740 | |||
741 | $this->client->request('POST', '/api/entries.json', [ | ||
742 | 'url' => $entry->getUrl(), | ||
743 | ]); | ||
744 | |||
745 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
746 | |||
747 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
748 | |||
749 | $this->assertEquals(true, $content['is_starred']); | ||
750 | } | ||
751 | |||
752 | public function testSaveIsArchivedAfterPatch() | ||
753 | { | ||
754 | $entry = $this->client->getContainer() | ||
755 | ->get('doctrine.orm.entity_manager') | ||
756 | ->getRepository('WallabagCoreBundle:Entry') | ||
757 | ->findOneBy(['user' => 1, 'isArchived' => true]); | ||
758 | |||
759 | if (!$entry) { | ||
760 | $this->markTestSkipped('No content found in db.'); | ||
761 | } | ||
762 | |||
763 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
764 | 'title' => $entry->getTitle().'++', | ||
765 | ]); | ||
766 | |||
767 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
768 | |||
769 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
770 | |||
771 | $this->assertEquals(true, $content['is_archived']); | ||
772 | } | ||
773 | |||
774 | public function testSaveIsStarredAfterPatch() | ||
775 | { | ||
776 | $entry = $this->client->getContainer() | ||
777 | ->get('doctrine.orm.entity_manager') | ||
778 | ->getRepository('WallabagCoreBundle:Entry') | ||
779 | ->findOneBy(['user' => 1, 'isStarred' => true]); | ||
780 | |||
781 | if (!$entry) { | ||
782 | $this->markTestSkipped('No content found in db.'); | ||
783 | } | ||
784 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', [ | ||
785 | 'title' => $entry->getTitle().'++', | ||
786 | ]); | ||
787 | |||
788 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
789 | |||
790 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
791 | |||
792 | $this->assertEquals(true, $content['is_starred']); | ||
793 | } | ||
794 | |||
795 | public function testGetEntriesExists() | ||
796 | { | ||
797 | $this->client->request('GET', '/api/entries/exists?url=http://0.0.0.0/entry2'); | ||
798 | |||
799 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
800 | |||
801 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
802 | |||
803 | $this->assertEquals(true, $content['exists']); | ||
804 | } | ||
805 | |||
806 | public function testGetEntriesExistsWithManyUrls() | ||
807 | { | ||
808 | $url1 = 'http://0.0.0.0/entry2'; | ||
809 | $url2 = 'http://0.0.0.0/entry10'; | ||
810 | $this->client->request('GET', '/api/entries/exists?urls[]='.$url1.'&urls[]='.$url2); | ||
811 | |||
812 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
813 | |||
814 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
815 | |||
816 | $this->assertArrayHasKey($url1, $content); | ||
817 | $this->assertArrayHasKey($url2, $content); | ||
818 | $this->assertEquals(true, $content[$url1]); | ||
819 | $this->assertEquals(false, $content[$url2]); | ||
820 | } | ||
821 | |||
822 | public function testGetEntriesExistsWhichDoesNotExists() | ||
823 | { | ||
824 | $this->client->request('GET', '/api/entries/exists?url=http://google.com/entry2'); | ||
825 | |||
826 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
827 | |||
828 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
829 | |||
830 | $this->assertEquals(false, $content['exists']); | ||
831 | } | ||
832 | |||
833 | public function testGetEntriesExistsWithNoUrl() | ||
834 | { | ||
835 | $this->client->request('GET', '/api/entries/exists?url='); | ||
836 | |||
837 | $this->assertEquals(403, $this->client->getResponse()->getStatusCode()); | ||
838 | } | ||
839 | } | 19 | } |