From: Jeremy Benoist Date: Tue, 9 May 2017 11:55:31 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/master' into 2.3 X-Git-Tag: 2.3.0~31^2~103 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=54c2d164a362e64a320438b439bf9dd6d2c02424;hp=-c;p=github%2Fwallabag%2Fwallabag.git Merge remote-tracking branch 'origin/master' into 2.3 --- 54c2d164a362e64a320438b439bf9dd6d2c02424 diff --combined docs/de/user/upgrade.rst index af3b96fb,76faa4e2..fa2aac45 --- a/docs/de/user/upgrade.rst +++ b/docs/de/user/upgrade.rst @@@ -61,9 -61,9 +61,9 @@@ Lade das letzte Release von wallabag he .. code-block:: bash - wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package + wget https://wllbg.org/latest-v2-package && tar xvf latest-v2-package -Du findest den `aktuellen MD5-Hash auf unserer Webseite `_. +Du findest den `aktuellen MD5-Hash auf unserer Webseite `_. Extrahiere das Archiv in deinen wallabag-Ordner und ersetze die ``app/config/parameters.yml`` mit deiner. diff --combined docs/en/user/upgrade.rst index 359a355f,46b490c3..3157684c --- a/docs/en/user/upgrade.rst +++ b/docs/en/user/upgrade.rst @@@ -65,9 -65,9 +65,9 @@@ Download the last release of wallabag .. code-block:: bash - wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package + wget https://wllbg.org/latest-v2-package && tar xvf latest-v2-package -You will find the `md5 hash of the latest package on our website `_. +You will find the `md5 hash of the latest package on our website `_. Extract the archive in your wallabag folder and replace ``app/config/parameters.yml`` with yours. diff --combined docs/fr/user/upgrade.rst index 5bb42deb,af97ebb2..af198006 --- a/docs/fr/user/upgrade.rst +++ b/docs/fr/user/upgrade.rst @@@ -61,9 -61,9 +61,9 @@@ Téléchargez la dernière version de w .. code-block:: bash - wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package + wget https://wllbg.org/latest-v2-package && tar xvf latest-v2-package -Vous trouverez `le hash md5 du dernier package sur notre site `_. +Vous trouverez `le hash md5 du dernier package sur notre site `_. Décompressez l'archive dans votre répertoire d'installation et remplacez le fichier ``app/config/parameters.yml`` avec le votre. diff --combined docs/it/user/installation.rst index c067228d,95d781e6..174507b8 --- a/docs/it/user/installation.rst +++ b/docs/it/user/installation.rst @@@ -86,9 -86,9 +86,9 @@@ Eseguite questo comando per scaricare e .. code-block:: bash - wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package + wget https://wllbg.org/latest-v2-package && tar xvf latest-v2-package -Troverete il `hash md5 del pacchetto piú aggiornato sul nostro sito `_. +Troverete il `hash md5 del pacchetto piú aggiornato sul nostro sito `_. Ora leggete la seguente documentazione per creare il vostro host virtuale poi accedete al vostro wallabag. Se avete cambiato la configurazione del database per usare MySQL o PostrgreSQL, dovrete creare un utente con il comando php bin/console wallabag:install --env=prod . @@@ -103,13 -103,6 +103,13 @@@ Comando per avviare il containe docker pull wallabag/wallabag +Installazione su Cloudron +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Cloudron fornisce un modo facile di installare webapps sul vostro server mirato ad automatizzare i compiti del sysadmin ed a mantenere le app aggiornate. +wallabag é pacchettizzata come app Cloudron ed é disponibile all'installazione direttamente dallo store. + +`Installa wallabag sul tuo Cloudron `__ Host virtuali ------------- diff --combined docs/it/user/upgrade.rst index 52cd98c7,e1c3f041..ede1a1a3 --- a/docs/it/user/upgrade.rst +++ b/docs/it/user/upgrade.rst @@@ -78,9 -78,9 +78,9 @@@ Scaricate l'ultima versione di wallabag . code-block:: bash - wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package + wget https://wllbg.org/latest-v2-package && tar xvf latest-v2-package -Troverete il `hash md5 dell'ultima versione del pacchetto sul nostro sito `_. +Troverete il `hash md5 dell'ultima versione del pacchetto sul nostro sito `_. Estraete l'archivio nella vostra cartella di wallabag e rimpiazzate ``app/config/parameters.yml`` con il vostro. @@@ -98,5 -98,5 +98,5 @@@ Da wallabag 1. Non esiste uno script automatico per aggiornare da wallabag 1.x a wallabag 2.x. Dovete: - esportare i vostri dati -- installare wallabag 2.x (leggete la documentazione a proposito dell'installazione *link mancante*) +- installare wallabag 2.x (leggete la documentazione a proposito dell'installazione *link mancante*) - importate i dati in questa nuova installazione (leggete la documentazione a proposito dell'importazione) diff --combined src/Wallabag/ApiBundle/Controller/EntryRestController.php index dbff6065,c544815e..632b16d9 --- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php +++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php @@@ -5,7 -5,6 +5,7 @@@ namespace Wallabag\ApiBundle\Controller use Hateoas\Configuration\Route; use Hateoas\Representation\Factory\PagerfantaFactory; use Nelmio\ApiDocBundle\Annotation\ApiDoc; +use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@@ -42,10 -41,12 +42,10 @@@ class EntryRestController extends Walla ->getRepository('WallabagCoreBundle:Entry') ->findByUrlAndUserId($url, $this->getUser()->getId()); - $results[$url] = false === $res ? false : true; + $results[$url] = $res instanceof Entry ? $res->getId() : false; } - $json = $this->get('serializer')->serialize($results, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($results); } // let's see if it is a simple url? @@@ -59,9 -60,11 +59,9 @@@ ->getRepository('WallabagCoreBundle:Entry') ->findByUrlAndUserId($url, $this->getUser()->getId()); - $exists = false === $res ? false : true; - - $json = $this->get('serializer')->serialize(['exists' => $exists], 'json'); + $exists = $res instanceof Entry ? $res->getId() : false; - return (new JsonResponse())->setJson($json); + return $this->sendResponse(['exists' => $exists]); } /** @@@ -95,12 -98,13 +95,13 @@@ $tags = $request->query->get('tags', ''); $since = $request->query->get('since', 0); + /** @var \Pagerfanta\Pagerfanta $pager */ $pager = $this->getDoctrine() ->getRepository('WallabagCoreBundle:Entry') ->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order, $since, $tags); - $pager->setCurrentPage($page); $pager->setMaxPerPage($perPage); + $pager->setCurrentPage($page); $pagerfantaFactory = new PagerfantaFactory('page', 'perPage'); $paginatedCollection = $pagerfantaFactory->createRepresentation( @@@ -121,7 -125,9 +122,7 @@@ ) ); - $json = $this->get('serializer')->serialize($paginatedCollection, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($paginatedCollection); } /** @@@ -140,7 -146,9 +141,7 @@@ $this->validateAuthentication(); $this->validateUserAccess($entry->getUser()->getId()); - $json = $this->get('serializer')->serialize($entry, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($entry); } /** @@@ -165,110 -173,6 +166,110 @@@ ->exportAs($request->attributes->get('_format')); } + /** + * Handles an entries list and delete URL. + * + * @ApiDoc( + * parameters={ + * {"name"="urls", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...'}, {'url': 'http://...'}]", "description"="Urls (as an array) to delete."} + * } + * ) + * + * @return JsonResponse + */ + public function deleteEntriesListAction(Request $request) + { + $this->validateAuthentication(); + + $urls = json_decode($request->query->get('urls', [])); + + if (empty($urls)) { + return $this->sendResponse([]); + } + + $results = []; + + // handle multiple urls + foreach ($urls as $key => $url) { + $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( + $url, + $this->getUser()->getId() + ); + + $results[$key]['url'] = $url; + + if (false !== $entry) { + $em = $this->getDoctrine()->getManager(); + $em->remove($entry); + $em->flush(); + + // entry deleted, dispatch event about it! + $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); + } + + $results[$key]['entry'] = $entry instanceof Entry ? true : false; + } + + return $this->sendResponse($results); + } + + /** + * Handles an entries list and create URL. + * + * @ApiDoc( + * parameters={ + * {"name"="urls", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...'}, {'url': 'http://...'}]", "description"="Urls (as an array) to create."} + * } + * ) + * + * @return JsonResponse + * + * @throws HttpException When limit is reached + */ + public function postEntriesListAction(Request $request) + { + $this->validateAuthentication(); + + $urls = json_decode($request->query->get('urls', [])); + $results = []; + + $limit = $this->container->getParameter('wallabag_core.api_limit_mass_actions'); + + if (count($urls) > $limit) { + throw new HttpException(400, 'API limit reached'); + } + + // handle multiple urls + if (!empty($urls)) { + foreach ($urls as $key => $url) { + $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( + $url, + $this->getUser()->getId() + ); + + $results[$key]['url'] = $url; + + if (false === $entry) { + $entry = $this->get('wallabag_core.content_proxy')->updateEntry( + new Entry($this->getUser()), + $url + ); + } + + $em = $this->getDoctrine()->getManager(); + $em->persist($entry); + $em->flush(); + + $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; + + // entry saved, dispatch event about it! + $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); + } + } + + return $this->sendResponse($results); + } + /** * Create an entry. * @@@ -326,7 -230,9 +327,7 @@@ // entry saved, dispatch event about it! $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); - $json = $this->get('serializer')->serialize($entry, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($entry); } /** @@@ -375,7 -281,9 +376,7 @@@ $em = $this->getDoctrine()->getManager(); $em->flush(); - $json = $this->get('serializer')->serialize($entry, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($entry); } /** @@@ -418,7 -326,9 +419,7 @@@ // entry saved, dispatch event about it! $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); - $json = $this->get('serializer')->serialize($entry, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($entry); } /** @@@ -444,7 -354,9 +445,7 @@@ // entry deleted, dispatch event about it! $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); - $json = $this->get('serializer')->serialize($entry, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($entry); } /** @@@ -463,7 -375,9 +464,7 @@@ $this->validateAuthentication(); $this->validateUserAccess($entry->getUser()->getId()); - $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($entry->getTags()); } /** @@@ -494,7 -408,9 +495,7 @@@ $em->persist($entry); $em->flush(); - $json = $this->get('serializer')->serialize($entry, 'json'); - - return (new JsonResponse())->setJson($json); + return $this->sendResponse($entry); } /** @@@ -519,124 -435,7 +520,124 @@@ $em->persist($entry); $em->flush(); - $json = $this->get('serializer')->serialize($entry, 'json'); + return $this->sendResponse($entry); + } + + /** + * Handles an entries list delete tags from them. + * + * @ApiDoc( + * parameters={ + * {"name"="list", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...','tags': 'tag1, tag2'}, {'url': 'http://...','tags': 'tag1, tag2'}]", "description"="Urls (as an array) to handle."} + * } + * ) + * + * @return JsonResponse + */ + public function deleteEntriesTagsListAction(Request $request) + { + $this->validateAuthentication(); + + $list = json_decode($request->query->get('list', [])); + + if (empty($list)) { + return $this->sendResponse([]); + } + + // handle multiple urls + $results = []; + + foreach ($list as $key => $element) { + $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( + $element->url, + $this->getUser()->getId() + ); + + $results[$key]['url'] = $element->url; + $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; + + $tags = $element->tags; + + if (false !== $entry && !(empty($tags))) { + $tags = explode(',', $tags); + foreach ($tags as $label) { + $label = trim($label); + + $tag = $this->getDoctrine() + ->getRepository('WallabagCoreBundle:Tag') + ->findOneByLabel($label); + + if (false !== $tag) { + $entry->removeTag($tag); + } + } + + $em = $this->getDoctrine()->getManager(); + $em->persist($entry); + $em->flush(); + } + } + + return $this->sendResponse($results); + } + + /** + * Handles an entries list and add tags to them. + * + * @ApiDoc( + * parameters={ + * {"name"="list", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...','tags': 'tag1, tag2'}, {'url': 'http://...','tags': 'tag1, tag2'}]", "description"="Urls (as an array) to handle."} + * } + * ) + * + * @return JsonResponse + */ + public function postEntriesTagsListAction(Request $request) + { + $this->validateAuthentication(); + + $list = json_decode($request->query->get('list', [])); + + if (empty($list)) { + return $this->sendResponse([]); + } + + $results = []; + + // handle multiple urls + foreach ($list as $key => $element) { + $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( + $element->url, + $this->getUser()->getId() + ); + + $results[$key]['url'] = $element->url; + $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; + + $tags = $element->tags; + + if (false !== $entry && !(empty($tags))) { + $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags); + + $em = $this->getDoctrine()->getManager(); + $em->persist($entry); + $em->flush(); + } + } + + return $this->sendResponse($results); + } + + /** + * Shortcut to send data serialized in json. + * + * @param mixed $data + * + * @return JsonResponse + */ + private function sendResponse($data) + { + $json = $this->get('serializer')->serialize($data, 'json'); return (new JsonResponse())->setJson($json); } diff --combined tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php index 362c269b,63d70bd9..4f49f040 --- a/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php +++ b/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php @@@ -156,6 -156,22 +156,22 @@@ class EntryRestControllerTest extends W $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type')); } + public function testGetEntriesOnPageTwo() + { + $this->client->request('GET', '/api/entries', [ + 'page' => 2, + 'perPage' => 2, + ]); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertGreaterThanOrEqual(0, $content['total']); + $this->assertEquals(2, $content['page']); + $this->assertEquals(2, $content['limit']); + } + public function testGetStarredEntries() { $this->client->request('GET', '/api/entries', ['starred' => 1, 'sort' => 'updated']); @@@ -298,7 -314,7 +314,7 @@@ $entry = $this->client->getContainer() ->get('doctrine.orm.entity_manager') ->getRepository('WallabagCoreBundle:Entry') - ->findOneByUser(1); + ->findOneByUser(1, ['id' => 'asc']); if (!$entry) { $this->markTestSkipped('No content found in db.'); @@@ -337,7 -353,7 +353,7 @@@ $this->assertEquals(false, $content['is_starred']); $this->assertEquals('New title for my article', $content['title']); $this->assertEquals(1, $content['user_id']); - $this->assertCount(1, $content['tags']); + $this->assertCount(2, $content['tags']); } public function testPostSameEntry() @@@ -356,7 -372,7 +372,7 @@@ $this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); $this->assertEquals(true, $content['is_archived']); $this->assertEquals(false, $content['is_starred']); - $this->assertCount(2, $content['tags']); + $this->assertCount(3, $content['tags']); } public function testPostArchivedAndStarredEntry() @@@ -642,7 -658,7 +658,7 @@@ $content = json_decode($this->client->getResponse()->getContent(), true); - $this->assertEquals(true, $content['exists']); + $this->assertEquals(2, $content['exists']); } public function testGetEntriesExistsWithManyUrls() @@@ -657,7 -673,7 +673,7 @@@ $this->assertArrayHasKey($url1, $content); $this->assertArrayHasKey($url2, $content); - $this->assertEquals(true, $content[$url1]); + $this->assertEquals(2, $content[$url1]); $this->assertEquals(false, $content[$url2]); } @@@ -714,120 -730,4 +730,120 @@@ $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type')); } + + public function testPostEntriesTagsListAction() + { + $entry = $this->client->getContainer()->get('doctrine.orm.entity_manager') + ->getRepository('WallabagCoreBundle:Entry') + ->findByUrlAndUserId('http://0.0.0.0/entry4', 1); + + $tags = $entry->getTags(); + + $this->assertCount(2, $tags); + + $list = [ + [ + 'url' => 'http://0.0.0.0/entry4', + 'tags' => 'new tag 1, new tag 2', + ], + ]; + + $this->client->request('POST', '/api/entries/tags/lists?list='.json_encode($list)); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertInternalType('int', $content[0]['entry']); + $this->assertEquals('http://0.0.0.0/entry4', $content[0]['url']); + + $entry = $this->client->getContainer()->get('doctrine.orm.entity_manager') + ->getRepository('WallabagCoreBundle:Entry') + ->findByUrlAndUserId('http://0.0.0.0/entry4', 1); + + $tags = $entry->getTags(); + $this->assertCount(4, $tags); + } + + public function testDeleteEntriesTagsListAction() + { + $entry = $this->client->getContainer()->get('doctrine.orm.entity_manager') + ->getRepository('WallabagCoreBundle:Entry') + ->findByUrlAndUserId('http://0.0.0.0/entry4', 1); + + $tags = $entry->getTags(); + + $this->assertCount(4, $tags); + + $list = [ + [ + 'url' => 'http://0.0.0.0/entry4', + 'tags' => 'new tag 1, new tag 2', + ], + ]; + + $this->client->request('DELETE', '/api/entries/tags/list?list='.json_encode($list)); + } + + public function testPostEntriesListAction() + { + $list = [ + 'http://www.lemonde.fr/musiques/article/2017/04/23/loin-de-la-politique-le-printemps-de-bourges-retombe-en-enfance_5115862_1654986.html', + 'http://0.0.0.0/entry2', + ]; + + $this->client->request('POST', '/api/entries/lists?urls='.json_encode($list)); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertInternalType('int', $content[0]['entry']); + $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']); + + $this->assertInternalType('int', $content[1]['entry']); + $this->assertEquals('http://0.0.0.0/entry2', $content[1]['url']); + } + + public function testDeleteEntriesListAction() + { + $list = [ + 'http://www.lemonde.fr/musiques/article/2017/04/23/loin-de-la-politique-le-printemps-de-bourges-retombe-en-enfance_5115862_1654986.html', + 'http://0.0.0.0/entry3', + ]; + + $this->client->request('DELETE', '/api/entries/list?urls='.json_encode($list)); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertTrue($content[0]['entry']); + $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']); + + $this->assertFalse($content[1]['entry']); + $this->assertEquals('http://0.0.0.0/entry3', $content[1]['url']); + } + + public function testLimitBulkAction() + { + $list = [ + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + 'http://0.0.0.0/entry1', + ]; + + $this->client->request('POST', '/api/entries/lists?urls='.json_encode($list)); + + $this->assertEquals(400, $this->client->getResponse()->getStatusCode()); + $this->assertContains('API limit reached', $this->client->getResponse()->getContent()); + } }