diff options
34 files changed, 875 insertions, 228 deletions
diff --git a/app/config/config.yml b/app/config/config.yml index c076aea9..116bb04c 100644 --- a/app/config/config.yml +++ b/app/config/config.yml | |||
@@ -59,6 +59,7 @@ wallabag_core: | |||
59 | list_mode: 0 | 59 | list_mode: 0 |
60 | fetching_error_message: | | 60 | fetching_error_message: | |
61 | wallabag can't retrieve contents for this article. Please <a href="http://doc.wallabag.org/en/master/user/errors_during_fetching.html#how-can-i-help-to-fix-that">troubleshoot this issue</a>. | 61 | wallabag can't retrieve contents for this article. Please <a href="http://doc.wallabag.org/en/master/user/errors_during_fetching.html#how-can-i-help-to-fix-that">troubleshoot this issue</a>. |
62 | api_limit_mass_actions: 10 | ||
62 | 63 | ||
63 | wallabag_user: | 64 | wallabag_user: |
64 | registration_enabled: "%fosuser_registration%" | 65 | registration_enabled: "%fosuser_registration%" |
diff --git a/docs/en/developer/console_commands.rst b/docs/en/developer/console_commands.rst new file mode 100644 index 00000000..85a8a092 --- /dev/null +++ b/docs/en/developer/console_commands.rst | |||
@@ -0,0 +1,30 @@ | |||
1 | Console Commands | ||
2 | ================ | ||
3 | |||
4 | wallabag has a number of CLI commands to manage a number of tasks. You can list all the commands by executing `bin/console` in the wallabag folder. | ||
5 | |||
6 | Each command has a help accessible through `bin/console help %command%`. | ||
7 | |||
8 | .. note:: | ||
9 | |||
10 | If you're in a production environment, remember to add `-e prod` to each command. | ||
11 | |||
12 | Notable commands | ||
13 | ---------------- | ||
14 | |||
15 | * `assets:install`: May be helpful if assets are missing. | ||
16 | * `cache:clear`: should be run after each update (included in `make update`). | ||
17 | * `doctrine:migrations:status`: Output the status of your database migrations. | ||
18 | * `fos:user:activate`: Manually activate an user. | ||
19 | * `fos:user:change-password`: Change a password for an user. | ||
20 | * `fos:user:create`: Create an user. | ||
21 | * `fos:user:deactivate`: Deactivate an user (not deleted). | ||
22 | * `fos:user:demote`: Removes a role from an user, typically admin rights. | ||
23 | * `fos:user:promote`: Adds a role to an user, typically admin rights. | ||
24 | * `rabbitmq:*`: May be useful if you're using RabbitMQ. | ||
25 | * `wallabag:clean-duplicates`: Removes all entry duplicates for one user or all users | ||
26 | * `wallabag:export`: Exports all entries for an user. You can choose the output path of the file. | ||
27 | * `wallabag:import`: Import entries to different formats to an user account. | ||
28 | * `wallabag:import:redis-worker`: Useful if you use Redis. | ||
29 | * `wallabag:install`: (re)Install wallabag | ||
30 | * `wallabag:tag:all`: Tag all entries for an user using his/her tagging rules. | ||
diff --git a/docs/en/user/import.rst b/docs/en/user/import.rst index 50bb1de3..f6aaa373 100644 --- a/docs/en/user/import.rst +++ b/docs/en/user/import.rst | |||
@@ -77,7 +77,7 @@ From Instapaper | |||
77 | --------------- | 77 | --------------- |
78 | 78 | ||
79 | Export your Instapaper data | 79 | Export your Instapaper data |
80 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 80 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
81 | 81 | ||
82 | On the settings (`https://www.instapaper.com/user <https://www.instapaper.com/user>`_) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like ``instapaper-export.csv``). | 82 | On the settings (`https://www.instapaper.com/user <https://www.instapaper.com/user>`_) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like ``instapaper-export.csv``). |
83 | 83 | ||
@@ -133,16 +133,21 @@ If you have a CLI access on your web server, you can execute this command to imp | |||
133 | 133 | ||
134 | :: | 134 | :: |
135 | 135 | ||
136 | bin/console wallabag:import 1 ~/Downloads/wallabag-export-1-2016-04-05.json --env=prod | 136 | bin/console wallabag:import username ~/Downloads/wallabag-export-1-2016-04-05.json --env=prod |
137 | 137 | ||
138 | Please replace values: | 138 | Please replace values: |
139 | 139 | ||
140 | * ``1`` is the user identifier in database (The ID of the first user created on wallabag is 1) | 140 | * ``username`` is the user's username |
141 | * ``~/Downloads/wallabag-export-1-2016-04-05.json`` is the path of your wallabag v1 export | 141 | * ``~/Downloads/wallabag-export-1-2016-04-05.json`` is the path of your wallabag v1 export |
142 | 142 | ||
143 | If you want to mark all these entries as read, you can add the ``--markAsRead`` option. | 143 | .. note:: |
144 | If you want to mark all these entries as read, you can add the ``--markAsRead`` option. | ||
144 | 145 | ||
145 | To import a wallabag v2 file, you need to add the option ``--importer=v2``. | 146 | .. note:: |
147 | To import a wallabag v2 file, you need to add the option ``--importer=v2``. | ||
148 | |||
149 | .. note:: | ||
150 | If you want to pass the user id of the user instead of it's username, add the option ``--useUserId=true``. | ||
146 | 151 | ||
147 | You'll have this in return: | 152 | You'll have this in return: |
148 | 153 | ||
diff --git a/docs/fr/developer/console_commands.rst b/docs/fr/developer/console_commands.rst new file mode 100644 index 00000000..1b222b32 --- /dev/null +++ b/docs/fr/developer/console_commands.rst | |||
@@ -0,0 +1,30 @@ | |||
1 | Actions en ligne de commande | ||
2 | ============================ | ||
3 | |||
4 | wallabag a un certain nombre de commandes CLI pour effectuer des tâches. Vous pouvez lister toutes les commandes en exécutant `bin/console` dans le dossier d'installation de wallabag. | ||
5 | |||
6 | Chaque commande a une aide correspondante accessible via `bin/console help %command%`. | ||
7 | |||
8 | .. note:: | ||
9 | |||
10 | Si vous êtes dans un environnement de production, souvenez-vous d'ajouter `-e prod` à chaque commande. | ||
11 | |||
12 | Commandes notables | ||
13 | ------------------ | ||
14 | |||
15 | * `assets:install`: Peut-être utile si les *assets* sont manquants. | ||
16 | * `cache:clear`: doit être exécuté après chaque mise à jour (appelé dans `make update`). | ||
17 | * `doctrine:migrations:status`: Montre le statut de vos migrations de vos bases de données. | ||
18 | * `fos:user:activate`: Activer manuellement un utilisateur. | ||
19 | * `fos:user:change-password`: Changer le mot de passe pour un utilisateur. | ||
20 | * `fos:user:create`: Créer un utilisateur. | ||
21 | * `fos:user:deactivate`: Désactiver un utilisateur (non supprimé). | ||
22 | * `fos:user:demote`: Supprimer un rôle d'un utilisateur, typiquement les droits d'administration. | ||
23 | * `fos:user:promote`: Ajoute un rôle à un utilisateur, typiquement les droits d'administration. | ||
24 | * `rabbitmq:*`: Peut-être utile si vous utilisez RabbitMQ. | ||
25 | * `wallabag:clean-duplicates`: Supprime tous les articles dupliqués pour un utilisateur ou bien tous. | ||
26 | * `wallabag:export`: Exporte tous les articles pour un utilisateur. Vous pouvez choisir le chemin du fichier exporté. | ||
27 | * `wallabag:import`: Importe les articles en différents formats dans un compte utilisateur. | ||
28 | * `wallabag:import:redis-worker`: Utile si vous utilisez Redis. | ||
29 | * `wallabag:install`: (ré)Installer wallabag | ||
30 | * `wallabag:tag:all`: Tagger tous les articles pour un utilisateur ou une utilisatrice en utilisant ses règles de tags automatiques. | ||
diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php index 7590efbb..dbff6065 100644 --- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php +++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php | |||
@@ -5,6 +5,7 @@ namespace Wallabag\ApiBundle\Controller; | |||
5 | use Hateoas\Configuration\Route; | 5 | use Hateoas\Configuration\Route; |
6 | use Hateoas\Representation\Factory\PagerfantaFactory; | 6 | use Hateoas\Representation\Factory\PagerfantaFactory; |
7 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | 7 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
8 | use Symfony\Component\HttpKernel\Exception\HttpException; | ||
8 | use Symfony\Component\HttpFoundation\Request; | 9 | use Symfony\Component\HttpFoundation\Request; |
9 | use Symfony\Component\HttpFoundation\JsonResponse; | 10 | use Symfony\Component\HttpFoundation\JsonResponse; |
10 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 11 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
@@ -44,9 +45,7 @@ class EntryRestController extends WallabagRestController | |||
44 | $results[$url] = $res instanceof Entry ? $res->getId() : false; | 45 | $results[$url] = $res instanceof Entry ? $res->getId() : false; |
45 | } | 46 | } |
46 | 47 | ||
47 | $json = $this->get('serializer')->serialize($results, 'json'); | 48 | return $this->sendResponse($results); |
48 | |||
49 | return (new JsonResponse())->setJson($json); | ||
50 | } | 49 | } |
51 | 50 | ||
52 | // let's see if it is a simple url? | 51 | // let's see if it is a simple url? |
@@ -62,9 +61,7 @@ class EntryRestController extends WallabagRestController | |||
62 | 61 | ||
63 | $exists = $res instanceof Entry ? $res->getId() : false; | 62 | $exists = $res instanceof Entry ? $res->getId() : false; |
64 | 63 | ||
65 | $json = $this->get('serializer')->serialize(['exists' => $exists], 'json'); | 64 | return $this->sendResponse(['exists' => $exists]); |
66 | |||
67 | return (new JsonResponse())->setJson($json); | ||
68 | } | 65 | } |
69 | 66 | ||
70 | /** | 67 | /** |
@@ -124,9 +121,7 @@ class EntryRestController extends WallabagRestController | |||
124 | ) | 121 | ) |
125 | ); | 122 | ); |
126 | 123 | ||
127 | $json = $this->get('serializer')->serialize($paginatedCollection, 'json'); | 124 | return $this->sendResponse($paginatedCollection); |
128 | |||
129 | return (new JsonResponse())->setJson($json); | ||
130 | } | 125 | } |
131 | 126 | ||
132 | /** | 127 | /** |
@@ -145,9 +140,7 @@ class EntryRestController extends WallabagRestController | |||
145 | $this->validateAuthentication(); | 140 | $this->validateAuthentication(); |
146 | $this->validateUserAccess($entry->getUser()->getId()); | 141 | $this->validateUserAccess($entry->getUser()->getId()); |
147 | 142 | ||
148 | $json = $this->get('serializer')->serialize($entry, 'json'); | 143 | return $this->sendResponse($entry); |
149 | |||
150 | return (new JsonResponse())->setJson($json); | ||
151 | } | 144 | } |
152 | 145 | ||
153 | /** | 146 | /** |
@@ -173,6 +166,110 @@ class EntryRestController extends WallabagRestController | |||
173 | } | 166 | } |
174 | 167 | ||
175 | /** | 168 | /** |
169 | * Handles an entries list and delete URL. | ||
170 | * | ||
171 | * @ApiDoc( | ||
172 | * parameters={ | ||
173 | * {"name"="urls", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...'}, {'url': 'http://...'}]", "description"="Urls (as an array) to delete."} | ||
174 | * } | ||
175 | * ) | ||
176 | * | ||
177 | * @return JsonResponse | ||
178 | */ | ||
179 | public function deleteEntriesListAction(Request $request) | ||
180 | { | ||
181 | $this->validateAuthentication(); | ||
182 | |||
183 | $urls = json_decode($request->query->get('urls', [])); | ||
184 | |||
185 | if (empty($urls)) { | ||
186 | return $this->sendResponse([]); | ||
187 | } | ||
188 | |||
189 | $results = []; | ||
190 | |||
191 | // handle multiple urls | ||
192 | foreach ($urls as $key => $url) { | ||
193 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( | ||
194 | $url, | ||
195 | $this->getUser()->getId() | ||
196 | ); | ||
197 | |||
198 | $results[$key]['url'] = $url; | ||
199 | |||
200 | if (false !== $entry) { | ||
201 | $em = $this->getDoctrine()->getManager(); | ||
202 | $em->remove($entry); | ||
203 | $em->flush(); | ||
204 | |||
205 | // entry deleted, dispatch event about it! | ||
206 | $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); | ||
207 | } | ||
208 | |||
209 | $results[$key]['entry'] = $entry instanceof Entry ? true : false; | ||
210 | } | ||
211 | |||
212 | return $this->sendResponse($results); | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * Handles an entries list and create URL. | ||
217 | * | ||
218 | * @ApiDoc( | ||
219 | * parameters={ | ||
220 | * {"name"="urls", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...'}, {'url': 'http://...'}]", "description"="Urls (as an array) to create."} | ||
221 | * } | ||
222 | * ) | ||
223 | * | ||
224 | * @return JsonResponse | ||
225 | * | ||
226 | * @throws HttpException When limit is reached | ||
227 | */ | ||
228 | public function postEntriesListAction(Request $request) | ||
229 | { | ||
230 | $this->validateAuthentication(); | ||
231 | |||
232 | $urls = json_decode($request->query->get('urls', [])); | ||
233 | $results = []; | ||
234 | |||
235 | $limit = $this->container->getParameter('wallabag_core.api_limit_mass_actions'); | ||
236 | |||
237 | if (count($urls) > $limit) { | ||
238 | throw new HttpException(400, 'API limit reached'); | ||
239 | } | ||
240 | |||
241 | // handle multiple urls | ||
242 | if (!empty($urls)) { | ||
243 | foreach ($urls as $key => $url) { | ||
244 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( | ||
245 | $url, | ||
246 | $this->getUser()->getId() | ||
247 | ); | ||
248 | |||
249 | $results[$key]['url'] = $url; | ||
250 | |||
251 | if (false === $entry) { | ||
252 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry( | ||
253 | new Entry($this->getUser()), | ||
254 | $url | ||
255 | ); | ||
256 | } | ||
257 | |||
258 | $em = $this->getDoctrine()->getManager(); | ||
259 | $em->persist($entry); | ||
260 | $em->flush(); | ||
261 | |||
262 | $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; | ||
263 | |||
264 | // entry saved, dispatch event about it! | ||
265 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | return $this->sendResponse($results); | ||
270 | } | ||
271 | |||
272 | /** | ||
176 | * Create an entry. | 273 | * Create an entry. |
177 | * | 274 | * |
178 | * @ApiDoc( | 275 | * @ApiDoc( |
@@ -229,9 +326,7 @@ class EntryRestController extends WallabagRestController | |||
229 | // entry saved, dispatch event about it! | 326 | // entry saved, dispatch event about it! |
230 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | 327 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); |
231 | 328 | ||
232 | $json = $this->get('serializer')->serialize($entry, 'json'); | 329 | return $this->sendResponse($entry); |
233 | |||
234 | return (new JsonResponse())->setJson($json); | ||
235 | } | 330 | } |
236 | 331 | ||
237 | /** | 332 | /** |
@@ -280,9 +375,7 @@ class EntryRestController extends WallabagRestController | |||
280 | $em = $this->getDoctrine()->getManager(); | 375 | $em = $this->getDoctrine()->getManager(); |
281 | $em->flush(); | 376 | $em->flush(); |
282 | 377 | ||
283 | $json = $this->get('serializer')->serialize($entry, 'json'); | 378 | return $this->sendResponse($entry); |
284 | |||
285 | return (new JsonResponse())->setJson($json); | ||
286 | } | 379 | } |
287 | 380 | ||
288 | /** | 381 | /** |
@@ -325,9 +418,7 @@ class EntryRestController extends WallabagRestController | |||
325 | // entry saved, dispatch event about it! | 418 | // entry saved, dispatch event about it! |
326 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | 419 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); |
327 | 420 | ||
328 | $json = $this->get('serializer')->serialize($entry, 'json'); | 421 | return $this->sendResponse($entry); |
329 | |||
330 | return (new JsonResponse())->setJson($json); | ||
331 | } | 422 | } |
332 | 423 | ||
333 | /** | 424 | /** |
@@ -353,9 +444,7 @@ class EntryRestController extends WallabagRestController | |||
353 | // entry deleted, dispatch event about it! | 444 | // entry deleted, dispatch event about it! |
354 | $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); | 445 | $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); |
355 | 446 | ||
356 | $json = $this->get('serializer')->serialize($entry, 'json'); | 447 | return $this->sendResponse($entry); |
357 | |||
358 | return (new JsonResponse())->setJson($json); | ||
359 | } | 448 | } |
360 | 449 | ||
361 | /** | 450 | /** |
@@ -374,9 +463,7 @@ class EntryRestController extends WallabagRestController | |||
374 | $this->validateAuthentication(); | 463 | $this->validateAuthentication(); |
375 | $this->validateUserAccess($entry->getUser()->getId()); | 464 | $this->validateUserAccess($entry->getUser()->getId()); |
376 | 465 | ||
377 | $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); | 466 | return $this->sendResponse($entry->getTags()); |
378 | |||
379 | return (new JsonResponse())->setJson($json); | ||
380 | } | 467 | } |
381 | 468 | ||
382 | /** | 469 | /** |
@@ -407,9 +494,7 @@ class EntryRestController extends WallabagRestController | |||
407 | $em->persist($entry); | 494 | $em->persist($entry); |
408 | $em->flush(); | 495 | $em->flush(); |
409 | 496 | ||
410 | $json = $this->get('serializer')->serialize($entry, 'json'); | 497 | return $this->sendResponse($entry); |
411 | |||
412 | return (new JsonResponse())->setJson($json); | ||
413 | } | 498 | } |
414 | 499 | ||
415 | /** | 500 | /** |
@@ -434,9 +519,7 @@ class EntryRestController extends WallabagRestController | |||
434 | $em->persist($entry); | 519 | $em->persist($entry); |
435 | $em->flush(); | 520 | $em->flush(); |
436 | 521 | ||
437 | $json = $this->get('serializer')->serialize($entry, 'json'); | 522 | return $this->sendResponse($entry); |
438 | |||
439 | return (new JsonResponse())->setJson($json); | ||
440 | } | 523 | } |
441 | 524 | ||
442 | /** | 525 | /** |
@@ -455,45 +538,46 @@ class EntryRestController extends WallabagRestController | |||
455 | $this->validateAuthentication(); | 538 | $this->validateAuthentication(); |
456 | 539 | ||
457 | $list = json_decode($request->query->get('list', [])); | 540 | $list = json_decode($request->query->get('list', [])); |
458 | $results = []; | 541 | |
542 | if (empty($list)) { | ||
543 | return $this->sendResponse([]); | ||
544 | } | ||
459 | 545 | ||
460 | // handle multiple urls | 546 | // handle multiple urls |
461 | if (!empty($list)) { | 547 | $results = []; |
462 | foreach ($list as $key => $element) { | ||
463 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( | ||
464 | $element->url, | ||
465 | $this->getUser()->getId() | ||
466 | ); | ||
467 | 548 | ||
468 | $results[$key]['url'] = $element->url; | 549 | foreach ($list as $key => $element) { |
469 | $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; | 550 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( |
551 | $element->url, | ||
552 | $this->getUser()->getId() | ||
553 | ); | ||
470 | 554 | ||
471 | $tags = $element->tags; | 555 | $results[$key]['url'] = $element->url; |
556 | $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; | ||
472 | 557 | ||
473 | if (false !== $entry && !(empty($tags))) { | 558 | $tags = $element->tags; |
474 | $tags = explode(',', $tags); | ||
475 | foreach ($tags as $label) { | ||
476 | $label = trim($label); | ||
477 | 559 | ||
478 | $tag = $this->getDoctrine() | 560 | if (false !== $entry && !(empty($tags))) { |
479 | ->getRepository('WallabagCoreBundle:Tag') | 561 | $tags = explode(',', $tags); |
480 | ->findOneByLabel($label); | 562 | foreach ($tags as $label) { |
563 | $label = trim($label); | ||
481 | 564 | ||
482 | if (false !== $tag) { | 565 | $tag = $this->getDoctrine() |
483 | $entry->removeTag($tag); | 566 | ->getRepository('WallabagCoreBundle:Tag') |
484 | } | 567 | ->findOneByLabel($label); |
485 | } | ||
486 | 568 | ||
487 | $em = $this->getDoctrine()->getManager(); | 569 | if (false !== $tag) { |
488 | $em->persist($entry); | 570 | $entry->removeTag($tag); |
489 | $em->flush(); | 571 | } |
490 | } | 572 | } |
573 | |||
574 | $em = $this->getDoctrine()->getManager(); | ||
575 | $em->persist($entry); | ||
576 | $em->flush(); | ||
491 | } | 577 | } |
492 | } | 578 | } |
493 | 579 | ||
494 | $json = $this->get('serializer')->serialize($results, 'json'); | 580 | return $this->sendResponse($results); |
495 | |||
496 | return (new JsonResponse())->setJson($json); | ||
497 | } | 581 | } |
498 | 582 | ||
499 | /** | 583 | /** |
@@ -512,32 +596,47 @@ class EntryRestController extends WallabagRestController | |||
512 | $this->validateAuthentication(); | 596 | $this->validateAuthentication(); |
513 | 597 | ||
514 | $list = json_decode($request->query->get('list', [])); | 598 | $list = json_decode($request->query->get('list', [])); |
599 | |||
600 | if (empty($list)) { | ||
601 | return $this->sendResponse([]); | ||
602 | } | ||
603 | |||
515 | $results = []; | 604 | $results = []; |
516 | 605 | ||
517 | // handle multiple urls | 606 | // handle multiple urls |
518 | if (!empty($list)) { | 607 | foreach ($list as $key => $element) { |
519 | foreach ($list as $key => $element) { | 608 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( |
520 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( | 609 | $element->url, |
521 | $element->url, | 610 | $this->getUser()->getId() |
522 | $this->getUser()->getId() | 611 | ); |
523 | ); | ||
524 | 612 | ||
525 | $results[$key]['url'] = $element->url; | 613 | $results[$key]['url'] = $element->url; |
526 | $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; | 614 | $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; |
527 | 615 | ||
528 | $tags = $element->tags; | 616 | $tags = $element->tags; |
529 | 617 | ||
530 | if (false !== $entry && !(empty($tags))) { | 618 | if (false !== $entry && !(empty($tags))) { |
531 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); | 619 | $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); |
532 | 620 | ||
533 | $em = $this->getDoctrine()->getManager(); | 621 | $em = $this->getDoctrine()->getManager(); |
534 | $em->persist($entry); | 622 | $em->persist($entry); |
535 | $em->flush(); | 623 | $em->flush(); |
536 | } | ||
537 | } | 624 | } |
538 | } | 625 | } |
539 | 626 | ||
540 | $json = $this->get('serializer')->serialize($results, 'json'); | 627 | return $this->sendResponse($results); |
628 | } | ||
629 | |||
630 | /** | ||
631 | * Shortcut to send data serialized in json. | ||
632 | * | ||
633 | * @param mixed $data | ||
634 | * | ||
635 | * @return JsonResponse | ||
636 | */ | ||
637 | private function sendResponse($data) | ||
638 | { | ||
639 | $json = $this->get('serializer')->serialize($data, 'json'); | ||
541 | 640 | ||
542 | return (new JsonResponse())->setJson($json); | 641 | return (new JsonResponse())->setJson($json); |
543 | } | 642 | } |
diff --git a/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php b/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php new file mode 100644 index 00000000..65f35d8e --- /dev/null +++ b/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php | |||
@@ -0,0 +1,119 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Command; | ||
4 | |||
5 | use Doctrine\ORM\NoResultException; | ||
6 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; | ||
7 | use Symfony\Component\Console\Input\InputArgument; | ||
8 | use Symfony\Component\Console\Input\InputInterface; | ||
9 | use Symfony\Component\Console\Output\OutputInterface; | ||
10 | use Wallabag\CoreBundle\Entity\Entry; | ||
11 | use Wallabag\UserBundle\Entity\User; | ||
12 | |||
13 | class CleanDuplicatesCommand extends ContainerAwareCommand | ||
14 | { | ||
15 | /** @var OutputInterface */ | ||
16 | protected $output; | ||
17 | |||
18 | protected $duplicates = 0; | ||
19 | |||
20 | protected function configure() | ||
21 | { | ||
22 | $this | ||
23 | ->setName('wallabag:clean-duplicates') | ||
24 | ->setDescription('Cleans the database for duplicates') | ||
25 | ->setHelp('This command helps you to clean your articles list in case of duplicates') | ||
26 | ->addArgument( | ||
27 | 'username', | ||
28 | InputArgument::OPTIONAL, | ||
29 | 'User to clean' | ||
30 | ); | ||
31 | } | ||
32 | |||
33 | protected function execute(InputInterface $input, OutputInterface $output) | ||
34 | { | ||
35 | $this->output = $output; | ||
36 | |||
37 | $username = $input->getArgument('username'); | ||
38 | |||
39 | if ($username) { | ||
40 | try { | ||
41 | $user = $this->getUser($username); | ||
42 | $this->cleanDuplicates($user); | ||
43 | } catch (NoResultException $e) { | ||
44 | $output->writeln(sprintf('<error>User "%s" not found.</error>', $username)); | ||
45 | |||
46 | return 1; | ||
47 | } | ||
48 | } else { | ||
49 | $users = $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findAll(); | ||
50 | |||
51 | $output->writeln(sprintf('Cleaning through %d user accounts', count($users))); | ||
52 | |||
53 | foreach ($users as $user) { | ||
54 | $output->writeln(sprintf('Processing user %s', $user->getUsername())); | ||
55 | $this->cleanDuplicates($user); | ||
56 | } | ||
57 | $output->writeln(sprintf('Finished cleaning. %d duplicates found in total', $this->duplicates)); | ||
58 | } | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * @param User $user | ||
65 | */ | ||
66 | private function cleanDuplicates(User $user) | ||
67 | { | ||
68 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); | ||
69 | $repo = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry'); | ||
70 | |||
71 | $entries = $repo->getAllEntriesIdAndUrl($user->getId()); | ||
72 | |||
73 | $duplicatesCount = 0; | ||
74 | $urls = []; | ||
75 | foreach ($entries as $entry) { | ||
76 | $url = $this->similarUrl($entry['url']); | ||
77 | |||
78 | /* @var $entry Entry */ | ||
79 | if (in_array($url, $urls)) { | ||
80 | ++$duplicatesCount; | ||
81 | |||
82 | $em->remove($repo->find($entry['id'])); | ||
83 | $em->flush(); // Flushing at the end of the loop would require the instance not being online | ||
84 | } else { | ||
85 | $urls[] = $entry['url']; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | $this->duplicates += $duplicatesCount; | ||
90 | |||
91 | $this->output->writeln(sprintf('Cleaned %d duplicates for user %s', $duplicatesCount, $user->getUserName())); | ||
92 | } | ||
93 | |||
94 | private function similarUrl($url) | ||
95 | { | ||
96 | if (in_array(substr($url, -1), ['/', '#'])) { // get rid of "/" and "#" and the end of urls | ||
97 | return substr($url, 0, strlen($url)); | ||
98 | } | ||
99 | |||
100 | return $url; | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * Fetches a user from its username. | ||
105 | * | ||
106 | * @param string $username | ||
107 | * | ||
108 | * @return \Wallabag\UserBundle\Entity\User | ||
109 | */ | ||
110 | private function getUser($username) | ||
111 | { | ||
112 | return $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findOneByUserName($username); | ||
113 | } | ||
114 | |||
115 | private function getDoctrine() | ||
116 | { | ||
117 | return $this->getContainer()->get('doctrine'); | ||
118 | } | ||
119 | } | ||
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php index 3c4d3f25..0d9364f6 100644 --- a/src/Wallabag/CoreBundle/Command/InstallCommand.php +++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php | |||
@@ -63,6 +63,7 @@ class InstallCommand extends ContainerAwareCommand | |||
63 | ->setupDatabase() | 63 | ->setupDatabase() |
64 | ->setupAdmin() | 64 | ->setupAdmin() |
65 | ->setupConfig() | 65 | ->setupConfig() |
66 | ->runMigrations() | ||
66 | ; | 67 | ; |
67 | 68 | ||
68 | $output->writeln('<info>wallabag has been successfully installed.</info>'); | 69 | $output->writeln('<info>wallabag has been successfully installed.</info>'); |
@@ -71,7 +72,7 @@ class InstallCommand extends ContainerAwareCommand | |||
71 | 72 | ||
72 | protected function checkRequirements() | 73 | protected function checkRequirements() |
73 | { | 74 | { |
74 | $this->defaultOutput->writeln('<info><comment>Step 1 of 4.</comment> Checking system requirements.</info>'); | 75 | $this->defaultOutput->writeln('<info><comment>Step 1 of 5.</comment> Checking system requirements.</info>'); |
75 | $doctrineManager = $this->getContainer()->get('doctrine')->getManager(); | 76 | $doctrineManager = $this->getContainer()->get('doctrine')->getManager(); |
76 | 77 | ||
77 | $rows = []; | 78 | $rows = []; |
@@ -175,11 +176,11 @@ class InstallCommand extends ContainerAwareCommand | |||
175 | 176 | ||
176 | protected function setupDatabase() | 177 | protected function setupDatabase() |
177 | { | 178 | { |
178 | $this->defaultOutput->writeln('<info><comment>Step 2 of 4.</comment> Setting up database.</info>'); | 179 | $this->defaultOutput->writeln('<info><comment>Step 2 of 5.</comment> Setting up database.</info>'); |
179 | 180 | ||
180 | // user want to reset everything? Don't care about what is already here | 181 | // user want to reset everything? Don't care about what is already here |
181 | if (true === $this->defaultInput->getOption('reset')) { | 182 | if (true === $this->defaultInput->getOption('reset')) { |
182 | $this->defaultOutput->writeln('Droping database, creating database and schema, clearing the cache'); | 183 | $this->defaultOutput->writeln('Dropping database, creating database and schema, clearing the cache'); |
183 | 184 | ||
184 | $this | 185 | $this |
185 | ->runCommand('doctrine:database:drop', ['--force' => true]) | 186 | ->runCommand('doctrine:database:drop', ['--force' => true]) |
@@ -211,7 +212,7 @@ class InstallCommand extends ContainerAwareCommand | |||
211 | $question = new ConfirmationQuestion('It appears that your database already exists. Would you like to reset it? (y/N)', false); | 212 | $question = new ConfirmationQuestion('It appears that your database already exists. Would you like to reset it? (y/N)', false); |
212 | 213 | ||
213 | if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { | 214 | if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { |
214 | $this->defaultOutput->writeln('Droping database, creating database and schema'); | 215 | $this->defaultOutput->writeln('Dropping database, creating database and schema'); |
215 | 216 | ||
216 | $this | 217 | $this |
217 | ->runCommand('doctrine:database:drop', ['--force' => true]) | 218 | ->runCommand('doctrine:database:drop', ['--force' => true]) |
@@ -221,7 +222,7 @@ class InstallCommand extends ContainerAwareCommand | |||
221 | } elseif ($this->isSchemaPresent()) { | 222 | } elseif ($this->isSchemaPresent()) { |
222 | $question = new ConfirmationQuestion('Seems like your database contains schema. Do you want to reset it? (y/N)', false); | 223 | $question = new ConfirmationQuestion('Seems like your database contains schema. Do you want to reset it? (y/N)', false); |
223 | if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { | 224 | if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { |
224 | $this->defaultOutput->writeln('Droping schema and creating schema'); | 225 | $this->defaultOutput->writeln('Dropping schema and creating schema'); |
225 | 226 | ||
226 | $this | 227 | $this |
227 | ->runCommand('doctrine:schema:drop', ['--force' => true]) | 228 | ->runCommand('doctrine:schema:drop', ['--force' => true]) |
@@ -246,7 +247,7 @@ class InstallCommand extends ContainerAwareCommand | |||
246 | 247 | ||
247 | protected function setupAdmin() | 248 | protected function setupAdmin() |
248 | { | 249 | { |
249 | $this->defaultOutput->writeln('<info><comment>Step 3 of 4.</comment> Administration setup.</info>'); | 250 | $this->defaultOutput->writeln('<info><comment>Step 3 of 5.</comment> Administration setup.</info>'); |
250 | 251 | ||
251 | $questionHelper = $this->getHelperSet()->get('question'); | 252 | $questionHelper = $this->getHelperSet()->get('question'); |
252 | $question = new ConfirmationQuestion('Would you like to create a new admin user (recommended) ? (Y/n)', true); | 253 | $question = new ConfirmationQuestion('Would you like to create a new admin user (recommended) ? (Y/n)', true); |
@@ -285,7 +286,7 @@ class InstallCommand extends ContainerAwareCommand | |||
285 | 286 | ||
286 | protected function setupConfig() | 287 | protected function setupConfig() |
287 | { | 288 | { |
288 | $this->defaultOutput->writeln('<info><comment>Step 4 of 4.</comment> Config setup.</info>'); | 289 | $this->defaultOutput->writeln('<info><comment>Step 4 of 5.</comment> Config setup.</info>'); |
289 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); | 290 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); |
290 | 291 | ||
291 | // cleanup before insert new stuff | 292 | // cleanup before insert new stuff |
@@ -464,6 +465,14 @@ class InstallCommand extends ContainerAwareCommand | |||
464 | return $this; | 465 | return $this; |
465 | } | 466 | } |
466 | 467 | ||
468 | protected function runMigrations() | ||
469 | { | ||
470 | $this->defaultOutput->writeln('<info><comment>Step 5 of 5.</comment> Run migrations.</info>'); | ||
471 | |||
472 | $this | ||
473 | ->runCommand('doctrine:migrations:migrate', ['--no-interaction' => true]); | ||
474 | } | ||
475 | |||
467 | /** | 476 | /** |
468 | * Run a command. | 477 | * Run a command. |
469 | * | 478 | * |
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php index 006a18c3..75b37729 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php | |||
@@ -47,6 +47,9 @@ class Configuration implements ConfigurationInterface | |||
47 | ->scalarNode('list_mode') | 47 | ->scalarNode('list_mode') |
48 | ->defaultValue(1) | 48 | ->defaultValue(1) |
49 | ->end() | 49 | ->end() |
50 | ->scalarNode('api_limit_mass_actions') | ||
51 | ->defaultValue(10) | ||
52 | ->end() | ||
50 | ->end() | 53 | ->end() |
51 | ; | 54 | ; |
52 | 55 | ||
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php index aa9ee339..c075c19f 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php | |||
@@ -26,6 +26,7 @@ class WallabagCoreExtension extends Extension | |||
26 | $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']); | 26 | $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']); |
27 | $container->setParameter('wallabag_core.list_mode', $config['list_mode']); | 27 | $container->setParameter('wallabag_core.list_mode', $config['list_mode']); |
28 | $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']); | 28 | $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']); |
29 | $container->setParameter('wallabag_core.api_limit_mass_actions', $config['api_limit_mass_actions']); | ||
29 | 30 | ||
30 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | 31 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
31 | $loader->load('services.yml'); | 32 | $loader->load('services.yml'); |
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php index 1f22e901..6972e974 100644 --- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php | |||
@@ -379,4 +379,34 @@ class EntryRepository extends EntityRepository | |||
379 | ->setParameter('userId', $userId) | 379 | ->setParameter('userId', $userId) |
380 | ->execute(); | 380 | ->execute(); |
381 | } | 381 | } |
382 | |||
383 | /** | ||
384 | * Get id and url from all entries | ||
385 | * Used for the clean-duplicates command. | ||
386 | */ | ||
387 | public function getAllEntriesIdAndUrl($userId) | ||
388 | { | ||
389 | $qb = $this->createQueryBuilder('e') | ||
390 | ->select('e.id, e.url') | ||
391 | ->where('e.user = :userid')->setParameter(':userid', $userId); | ||
392 | |||
393 | return $qb->getQuery()->getArrayResult(); | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * Find all entries by url and owner. | ||
398 | * | ||
399 | * @param $url | ||
400 | * @param $userId | ||
401 | * | ||
402 | * @return array | ||
403 | */ | ||
404 | public function findAllByUrlAndUserId($url, $userId) | ||
405 | { | ||
406 | return $this->createQueryBuilder('e') | ||
407 | ->where('e.url = :url')->setParameter('url', urldecode($url)) | ||
408 | ->andWhere('e.user = :user_id')->setParameter('user_id', $userId) | ||
409 | ->getQuery() | ||
410 | ->getResult(); | ||
411 | } | ||
382 | } | 412 | } |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml index e5211b57..57319af7 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml | |||
@@ -512,6 +512,8 @@ user: | |||
512 | # delete: Delete | 512 | # delete: Delete |
513 | # delete_confirm: Are you sure? | 513 | # delete_confirm: Are you sure? |
514 | # back_to_list: Back to list | 514 | # back_to_list: Back to list |
515 | search: | ||
516 | # placeholder: Filter by username or email | ||
515 | 517 | ||
516 | error: | 518 | error: |
517 | # page_title: An error occurred | 519 | # page_title: An error occurred |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml index 893a4564..a7bcecc6 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | delete: Löschen | 513 | delete: Löschen |
514 | delete_confirm: Bist du sicher? | 514 | delete_confirm: Bist du sicher? |
515 | back_to_list: Zurück zur Liste | 515 | back_to_list: Zurück zur Liste |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | page_title: Ein Fehler ist aufgetreten | 520 | page_title: Ein Fehler ist aufgetreten |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml index 4b745683..1ef2874d 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | delete: Delete | 513 | delete: Delete |
514 | delete_confirm: Are you sure? | 514 | delete_confirm: Are you sure? |
515 | back_to_list: Back to list | 515 | back_to_list: Back to list |
516 | search: | ||
517 | placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | page_title: An error occurred | 520 | page_title: An error occurred |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml index 99d25859..6cd079b0 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | delete: Eliminar | 513 | delete: Eliminar |
514 | delete_confirm: ¿Estás seguro? | 514 | delete_confirm: ¿Estás seguro? |
515 | back_to_list: Volver a la lista | 515 | back_to_list: Volver a la lista |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | page_title: Ha ocurrido un error | 520 | page_title: Ha ocurrido un error |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml index ccd9d555..fb6e315e 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | # delete: Delete | 513 | # delete: Delete |
514 | # delete_confirm: Are you sure? | 514 | # delete_confirm: Are you sure? |
515 | # back_to_list: Back to list | 515 | # back_to_list: Back to list |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | # page_title: An error occurred | 520 | # page_title: An error occurred |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml index a0f100f7..ad886363 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml | |||
@@ -46,7 +46,7 @@ footer: | |||
46 | social: "Social" | 46 | social: "Social" |
47 | powered_by: "propulsé par" | 47 | powered_by: "propulsé par" |
48 | about: "À propos" | 48 | about: "À propos" |
49 | stats: Depuis le %user_creation%, vous avez lu %nb_archives% articles. Ce qui fait %per_day% par jour ! | 49 | stats: "Depuis le %user_creation%, vous avez lu %nb_archives% articles. Ce qui fait %per_day% par jour !" |
50 | 50 | ||
51 | config: | 51 | config: |
52 | page_title: "Configuration" | 52 | page_title: "Configuration" |
@@ -71,16 +71,16 @@ config: | |||
71 | 300_word: "Je lis environ 300 mots par minute" | 71 | 300_word: "Je lis environ 300 mots par minute" |
72 | 400_word: "Je lis environ 400 mots par minute" | 72 | 400_word: "Je lis environ 400 mots par minute" |
73 | action_mark_as_read: | 73 | action_mark_as_read: |
74 | label: 'Où souhaitez-vous être redirigé après avoir marqué un article comme lu ?' | 74 | label: "Où souhaitez-vous être redirigé après avoir marqué un article comme lu ?" |
75 | redirect_homepage: "À la page d'accueil" | 75 | redirect_homepage: "À la page d’accueil" |
76 | redirect_current_page: 'À la page courante' | 76 | redirect_current_page: "À la page courante" |
77 | pocket_consumer_key_label: Clé d’authentification Pocket pour importer les données | 77 | pocket_consumer_key_label: "Clé d’authentification Pocket pour importer les données" |
78 | android_configuration: Configurez votre application Android | 78 | android_configuration: "Configurez votre application Android" |
79 | help_theme: "L'affichage de wallabag est personnalisable. C'est ici que vous choisissez le thème que vous préférez." | 79 | help_theme: "L’affichage de wallabag est personnalisable. C’est ici que vous choisissez le thème que vous préférez." |
80 | help_items_per_page: "Vous pouvez définir le nombre d'articles affichés sur chaque page." | 80 | help_items_per_page: "Vous pouvez définir le nombre d’articles affichés sur chaque page." |
81 | help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article." | 81 | help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article." |
82 | help_language: "Vous pouvez définir la langue de l'interface de wallabag." | 82 | help_language: "Vous pouvez définir la langue de l’interface de wallabag." |
83 | help_pocket_consumer_key: "Nécessaire pour l'import depuis Pocket. Vous pouvez le créer depuis votre compte Pocket." | 83 | help_pocket_consumer_key: "Nécessaire pour l’import depuis Pocket. Vous pouvez le créer depuis votre compte Pocket." |
84 | form_rss: | 84 | form_rss: |
85 | description: "Les flux RSS fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton." | 85 | description: "Les flux RSS fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton." |
86 | token_label: "Jeton RSS" | 86 | token_label: "Jeton RSS" |
@@ -100,18 +100,18 @@ config: | |||
100 | twoFactorAuthentication_label: "Double authentification" | 100 | twoFactorAuthentication_label: "Double authentification" |
101 | help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email." | 101 | help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email." |
102 | delete: | 102 | delete: |
103 | title: Supprimer mon compte (attention danger !) | 103 | title: "Supprimer mon compte (attention danger !)" |
104 | description: Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c'est IRRÉVERSIBLE). Vous serez ensuite déconnecté. | 104 | description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c’est IRRÉVERSIBLE). Vous serez ensuite déconnecté." |
105 | confirm: Vous êtes vraiment sûr ? (C'EST IRRÉVERSIBLE) | 105 | confirm: "Vous êtes vraiment sûr ? (C’EST IRRÉVERSIBLE)" |
106 | button: 'Supprimer mon compte' | 106 | button: "Supprimer mon compte" |
107 | reset: | 107 | reset: |
108 | title: Réinitialisation (attention danger !) | 108 | title: "Réinitialisation (attention danger !)" |
109 | description: En cliquant sur les boutons ci-dessous vous avez la possibilité de supprimer certaines informations de votre compte. Attention, ces actions sont IRRÉVERSIBLES ! | 109 | description: "En cliquant sur les boutons ci-dessous vous avez la possibilité de supprimer certaines informations de votre compte. Attention, ces actions sont IRRÉVERSIBLES !" |
110 | annotations: Supprimer TOUTES les annotations | 110 | annotations: "Supprimer TOUTES les annotations" |
111 | tags: Supprimer TOUS les tags | 111 | tags: "Supprimer TOUS les tags" |
112 | entries: Supprimer TOUS les articles | 112 | entries: "Supprimer TOUS les articles" |
113 | archived: Supprimer TOUS les articles archivés | 113 | archived: "Supprimer TOUS les articles archivés" |
114 | confirm: Êtes-vous vraiment vraiment sûr ? (C'EST IRRÉVERSIBLE) | 114 | confirm: "Êtes-vous vraiment vraiment sûr ? (C’EST IRRÉVERSIBLE)" |
115 | form_password: | 115 | form_password: |
116 | description: "Vous pouvez changer ici votre mot de passe. Le mot de passe doit contenir au moins 8 caractères." | 116 | description: "Vous pouvez changer ici votre mot de passe. Le mot de passe doit contenir au moins 8 caractères." |
117 | old_password_label: "Mot de passe actuel" | 117 | old_password_label: "Mot de passe actuel" |
@@ -164,7 +164,7 @@ entry: | |||
164 | archived: "Articles lus" | 164 | archived: "Articles lus" |
165 | filtered: "Articles filtrés" | 165 | filtered: "Articles filtrés" |
166 | filtered_tags: "Articles filtrés par tags :" | 166 | filtered_tags: "Articles filtrés par tags :" |
167 | filtered_search: 'Articles filtrés par recherche :' | 167 | filtered_search: "Articles filtrés par recherche :" |
168 | untagged: "Article sans tag" | 168 | untagged: "Article sans tag" |
169 | list: | 169 | list: |
170 | number_on_the_page: "{0} Il n’y a pas d’article.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles." | 170 | number_on_the_page: "{0} Il n’y a pas d’article.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles." |
@@ -188,7 +188,7 @@ entry: | |||
188 | preview_picture_label: "A une photo" | 188 | preview_picture_label: "A une photo" |
189 | preview_picture_help: "Photo" | 189 | preview_picture_help: "Photo" |
190 | language_label: "Langue" | 190 | language_label: "Langue" |
191 | http_status_label: 'Statut HTTP' | 191 | http_status_label: "Statut HTTP" |
192 | reading_time: | 192 | reading_time: |
193 | label: "Durée de lecture en minutes" | 193 | label: "Durée de lecture en minutes" |
194 | from: "de" | 194 | from: "de" |
@@ -298,32 +298,32 @@ howto: | |||
298 | bookmarklet: | 298 | bookmarklet: |
299 | description: "Glissez et déposez ce lien dans votre barre de favoris :" | 299 | description: "Glissez et déposez ce lien dans votre barre de favoris :" |
300 | shortcuts: | 300 | shortcuts: |
301 | page_description: Voici les raccourcis disponibles dans wallabag. | 301 | page_description: "Voici les raccourcis disponibles dans wallabag." |
302 | shortcut: Raccourci | 302 | shortcut: "Raccourci" |
303 | action: Action | 303 | action: "Action" |
304 | all_pages_title: Raccourcis disponibles dans toutes les pages | 304 | all_pages_title: "Raccourcis disponibles dans toutes les pages" |
305 | go_unread: Afficher les articles non lus | 305 | go_unread: "Afficher les articles non lus" |
306 | go_starred: Afficher les articles favoris | 306 | go_starred: "Afficher les articles favoris" |
307 | go_archive: Afficher les articles lus | 307 | go_archive: "Afficher les articles lus" |
308 | go_all: Afficher tous les articles | 308 | go_all: "Afficher tous les articles" |
309 | go_tags: Afficher les tags | 309 | go_tags: "Afficher les tags" |
310 | go_config: Aller à la configuration | 310 | go_config: "Aller à la configuration" |
311 | go_import: Aller aux imports | 311 | go_import: "Aller aux imports" |
312 | go_developers: Aller à la section Développeurs | 312 | go_developers: "Aller à la section Développeurs" |
313 | go_howto: Afficher l'aide (cette page !) | 313 | go_howto: "Afficher l’aide (cette page !)" |
314 | go_logout: Se déconnecter | 314 | go_logout: "Se déconnecter" |
315 | list_title: Raccourcis disponibles dans les pages de liste | 315 | list_title: "Raccourcis disponibles dans les pages de liste" |
316 | search: Afficher le formulaire de recherche | 316 | search: "Afficher le formulaire de recherche" |
317 | article_title: Raccourcis disponibles quand on affiche un article | 317 | article_title: "Raccourcis disponibles quand on affiche un article" |
318 | open_original: Ouvrir l'URL originale de l'article | 318 | open_original: "Ouvrir l’URL originale de l’article" |
319 | toggle_favorite: Changer le statut Favori de l'article | 319 | toggle_favorite: "Changer le statut Favori de l’article" |
320 | toggle_archive: Changer le status Lu de l'article | 320 | toggle_archive: "Changer le status Lu de l’article" |
321 | delete: Supprimer l'article | 321 | delete: "Supprimer l’article" |
322 | material_title: Raccourcis disponibles avec le thème Material uniquement | 322 | material_title: "Raccourcis disponibles avec le thème Material uniquement" |
323 | add_link: Ajouter un nouvel article | 323 | add_link: "Ajouter un nouvel article" |
324 | hide_form: Masquer le formulaire courant (recherche ou nouvel article) | 324 | hide_form: "Masquer le formulaire courant (recherche ou nouvel article)" |
325 | arrows_navigation: Naviguer à travers les articles | 325 | arrows_navigation: "Naviguer à travers les articles" |
326 | open_article: Afficher l'article sélectionné | 326 | open_article: "Afficher l’article sélectionné" |
327 | 327 | ||
328 | quickstart: | 328 | quickstart: |
329 | page_title: "Pour bien débuter" | 329 | page_title: "Pour bien débuter" |
@@ -385,8 +385,8 @@ tag: | |||
385 | number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags." | 385 | number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags." |
386 | see_untagged_entries: "Voir les articles sans tag" | 386 | see_untagged_entries: "Voir les articles sans tag" |
387 | new: | 387 | new: |
388 | add: 'Ajouter' | 388 | add: "Ajouter" |
389 | placeholder: 'Vous pouvez ajouter plusieurs tags, séparés par une virgule.' | 389 | placeholder: "Vous pouvez ajouter plusieurs tags, séparés par une virgule." |
390 | 390 | ||
391 | import: | 391 | import: |
392 | page_title: "Importer" | 392 | page_title: "Importer" |
@@ -420,7 +420,7 @@ import: | |||
420 | how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l’importer." | 420 | how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l’importer." |
421 | worker: | 421 | worker: |
422 | enabled: "Les imports sont asynchrones. Une fois l’import commencé un worker externe traitera les messages un par un. Le service activé est :" | 422 | enabled: "Les imports sont asynchrones. Une fois l’import commencé un worker externe traitera les messages un par un. Le service activé est :" |
423 | download_images_warning: "Vous avez configuré le téléchagement des images pour vos articles. Combiné à l'import classique, cette opération peut être très très longue (voire échouer). Nous vous conseillons <strong>vivement</strong> d'activer les imports asynchrones." | 423 | download_images_warning: "Vous avez configuré le téléchagement des images pour vos articles. Combiné à l’import classique, cette opération peut être très très longue (voire échouer). Nous vous conseillons <strong>vivement</strong> d’activer les imports asynchrones." |
424 | firefox: | 424 | firefox: |
425 | page_title: "Import > Firefox" | 425 | page_title: "Import > Firefox" |
426 | description: "Cet outil va vous permettre d’importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde… ». Vous allez récupérer un fichier .json. </p>" | 426 | description: "Cet outil va vous permettre d’importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde… ». Vous allez récupérer un fichier .json. </p>" |
@@ -489,16 +489,16 @@ developer: | |||
489 | back: "Retour" | 489 | back: "Retour" |
490 | 490 | ||
491 | user: | 491 | user: |
492 | page_title: Gestion des utilisateurs | 492 | page_title: "Gestion des utilisateurs" |
493 | new_user: Créer un nouvel utilisateur | 493 | new_user: "Créer un nouvel utilisateur" |
494 | edit_user: Éditer un utilisateur existant | 494 | edit_user: "Éditer un utilisateur existant" |
495 | description: Ici vous pouvez gérer vos utilisateurs (création, mise à jour et suppression) | 495 | description: "Ici vous pouvez gérer vos utilisateurs (création, mise à jour et suppression)" |
496 | list: | 496 | list: |
497 | actions: Actions | 497 | actions: "Actions" |
498 | edit_action: Éditer | 498 | edit_action: "Éditer" |
499 | yes: Oui | 499 | yes: "Oui" |
500 | no: Non | 500 | no: "Non" |
501 | create_new_one: Créer un nouvel utilisateur | 501 | create_new_one: "Créer un nouvel utilisateur" |
502 | form: | 502 | form: |
503 | username_label: "Nom d’utilisateur" | 503 | username_label: "Nom d’utilisateur" |
504 | name_label: "Nom" | 504 | name_label: "Nom" |
@@ -513,9 +513,11 @@ user: | |||
513 | delete: "Supprimer" | 513 | delete: "Supprimer" |
514 | delete_confirm: "Voulez-vous vraiment ?" | 514 | delete_confirm: "Voulez-vous vraiment ?" |
515 | back_to_list: "Revenir à la liste" | 515 | back_to_list: "Revenir à la liste" |
516 | search: | ||
517 | placeholder: "Filtrer par nom d’utilisateur ou email" | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | page_title: Une erreur est survenue | 520 | page_title: "Une erreur est survenue" |
519 | 521 | ||
520 | flashes: | 522 | flashes: |
521 | config: | 523 | config: |
@@ -528,10 +530,10 @@ flashes: | |||
528 | tagging_rules_updated: "Règles mises à jour" | 530 | tagging_rules_updated: "Règles mises à jour" |
529 | tagging_rules_deleted: "Règle supprimée" | 531 | tagging_rules_deleted: "Règle supprimée" |
530 | rss_token_updated: "Jeton RSS mis à jour" | 532 | rss_token_updated: "Jeton RSS mis à jour" |
531 | annotations_reset: Annotations supprimées | 533 | annotations_reset: "Annotations supprimées" |
532 | tags_reset: Tags supprimés | 534 | tags_reset: "Tags supprimés" |
533 | entries_reset: Articles supprimés | 535 | entries_reset: "Articles supprimés" |
534 | archived_reset: Articles archivés supprimés | 536 | archived_reset: "Articles archivés supprimés" |
535 | entry: | 537 | entry: |
536 | notice: | 538 | notice: |
537 | entry_already_saved: "Article déjà sauvegardé le %date%" | 539 | entry_already_saved: "Article déjà sauvegardé le %date%" |
@@ -563,6 +565,6 @@ flashes: | |||
563 | client_deleted: "Client %name% supprimé" | 565 | client_deleted: "Client %name% supprimé" |
564 | user: | 566 | user: |
565 | notice: | 567 | notice: |
566 | added: 'Utilisateur "%username%" ajouté' | 568 | added: "Utilisateur \"%username%\" ajouté" |
567 | updated: 'Utilisateur "%username%" mis à jour' | 569 | updated: "Utilisateur \"%username%\" mis à jour" |
568 | deleted: 'Utilisateur "%username%" supprimé' | 570 | deleted: "Utilisateur \"%username%\" supprimé" |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml index 374071ce..5a9605ff 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | # delete: Delete | 513 | # delete: Delete |
514 | # delete_confirm: Are you sure? | 514 | # delete_confirm: Are you sure? |
515 | # back_to_list: Back to list | 515 | # back_to_list: Back to list |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | # page_title: An error occurred | 520 | # page_title: An error occurred |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml index b01c611b..942bc257 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | delete: 'Suprimir' | 513 | delete: 'Suprimir' |
514 | delete_confirm: 'Sètz segur ?' | 514 | delete_confirm: 'Sètz segur ?' |
515 | back_to_list: 'Tornar a la lista' | 515 | back_to_list: 'Tornar a la lista' |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | page_title: Una error s'es produsida | 520 | page_title: Una error s'es produsida |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml index d76ac328..fea90440 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | delete: Usuń | 513 | delete: Usuń |
514 | delete_confirm: Jesteś pewien? | 514 | delete_confirm: Jesteś pewien? |
515 | back_to_list: Powrót do listy | 515 | back_to_list: Powrót do listy |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | page_title: Wystąpił błąd | 520 | page_title: Wystąpił błąd |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml index 98dfcd25..c59991f8 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | delete: 'Apagar' | 513 | delete: 'Apagar' |
514 | delete_confirm: 'Tem certeza?' | 514 | delete_confirm: 'Tem certeza?' |
515 | back_to_list: 'Voltar para a lista' | 515 | back_to_list: 'Voltar para a lista' |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | # page_title: An error occurred | 520 | # page_title: An error occurred |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml index 8c07c13f..5846b7cc 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | # delete: Delete | 513 | # delete: Delete |
514 | # delete_confirm: Are you sure? | 514 | # delete_confirm: Are you sure? |
515 | # back_to_list: Back to list | 515 | # back_to_list: Back to list |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | # page_title: An error occurred | 520 | # page_title: An error occurred |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml index bd21cb67..430fb96b 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml | |||
@@ -513,6 +513,8 @@ user: | |||
513 | # delete: Delete | 513 | # delete: Delete |
514 | # delete_confirm: Are you sure? | 514 | # delete_confirm: Are you sure? |
515 | # back_to_list: Back to list | 515 | # back_to_list: Back to list |
516 | search: | ||
517 | # placeholder: Filter by username or email | ||
516 | 518 | ||
517 | error: | 519 | error: |
518 | # page_title: An error occurred | 520 | # page_title: An error occurred |
diff --git a/src/Wallabag/ImportBundle/Command/ImportCommand.php b/src/Wallabag/ImportBundle/Command/ImportCommand.php index 28d01715..ce72837a 100644 --- a/src/Wallabag/ImportBundle/Command/ImportCommand.php +++ b/src/Wallabag/ImportBundle/Command/ImportCommand.php | |||
@@ -15,10 +15,11 @@ class ImportCommand extends ContainerAwareCommand | |||
15 | $this | 15 | $this |
16 | ->setName('wallabag:import') | 16 | ->setName('wallabag:import') |
17 | ->setDescription('Import entries from a JSON export') | 17 | ->setDescription('Import entries from a JSON export') |
18 | ->addArgument('userId', InputArgument::REQUIRED, 'User ID to populate') | 18 | ->addArgument('username', InputArgument::REQUIRED, 'User to populate') |
19 | ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file') | 19 | ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file') |
20 | ->addOption('importer', null, InputArgument::OPTIONAL, 'The importer to use: v1, v2, instapaper, pinboard, readability, firefox or chrome', 'v1') | 20 | ->addOption('importer', null, InputArgument::OPTIONAL, 'The importer to use: v1, v2, instapaper, pinboard, readability, firefox or chrome', 'v1') |
21 | ->addOption('markAsRead', null, InputArgument::OPTIONAL, 'Mark all entries as read', false) | 21 | ->addOption('markAsRead', null, InputArgument::OPTIONAL, 'Mark all entries as read', false) |
22 | ->addOption('useUserId', null, InputArgument::OPTIONAL, 'Use user id instead of username to find account', false) | ||
22 | ; | 23 | ; |
23 | } | 24 | } |
24 | 25 | ||
@@ -34,10 +35,14 @@ class ImportCommand extends ContainerAwareCommand | |||
34 | // Turning off doctrine default logs queries for saving memory | 35 | // Turning off doctrine default logs queries for saving memory |
35 | $em->getConnection()->getConfiguration()->setSQLLogger(null); | 36 | $em->getConnection()->getConfiguration()->setSQLLogger(null); |
36 | 37 | ||
37 | $user = $em->getRepository('WallabagUserBundle:User')->findOneById($input->getArgument('userId')); | 38 | if ($input->getOption('useUserId')) { |
39 | $user = $em->getRepository('WallabagUserBundle:User')->findOneById($input->getArgument('username')); | ||
40 | } else { | ||
41 | $user = $em->getRepository('WallabagUserBundle:User')->findOneByUsername($input->getArgument('username')); | ||
42 | } | ||
38 | 43 | ||
39 | if (!is_object($user)) { | 44 | if (!is_object($user)) { |
40 | throw new Exception(sprintf('User with id "%s" not found', $input->getArgument('userId'))); | 45 | throw new Exception(sprintf('User "%s" not found', $input->getArgument('username'))); |
41 | } | 46 | } |
42 | 47 | ||
43 | switch ($input->getOption('importer')) { | 48 | switch ($input->getOption('importer')) { |
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php index 92ee2b41..1c5c86d4 100644 --- a/src/Wallabag/UserBundle/Controller/ManageController.php +++ b/src/Wallabag/UserBundle/Controller/ManageController.php | |||
@@ -4,12 +4,15 @@ namespace Wallabag\UserBundle\Controller; | |||
4 | 4 | ||
5 | use FOS\UserBundle\Event\UserEvent; | 5 | use FOS\UserBundle\Event\UserEvent; |
6 | use FOS\UserBundle\FOSUserEvents; | 6 | use FOS\UserBundle\FOSUserEvents; |
7 | use Pagerfanta\Adapter\DoctrineORMAdapter; | ||
8 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | ||
9 | use Pagerfanta\Pagerfanta; | ||
7 | use Symfony\Component\HttpFoundation\Request; | 10 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 11 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; | 12 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; |
10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | 13 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
11 | use Wallabag\UserBundle\Entity\User; | 14 | use Wallabag\UserBundle\Entity\User; |
12 | use Wallabag\CoreBundle\Entity\Config; | 15 | use Wallabag\UserBundle\Form\SearchUserType; |
13 | 16 | ||
14 | /** | 17 | /** |
15 | * User controller. | 18 | * User controller. |
@@ -17,23 +20,6 @@ use Wallabag\CoreBundle\Entity\Config; | |||
17 | class ManageController extends Controller | 20 | class ManageController extends Controller |
18 | { | 21 | { |
19 | /** | 22 | /** |
20 | * Lists all User entities. | ||
21 | * | ||
22 | * @Route("/", name="user_index") | ||
23 | * @Method("GET") | ||
24 | */ | ||
25 | public function indexAction() | ||
26 | { | ||
27 | $em = $this->getDoctrine()->getManager(); | ||
28 | |||
29 | $users = $em->getRepository('WallabagUserBundle:User')->findAll(); | ||
30 | |||
31 | return $this->render('WallabagUserBundle:Manage:index.html.twig', array( | ||
32 | 'users' => $users, | ||
33 | )); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * Creates a new User entity. | 23 | * Creates a new User entity. |
38 | * | 24 | * |
39 | * @Route("/new", name="user_new") | 25 | * @Route("/new", name="user_new") |
@@ -146,4 +132,49 @@ class ManageController extends Controller | |||
146 | ->getForm() | 132 | ->getForm() |
147 | ; | 133 | ; |
148 | } | 134 | } |
135 | |||
136 | /** | ||
137 | * @param Request $request | ||
138 | * @param int $page | ||
139 | * | ||
140 | * @Route("/list/{page}", name="user_index", defaults={"page" = 1}) | ||
141 | * | ||
142 | * Default parameter for page is hardcoded (in duplication of the defaults from the Route) | ||
143 | * because this controller is also called inside the layout template without any page as argument | ||
144 | * | ||
145 | * @return \Symfony\Component\HttpFoundation\Response | ||
146 | */ | ||
147 | public function searchFormAction(Request $request, $page = 1) | ||
148 | { | ||
149 | $em = $this->getDoctrine()->getManager(); | ||
150 | $qb = $em->getRepository('WallabagUserBundle:User')->createQueryBuilder('u'); | ||
151 | |||
152 | $form = $this->createForm(SearchUserType::class); | ||
153 | $form->handleRequest($request); | ||
154 | |||
155 | if ($form->isSubmitted() && $form->isValid()) { | ||
156 | $this->get('logger')->info('searching users'); | ||
157 | |||
158 | $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : ''); | ||
159 | |||
160 | $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm); | ||
161 | } | ||
162 | |||
163 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); | ||
164 | $pagerFanta = new Pagerfanta($pagerAdapter); | ||
165 | $pagerFanta->setMaxPerPage(50); | ||
166 | |||
167 | try { | ||
168 | $pagerFanta->setCurrentPage($page); | ||
169 | } catch (OutOfRangeCurrentPageException $e) { | ||
170 | if ($page > 1) { | ||
171 | return $this->redirect($this->generateUrl('user_index', ['page' => $pagerFanta->getNbPages()]), 302); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | return $this->render('WallabagUserBundle:Manage:index.html.twig', [ | ||
176 | 'searchForm' => $form->createView(), | ||
177 | 'users' => $pagerFanta, | ||
178 | ]); | ||
179 | } | ||
149 | } | 180 | } |
diff --git a/src/Wallabag/UserBundle/Form/SearchUserType.php b/src/Wallabag/UserBundle/Form/SearchUserType.php new file mode 100644 index 00000000..9ce46ee1 --- /dev/null +++ b/src/Wallabag/UserBundle/Form/SearchUserType.php | |||
@@ -0,0 +1,29 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\UserBundle\Form; | ||
4 | |||
5 | use Symfony\Component\Form\AbstractType; | ||
6 | use Symfony\Component\Form\Extension\Core\Type\TextType; | ||
7 | use Symfony\Component\Form\FormBuilderInterface; | ||
8 | use Symfony\Component\OptionsResolver\OptionsResolver; | ||
9 | |||
10 | class SearchUserType extends AbstractType | ||
11 | { | ||
12 | public function buildForm(FormBuilderInterface $builder, array $options) | ||
13 | { | ||
14 | $builder | ||
15 | ->setMethod('GET') | ||
16 | ->add('term', TextType::class, [ | ||
17 | 'required' => true, | ||
18 | 'label' => 'user.new.form_search.term_label', | ||
19 | ]) | ||
20 | ; | ||
21 | } | ||
22 | |||
23 | public function configureOptions(OptionsResolver $resolver) | ||
24 | { | ||
25 | $resolver->setDefaults([ | ||
26 | 'csrf_protection' => false, | ||
27 | ]); | ||
28 | } | ||
29 | } | ||
diff --git a/src/Wallabag/UserBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php index f913f52d..6adbe329 100644 --- a/src/Wallabag/UserBundle/Repository/UserRepository.php +++ b/src/Wallabag/UserBundle/Repository/UserRepository.php | |||
@@ -52,4 +52,17 @@ class UserRepository extends EntityRepository | |||
52 | ->getQuery() | 52 | ->getQuery() |
53 | ->getSingleScalarResult(); | 53 | ->getSingleScalarResult(); |
54 | } | 54 | } |
55 | |||
56 | /** | ||
57 | * Retrieves users filtered with a search term. | ||
58 | * | ||
59 | * @param string $term | ||
60 | * | ||
61 | * @return QueryBuilder | ||
62 | */ | ||
63 | public function getQueryBuilderForSearch($term) | ||
64 | { | ||
65 | return $this->createQueryBuilder('u') | ||
66 | ->andWhere('lower(u.username) LIKE lower(:term) OR lower(u.email) LIKE lower(:term) OR lower(u.name) LIKE lower(:term)')->setParameter('term', '%'.$term.'%'); | ||
67 | } | ||
55 | } | 68 | } |
diff --git a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig index daba29e4..15002632 100644 --- a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig +++ b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig | |||
@@ -7,37 +7,60 @@ | |||
7 | <div class="row"> | 7 | <div class="row"> |
8 | <div class="col s12"> | 8 | <div class="col s12"> |
9 | <div class="card-panel"> | 9 | <div class="card-panel"> |
10 | {% if users.getNbPages > 1 %} | ||
11 | {{ pagerfanta(users, 'twitter_bootstrap_translated', {'proximity': 1}) }} | ||
12 | {% endif %} | ||
10 | <div class="row"> | 13 | <div class="row"> |
11 | <div class="input-field col s12"> | 14 | <div class="col s6"> |
12 | <p class="help">{{ 'user.description'|trans|raw }}</p> | 15 | <p class="help">{{ 'user.description'|trans|raw }}</p> |
16 | </div> | ||
17 | <div class="col s6"> | ||
18 | <div class="input-field"> | ||
19 | <form name="search_users" method="GET" action="{{ path('user_index')}}"> | ||
20 | {% if form_errors(searchForm) %} | ||
21 | <span class="black-text">{{ form_errors(searchForm) }}</span> | ||
22 | {% endif %} | ||
23 | |||
24 | {% if form_errors(searchForm.term) %} | ||
25 | <span class="black-text">{{ form_errors(searchForm.term) }}</span> | ||
26 | {% endif %} | ||
13 | 27 | ||
14 | <table class="bordered"> | 28 | {{ form_widget(searchForm.term, { 'attr': {'autocomplete': 'off', 'placeholder': 'user.search.placeholder'} }) }} |
15 | <thead> | 29 | |
16 | <tr> | 30 | {{ form_rest(searchForm) }} |
17 | <th>{{ 'user.form.username_label'|trans }}</th> | 31 | </form> |
18 | <th>{{ 'user.form.email_label'|trans }}</th> | 32 | </div> |
19 | <th>{{ 'user.form.last_login_label'|trans }}</th> | ||
20 | <th>{{ 'user.list.actions'|trans }}</th> | ||
21 | </tr> | ||
22 | </thead> | ||
23 | <tbody> | ||
24 | {% for user in users %} | ||
25 | <tr> | ||
26 | <td>{{ user.username }}</td> | ||
27 | <td>{{ user.email }}</td> | ||
28 | <td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td> | ||
29 | <td> | ||
30 | <a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a> | ||
31 | </td> | ||
32 | </tr> | ||
33 | {% endfor %} | ||
34 | </tbody> | ||
35 | </table> | ||
36 | <br /> | ||
37 | <p> | ||
38 | <a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a> | ||
39 | </p> | ||
40 | </div> | 33 | </div> |
34 | |||
35 | <table class="bordered"> | ||
36 | <thead> | ||
37 | <tr> | ||
38 | <th>{{ 'user.form.username_label'|trans }}</th> | ||
39 | <th>{{ 'user.form.email_label'|trans }}</th> | ||
40 | <th>{{ 'user.form.last_login_label'|trans }}</th> | ||
41 | <th>{{ 'user.list.actions'|trans }}</th> | ||
42 | </tr> | ||
43 | </thead> | ||
44 | <tbody> | ||
45 | {% for user in users %} | ||
46 | <tr> | ||
47 | <td>{{ user.username }}</td> | ||
48 | <td>{{ user.email }}</td> | ||
49 | <td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td> | ||
50 | <td> | ||
51 | <a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a> | ||
52 | </td> | ||
53 | </tr> | ||
54 | {% endfor %} | ||
55 | </tbody> | ||
56 | </table> | ||
57 | <br /> | ||
58 | <p> | ||
59 | <a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a> | ||
60 | </p> | ||
61 | {% if users.getNbPages > 1 %} | ||
62 | {{ pagerfanta(users, 'twitter_bootstrap_translated', {'proximity': 1}) }} | ||
63 | {% endif %} | ||
41 | </div> | 64 | </div> |
42 | </div> | 65 | </div> |
43 | </div> | 66 | </div> |
diff --git a/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php index e6ffd664..362c269b 100644 --- a/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php +++ b/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php | |||
@@ -767,19 +767,67 @@ class EntryRestControllerTest extends WallabagApiTestCase | |||
767 | ]; | 767 | ]; |
768 | 768 | ||
769 | $this->client->request('DELETE', '/api/entries/tags/list?list='.json_encode($list)); | 769 | $this->client->request('DELETE', '/api/entries/tags/list?list='.json_encode($list)); |
770 | } | ||
771 | |||
772 | public function testPostEntriesListAction() | ||
773 | { | ||
774 | $list = [ | ||
775 | 'http://www.lemonde.fr/musiques/article/2017/04/23/loin-de-la-politique-le-printemps-de-bourges-retombe-en-enfance_5115862_1654986.html', | ||
776 | 'http://0.0.0.0/entry2', | ||
777 | ]; | ||
778 | |||
779 | $this->client->request('POST', '/api/entries/lists?urls='.json_encode($list)); | ||
770 | 780 | ||
771 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | 781 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
772 | 782 | ||
773 | $content = json_decode($this->client->getResponse()->getContent(), true); | 783 | $content = json_decode($this->client->getResponse()->getContent(), true); |
774 | 784 | ||
775 | $this->assertInternalType('int', $content[0]['entry']); | 785 | $this->assertInternalType('int', $content[0]['entry']); |
776 | $this->assertEquals('http://0.0.0.0/entry4', $content[0]['url']); | 786 | $this->assertEquals('http://www.lemonde.fr/musiques/article/2017/04/23/loin-de-la-politique-le-printemps-de-bourges-retombe-en-enfance_5115862_1654986.html', $content[0]['url']); |
777 | 787 | ||
778 | $entry = $this->client->getContainer()->get('doctrine.orm.entity_manager') | 788 | $this->assertInternalType('int', $content[1]['entry']); |
779 | ->getRepository('WallabagCoreBundle:Entry') | 789 | $this->assertEquals('http://0.0.0.0/entry2', $content[1]['url']); |
780 | ->findByUrlAndUserId('http://0.0.0.0/entry4', 1); | 790 | } |
781 | 791 | ||
782 | $tags = $entry->getTags(); | 792 | public function testDeleteEntriesListAction() |
783 | $this->assertCount(2, $tags); | 793 | { |
794 | $list = [ | ||
795 | 'http://www.lemonde.fr/musiques/article/2017/04/23/loin-de-la-politique-le-printemps-de-bourges-retombe-en-enfance_5115862_1654986.html', | ||
796 | 'http://0.0.0.0/entry3', | ||
797 | ]; | ||
798 | |||
799 | $this->client->request('DELETE', '/api/entries/list?urls='.json_encode($list)); | ||
800 | |||
801 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
802 | |||
803 | $content = json_decode($this->client->getResponse()->getContent(), true); | ||
804 | |||
805 | $this->assertTrue($content[0]['entry']); | ||
806 | $this->assertEquals('http://www.lemonde.fr/musiques/article/2017/04/23/loin-de-la-politique-le-printemps-de-bourges-retombe-en-enfance_5115862_1654986.html', $content[0]['url']); | ||
807 | |||
808 | $this->assertFalse($content[1]['entry']); | ||
809 | $this->assertEquals('http://0.0.0.0/entry3', $content[1]['url']); | ||
810 | } | ||
811 | |||
812 | public function testLimitBulkAction() | ||
813 | { | ||
814 | $list = [ | ||
815 | 'http://0.0.0.0/entry1', | ||
816 | 'http://0.0.0.0/entry1', | ||
817 | 'http://0.0.0.0/entry1', | ||
818 | 'http://0.0.0.0/entry1', | ||
819 | 'http://0.0.0.0/entry1', | ||
820 | 'http://0.0.0.0/entry1', | ||
821 | 'http://0.0.0.0/entry1', | ||
822 | 'http://0.0.0.0/entry1', | ||
823 | 'http://0.0.0.0/entry1', | ||
824 | 'http://0.0.0.0/entry1', | ||
825 | 'http://0.0.0.0/entry1', | ||
826 | ]; | ||
827 | |||
828 | $this->client->request('POST', '/api/entries/lists?urls='.json_encode($list)); | ||
829 | |||
830 | $this->assertEquals(400, $this->client->getResponse()->getStatusCode()); | ||
831 | $this->assertContains('API limit reached', $this->client->getResponse()->getContent()); | ||
784 | } | 832 | } |
785 | } | 833 | } |
diff --git a/tests/Wallabag/CoreBundle/Command/CleanDuplicatesCommandTest.php b/tests/Wallabag/CoreBundle/Command/CleanDuplicatesCommandTest.php new file mode 100644 index 00000000..e6e57f30 --- /dev/null +++ b/tests/Wallabag/CoreBundle/Command/CleanDuplicatesCommandTest.php | |||
@@ -0,0 +1,108 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Tests\Wallabag\CoreBundle\Command; | ||
4 | |||
5 | use Symfony\Bundle\FrameworkBundle\Console\Application; | ||
6 | use Symfony\Component\Console\Tester\CommandTester; | ||
7 | use Wallabag\CoreBundle\Command\CleanDuplicatesCommand; | ||
8 | use Tests\Wallabag\CoreBundle\WallabagCoreTestCase; | ||
9 | use Wallabag\CoreBundle\Entity\Entry; | ||
10 | |||
11 | class CleanDuplicatesCommandTest extends WallabagCoreTestCase | ||
12 | { | ||
13 | public function testRunCleanDuplicates() | ||
14 | { | ||
15 | $application = new Application($this->getClient()->getKernel()); | ||
16 | $application->add(new CleanDuplicatesCommand()); | ||
17 | |||
18 | $command = $application->find('wallabag:clean-duplicates'); | ||
19 | |||
20 | $tester = new CommandTester($command); | ||
21 | $tester->execute([ | ||
22 | 'command' => $command->getName(), | ||
23 | ]); | ||
24 | |||
25 | $this->assertContains('Cleaning through 3 user accounts', $tester->getDisplay()); | ||
26 | $this->assertContains('Finished cleaning. 0 duplicates found in total', $tester->getDisplay()); | ||
27 | } | ||
28 | |||
29 | public function testRunCleanDuplicatesCommandWithBadUsername() | ||
30 | { | ||
31 | $application = new Application($this->getClient()->getKernel()); | ||
32 | $application->add(new CleanDuplicatesCommand()); | ||
33 | |||
34 | $command = $application->find('wallabag:clean-duplicates'); | ||
35 | |||
36 | $tester = new CommandTester($command); | ||
37 | $tester->execute([ | ||
38 | 'command' => $command->getName(), | ||
39 | 'username' => 'unknown', | ||
40 | ]); | ||
41 | |||
42 | $this->assertContains('User "unknown" not found', $tester->getDisplay()); | ||
43 | } | ||
44 | |||
45 | public function testRunCleanDuplicatesCommandForUser() | ||
46 | { | ||
47 | $application = new Application($this->getClient()->getKernel()); | ||
48 | $application->add(new CleanDuplicatesCommand()); | ||
49 | |||
50 | $command = $application->find('wallabag:clean-duplicates'); | ||
51 | |||
52 | $tester = new CommandTester($command); | ||
53 | $tester->execute([ | ||
54 | 'command' => $command->getName(), | ||
55 | 'username' => 'admin', | ||
56 | ]); | ||
57 | |||
58 | $this->assertContains('Cleaned 0 duplicates for user admin', $tester->getDisplay()); | ||
59 | } | ||
60 | |||
61 | public function testDuplicate() | ||
62 | { | ||
63 | $url = 'http://www.lemonde.fr/sport/visuel/2017/05/05/rondelle-prison-blanchissage-comprendre-le-hockey-sur-glace_5122587_3242.html'; | ||
64 | $client = $this->getClient(); | ||
65 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | ||
66 | |||
67 | $this->logInAs('admin'); | ||
68 | |||
69 | $nbEntries = $em->getRepository('WallabagCoreBundle:Entry')->findAllByUrlAndUserId($url, $this->getLoggedInUserId()); | ||
70 | $this->assertCount(0, $nbEntries); | ||
71 | |||
72 | $user = $em->getRepository('WallabagUserBundle:User')->findOneById($this->getLoggedInUserId()); | ||
73 | |||
74 | $entry1 = new Entry($user); | ||
75 | $entry1->setUrl($url); | ||
76 | |||
77 | $entry2 = new Entry($user); | ||
78 | $entry2->setUrl($url); | ||
79 | |||
80 | $em->persist($entry1); | ||
81 | $em->persist($entry2); | ||
82 | |||
83 | $em->flush(); | ||
84 | |||
85 | $nbEntries = $em->getRepository('WallabagCoreBundle:Entry')->findAllByUrlAndUserId($url, $this->getLoggedInUserId()); | ||
86 | $this->assertCount(2, $nbEntries); | ||
87 | |||
88 | $application = new Application($this->getClient()->getKernel()); | ||
89 | $application->add(new CleanDuplicatesCommand()); | ||
90 | |||
91 | $command = $application->find('wallabag:clean-duplicates'); | ||
92 | |||
93 | $tester = new CommandTester($command); | ||
94 | $tester->execute([ | ||
95 | 'command' => $command->getName(), | ||
96 | 'username' => 'admin', | ||
97 | ]); | ||
98 | |||
99 | $this->assertContains('Cleaned 1 duplicates for user admin', $tester->getDisplay()); | ||
100 | |||
101 | $nbEntries = $em->getRepository('WallabagCoreBundle:Entry')->findAllByUrlAndUserId($url, $this->getLoggedInUserId()); | ||
102 | $this->assertCount(1, $nbEntries); | ||
103 | |||
104 | $query = $em->createQuery('DELETE FROM Wallabag\CoreBundle\Entity\Entry e WHERE e.url = :url'); | ||
105 | $query->setParameter('url', $url); | ||
106 | $query->execute(); | ||
107 | } | ||
108 | } | ||
diff --git a/tests/Wallabag/CoreBundle/Command/ExportCommandTest.php b/tests/Wallabag/CoreBundle/Command/ExportCommandTest.php index 6798c5d7..b21f3318 100644 --- a/tests/Wallabag/CoreBundle/Command/ExportCommandTest.php +++ b/tests/Wallabag/CoreBundle/Command/ExportCommandTest.php | |||
@@ -70,7 +70,7 @@ class ExportCommandTest extends WallabagCoreTestCase | |||
70 | $tester->execute([ | 70 | $tester->execute([ |
71 | 'command' => $command->getName(), | 71 | 'command' => $command->getName(), |
72 | 'username' => 'admin', | 72 | 'username' => 'admin', |
73 | 'filepath' => 'specialexport.json' | 73 | 'filepath' => 'specialexport.json', |
74 | ]); | 74 | ]); |
75 | 75 | ||
76 | $this->assertFileExists('specialexport.json'); | 76 | $this->assertFileExists('specialexport.json'); |
diff --git a/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php b/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php index 1bfd41d5..122a87d4 100644 --- a/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php +++ b/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php | |||
@@ -87,6 +87,7 @@ class InstallCommandTest extends WallabagCoreTestCase | |||
87 | $this->assertContains('Setting up database.', $tester->getDisplay()); | 87 | $this->assertContains('Setting up database.', $tester->getDisplay()); |
88 | $this->assertContains('Administration setup.', $tester->getDisplay()); | 88 | $this->assertContains('Administration setup.', $tester->getDisplay()); |
89 | $this->assertContains('Config setup.', $tester->getDisplay()); | 89 | $this->assertContains('Config setup.', $tester->getDisplay()); |
90 | $this->assertContains('Run migrations.', $tester->getDisplay()); | ||
90 | } | 91 | } |
91 | 92 | ||
92 | public function testRunInstallCommandWithReset() | 93 | public function testRunInstallCommandWithReset() |
@@ -115,12 +116,13 @@ class InstallCommandTest extends WallabagCoreTestCase | |||
115 | 116 | ||
116 | $this->assertContains('Checking system requirements.', $tester->getDisplay()); | 117 | $this->assertContains('Checking system requirements.', $tester->getDisplay()); |
117 | $this->assertContains('Setting up database.', $tester->getDisplay()); | 118 | $this->assertContains('Setting up database.', $tester->getDisplay()); |
118 | $this->assertContains('Droping database, creating database and schema, clearing the cache', $tester->getDisplay()); | 119 | $this->assertContains('Dropping database, creating database and schema, clearing the cache', $tester->getDisplay()); |
119 | $this->assertContains('Administration setup.', $tester->getDisplay()); | 120 | $this->assertContains('Administration setup.', $tester->getDisplay()); |
120 | $this->assertContains('Config setup.', $tester->getDisplay()); | 121 | $this->assertContains('Config setup.', $tester->getDisplay()); |
122 | $this->assertContains('Run migrations.', $tester->getDisplay()); | ||
121 | 123 | ||
122 | // we force to reset everything | 124 | // we force to reset everything |
123 | $this->assertContains('Droping database, creating database and schema, clearing the cache', $tester->getDisplay()); | 125 | $this->assertContains('Dropping database, creating database and schema, clearing the cache', $tester->getDisplay()); |
124 | } | 126 | } |
125 | 127 | ||
126 | public function testRunInstallCommandWithDatabaseRemoved() | 128 | public function testRunInstallCommandWithDatabaseRemoved() |
@@ -168,6 +170,7 @@ class InstallCommandTest extends WallabagCoreTestCase | |||
168 | $this->assertContains('Setting up database.', $tester->getDisplay()); | 170 | $this->assertContains('Setting up database.', $tester->getDisplay()); |
169 | $this->assertContains('Administration setup.', $tester->getDisplay()); | 171 | $this->assertContains('Administration setup.', $tester->getDisplay()); |
170 | $this->assertContains('Config setup.', $tester->getDisplay()); | 172 | $this->assertContains('Config setup.', $tester->getDisplay()); |
173 | $this->assertContains('Run migrations.', $tester->getDisplay()); | ||
171 | 174 | ||
172 | // the current database doesn't already exist | 175 | // the current database doesn't already exist |
173 | $this->assertContains('Creating database and schema, clearing the cache', $tester->getDisplay()); | 176 | $this->assertContains('Creating database and schema, clearing the cache', $tester->getDisplay()); |
@@ -205,8 +208,9 @@ class InstallCommandTest extends WallabagCoreTestCase | |||
205 | $this->assertContains('Setting up database.', $tester->getDisplay()); | 208 | $this->assertContains('Setting up database.', $tester->getDisplay()); |
206 | $this->assertContains('Administration setup.', $tester->getDisplay()); | 209 | $this->assertContains('Administration setup.', $tester->getDisplay()); |
207 | $this->assertContains('Config setup.', $tester->getDisplay()); | 210 | $this->assertContains('Config setup.', $tester->getDisplay()); |
211 | $this->assertContains('Run migrations.', $tester->getDisplay()); | ||
208 | 212 | ||
209 | $this->assertContains('Droping schema and creating schema', $tester->getDisplay()); | 213 | $this->assertContains('Dropping schema and creating schema', $tester->getDisplay()); |
210 | } | 214 | } |
211 | 215 | ||
212 | public function testRunInstallCommandChooseNothing() | 216 | public function testRunInstallCommandChooseNothing() |
@@ -259,6 +263,7 @@ class InstallCommandTest extends WallabagCoreTestCase | |||
259 | $this->assertContains('Setting up database.', $tester->getDisplay()); | 263 | $this->assertContains('Setting up database.', $tester->getDisplay()); |
260 | $this->assertContains('Administration setup.', $tester->getDisplay()); | 264 | $this->assertContains('Administration setup.', $tester->getDisplay()); |
261 | $this->assertContains('Config setup.', $tester->getDisplay()); | 265 | $this->assertContains('Config setup.', $tester->getDisplay()); |
266 | $this->assertContains('Run migrations.', $tester->getDisplay()); | ||
262 | 267 | ||
263 | $this->assertContains('Creating schema', $tester->getDisplay()); | 268 | $this->assertContains('Creating schema', $tester->getDisplay()); |
264 | } | 269 | } |
@@ -291,5 +296,6 @@ class InstallCommandTest extends WallabagCoreTestCase | |||
291 | $this->assertContains('Setting up database.', $tester->getDisplay()); | 296 | $this->assertContains('Setting up database.', $tester->getDisplay()); |
292 | $this->assertContains('Administration setup.', $tester->getDisplay()); | 297 | $this->assertContains('Administration setup.', $tester->getDisplay()); |
293 | $this->assertContains('Config setup.', $tester->getDisplay()); | 298 | $this->assertContains('Config setup.', $tester->getDisplay()); |
299 | $this->assertContains('Run migrations.', $tester->getDisplay()); | ||
294 | } | 300 | } |
295 | } | 301 | } |
diff --git a/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php b/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php index 5956b502..8abb1bbb 100644 --- a/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php +++ b/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php | |||
@@ -111,7 +111,7 @@ class ContentProxyTest extends \PHPUnit_Framework_TestCase | |||
111 | 111 | ||
112 | $this->assertEquals('http://domain.io', $entry->getUrl()); | 112 | $this->assertEquals('http://domain.io', $entry->getUrl()); |
113 | $this->assertEquals('my title', $entry->getTitle()); | 113 | $this->assertEquals('my title', $entry->getTitle()); |
114 | $this->assertEquals($this->fetchingErrorMessage . '<p><i>But we found a short description: </i></p>desc', $entry->getContent()); | 114 | $this->assertEquals($this->fetchingErrorMessage.'<p><i>But we found a short description: </i></p>desc', $entry->getContent()); |
115 | $this->assertEmpty($entry->getPreviewPicture()); | 115 | $this->assertEmpty($entry->getPreviewPicture()); |
116 | $this->assertEmpty($entry->getLanguage()); | 116 | $this->assertEmpty($entry->getLanguage()); |
117 | $this->assertEmpty($entry->getHttpStatus()); | 117 | $this->assertEmpty($entry->getHttpStatus()); |
diff --git a/tests/Wallabag/ImportBundle/Command/ImportCommandTest.php b/tests/Wallabag/ImportBundle/Command/ImportCommandTest.php index 7be1eb18..7043c345 100644 --- a/tests/Wallabag/ImportBundle/Command/ImportCommandTest.php +++ b/tests/Wallabag/ImportBundle/Command/ImportCommandTest.php | |||
@@ -10,7 +10,7 @@ use Tests\Wallabag\CoreBundle\WallabagCoreTestCase; | |||
10 | class ImportCommandTest extends WallabagCoreTestCase | 10 | class ImportCommandTest extends WallabagCoreTestCase |
11 | { | 11 | { |
12 | /** | 12 | /** |
13 | * @expectedException Symfony\Component\Console\Exception\RuntimeException | 13 | * @expectedException \Symfony\Component\Console\Exception\RuntimeException |
14 | * @expectedExceptionMessage Not enough arguments | 14 | * @expectedExceptionMessage Not enough arguments |
15 | */ | 15 | */ |
16 | public function testRunImportCommandWithoutArguments() | 16 | public function testRunImportCommandWithoutArguments() |
@@ -27,7 +27,7 @@ class ImportCommandTest extends WallabagCoreTestCase | |||
27 | } | 27 | } |
28 | 28 | ||
29 | /** | 29 | /** |
30 | * @expectedException Symfony\Component\Config\Definition\Exception\Exception | 30 | * @expectedException \Symfony\Component\Config\Definition\Exception\Exception |
31 | * @expectedExceptionMessage not found | 31 | * @expectedExceptionMessage not found |
32 | */ | 32 | */ |
33 | public function testRunImportCommandWithoutFilepath() | 33 | public function testRunImportCommandWithoutFilepath() |
@@ -40,16 +40,15 @@ class ImportCommandTest extends WallabagCoreTestCase | |||
40 | $tester = new CommandTester($command); | 40 | $tester = new CommandTester($command); |
41 | $tester->execute([ | 41 | $tester->execute([ |
42 | 'command' => $command->getName(), | 42 | 'command' => $command->getName(), |
43 | 'userId' => 1, | 43 | 'username' => 'admin', |
44 | 'filepath' => 1, | 44 | 'filepath' => 1, |
45 | ]); | 45 | ]); |
46 | } | 46 | } |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * @expectedException Symfony\Component\Config\Definition\Exception\Exception | 49 | * @expectedException \Doctrine\ORM\NoResultException |
50 | * @expectedExceptionMessage User with id | ||
51 | */ | 50 | */ |
52 | public function testRunImportCommandWithoutUserId() | 51 | public function testRunImportCommandWithWrongUsername() |
53 | { | 52 | { |
54 | $application = new Application($this->getClient()->getKernel()); | 53 | $application = new Application($this->getClient()->getKernel()); |
55 | $application->add(new ImportCommand()); | 54 | $application->add(new ImportCommand()); |
@@ -59,7 +58,7 @@ class ImportCommandTest extends WallabagCoreTestCase | |||
59 | $tester = new CommandTester($command); | 58 | $tester = new CommandTester($command); |
60 | $tester->execute([ | 59 | $tester->execute([ |
61 | 'command' => $command->getName(), | 60 | 'command' => $command->getName(), |
62 | 'userId' => 0, | 61 | 'username' => 'random', |
63 | 'filepath' => './', | 62 | 'filepath' => './', |
64 | ]); | 63 | ]); |
65 | } | 64 | } |
@@ -74,7 +73,7 @@ class ImportCommandTest extends WallabagCoreTestCase | |||
74 | $tester = new CommandTester($command); | 73 | $tester = new CommandTester($command); |
75 | $tester->execute([ | 74 | $tester->execute([ |
76 | 'command' => $command->getName(), | 75 | 'command' => $command->getName(), |
77 | 'userId' => 1, | 76 | 'username' => 'admin', |
78 | 'filepath' => $application->getKernel()->getContainer()->getParameter('kernel.root_dir').'/../tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json', | 77 | 'filepath' => $application->getKernel()->getContainer()->getParameter('kernel.root_dir').'/../tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json', |
79 | '--importer' => 'v2', | 78 | '--importer' => 'v2', |
80 | ]); | 79 | ]); |
@@ -82,4 +81,20 @@ class ImportCommandTest extends WallabagCoreTestCase | |||
82 | $this->assertContains('imported', $tester->getDisplay()); | 81 | $this->assertContains('imported', $tester->getDisplay()); |
83 | $this->assertContains('already saved', $tester->getDisplay()); | 82 | $this->assertContains('already saved', $tester->getDisplay()); |
84 | } | 83 | } |
84 | |||
85 | public function testRunImportCommandWithUserId() | ||
86 | { | ||
87 | $application = new Application($this->getClient()->getKernel()); | ||
88 | $application->add(new ImportCommand()); | ||
89 | |||
90 | $command = $application->find('wallabag:import'); | ||
91 | |||
92 | $tester = new CommandTester($command); | ||
93 | $tester->execute([ | ||
94 | 'command' => $command->getName(), | ||
95 | 'username' => 1, | ||
96 | 'filepath' => $application->getKernel()->getContainer()->getParameter('kernel.root_dir').'/../tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json', | ||
97 | '--useUserId' => true, | ||
98 | ]); | ||
99 | } | ||
85 | } | 100 | } |
diff --git a/tests/Wallabag/UserBundle/Controller/ManageControllerTest.php b/tests/Wallabag/UserBundle/Controller/ManageControllerTest.php index 4faddfc4..44b9a030 100644 --- a/tests/Wallabag/UserBundle/Controller/ManageControllerTest.php +++ b/tests/Wallabag/UserBundle/Controller/ManageControllerTest.php | |||
@@ -10,7 +10,7 @@ class ManageControllerTest extends WallabagCoreTestCase | |||
10 | { | 10 | { |
11 | $client = $this->getClient(); | 11 | $client = $this->getClient(); |
12 | 12 | ||
13 | $client->request('GET', '/users/'); | 13 | $client->request('GET', '/users/list'); |
14 | 14 | ||
15 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | 15 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); |
16 | $this->assertContains('login', $client->getResponse()->headers->get('location')); | 16 | $this->assertContains('login', $client->getResponse()->headers->get('location')); |
@@ -22,7 +22,7 @@ class ManageControllerTest extends WallabagCoreTestCase | |||
22 | $client = $this->getClient(); | 22 | $client = $this->getClient(); |
23 | 23 | ||
24 | // Create a new user in the database | 24 | // Create a new user in the database |
25 | $crawler = $client->request('GET', '/users/'); | 25 | $crawler = $client->request('GET', '/users/list'); |
26 | $this->assertEquals(200, $client->getResponse()->getStatusCode(), 'Unexpected HTTP status code for GET /users/'); | 26 | $this->assertEquals(200, $client->getResponse()->getStatusCode(), 'Unexpected HTTP status code for GET /users/'); |
27 | $crawler = $client->click($crawler->selectLink('user.list.create_new_one')->link()); | 27 | $crawler = $client->click($crawler->selectLink('user.list.create_new_one')->link()); |
28 | 28 | ||
@@ -36,7 +36,7 @@ class ManageControllerTest extends WallabagCoreTestCase | |||
36 | 36 | ||
37 | $client->submit($form); | 37 | $client->submit($form); |
38 | $client->followRedirect(); | 38 | $client->followRedirect(); |
39 | $crawler = $client->request('GET', '/users/'); | 39 | $crawler = $client->request('GET', '/users/list'); |
40 | 40 | ||
41 | // Check data in the show view | 41 | // Check data in the show view |
42 | $this->assertGreaterThan(0, $crawler->filter('td:contains("test_user")')->count(), 'Missing element td:contains("test_user")'); | 42 | $this->assertGreaterThan(0, $crawler->filter('td:contains("test_user")')->count(), 'Missing element td:contains("test_user")'); |
@@ -57,7 +57,7 @@ class ManageControllerTest extends WallabagCoreTestCase | |||
57 | // Check the element contains an attribute with value equals "Foo User" | 57 | // Check the element contains an attribute with value equals "Foo User" |
58 | $this->assertGreaterThan(0, $crawler->filter('[value="Foo User"]')->count(), 'Missing element [value="Foo User"]'); | 58 | $this->assertGreaterThan(0, $crawler->filter('[value="Foo User"]')->count(), 'Missing element [value="Foo User"]'); |
59 | 59 | ||
60 | $crawler = $client->request('GET', '/users/'); | 60 | $crawler = $client->request('GET', '/users/list'); |
61 | $crawler = $client->click($crawler->selectLink('user.list.edit_action')->last()->link()); | 61 | $crawler = $client->click($crawler->selectLink('user.list.edit_action')->last()->link()); |
62 | 62 | ||
63 | // Delete the user | 63 | // Delete the user |
@@ -78,4 +78,22 @@ class ManageControllerTest extends WallabagCoreTestCase | |||
78 | 78 | ||
79 | $this->assertEquals('disabled', $disabled[0]); | 79 | $this->assertEquals('disabled', $disabled[0]); |
80 | } | 80 | } |
81 | |||
82 | public function testUserSearch() | ||
83 | { | ||
84 | $this->logInAs('admin'); | ||
85 | $client = $this->getClient(); | ||
86 | |||
87 | // Search on unread list | ||
88 | $crawler = $client->request('GET', '/users/list'); | ||
89 | |||
90 | $form = $crawler->filter('form[name=search_users]')->form(); | ||
91 | $data = [ | ||
92 | 'search_user[term]' => 'admin', | ||
93 | ]; | ||
94 | |||
95 | $crawler = $client->submit($form, $data); | ||
96 | |||
97 | $this->assertCount(2, $crawler->filter('tr')); // 1 result + table header | ||
98 | } | ||
81 | } | 99 | } |