]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #2372 from pmartin/api-get-entry-as-epub
authorJeremy Benoist <j0k3r@users.noreply.github.com>
Wed, 12 Oct 2016 12:06:33 +0000 (14:06 +0200)
committerGitHub <noreply@github.com>
Wed, 12 Oct 2016 12:06:33 +0000 (14:06 +0200)
API: ability to export entry in all available format (epub, pdf, etc...)

1  2 
app/config/config.yml
src/Wallabag/ApiBundle/Controller/WallabagRestController.php
tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php

diff --combined app/config/config.yml
index bcc4c8eb0f5940c0fa904e5143293c6eef02bc10,48f317c7ee63f2f40eaa4c84c3d3467c04758e08..2f102c45c6af9dadb068b470f9f5e31cb76c0919
@@@ -30,7 -30,7 +30,7 @@@ framework
      assets: ~
  
  wallabag_core:
 -    version: 2.1.1
 +    version: 2.1.2-dev
      paypal_url: "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9UBA65LG3FX9Y&lc=gb"
      languages:
          en: 'English'
@@@ -130,6 -130,8 +130,8 @@@ fos_rest
  nelmio_api_doc:
      sandbox:
          enabled: false
+     cache:
+         enabled: true
      name: wallabag API documentation
  
  nelmio_cors:
index 9997913d2afefbd7c0f03143b17640470f1a42ae,8587558921bfc172d0c28c7571aeb9919e1180f8..fa573988b9c90b60628514850e4e5e9d633d7d2f
@@@ -3,7 -3,7 +3,7 @@@
  namespace Wallabag\ApiBundle\Controller;
  
  use FOS\RestBundle\Controller\FOSRestController;
- use Hateoas\Configuration\Route;
+ use Hateoas\Configuration\Route as HateoasRoute;
  use Hateoas\Representation\Factory\PagerfantaFactory;
  use Nelmio\ApiDocBundle\Annotation\ApiDoc;
  use Symfony\Component\HttpFoundation\Request;
@@@ -12,6 -12,7 +12,7 @@@ use Symfony\Component\Routing\Generator
  use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  use Wallabag\CoreBundle\Entity\Entry;
  use Wallabag\CoreBundle\Entity\Tag;
+ use FOS\RestBundle\Controller\Annotations\Route;
  
  class WallabagRestController extends FOSRestController
  {
@@@ -27,8 -28,7 +28,8 @@@
       *
       * @ApiDoc(
       *       parameters={
 -     *          {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}
 +     *          {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"},
 +     *          {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="Urls (as an array) to check if it exists"}
       *       }
       * )
       *
      {
          $this->validateAuthentication();
  
 +        $urls = $request->query->get('urls', []);
 +
 +        // handle multiple urls first
 +        if (!empty($urls)) {
 +            $results = [];
 +            foreach ($urls as $url) {
 +                $res = $this->getDoctrine()
 +                    ->getRepository('WallabagCoreBundle:Entry')
 +                    ->findByUrlAndUserId($url, $this->getUser()->getId());
 +
 +                $results[$url] = false === $res ? false : true;
 +            }
 +
 +            $json = $this->get('serializer')->serialize($results, 'json');
 +
 +            return (new JsonResponse())->setJson($json);
 +        }
 +
 +        // let's see if it is a simple url?
          $url = $request->query->get('url', '');
  
          if (empty($url)) {
          $pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
          $paginatedCollection = $pagerfantaFactory->createRepresentation(
              $pager,
-             new Route(
+             new HateoasRoute(
                  'api_get_entries',
                  [
                      'archive' => $isArchived,
          return (new JsonResponse())->setJson($json);
      }
  
+     /**
+      * Retrieve a single entry as a predefined format.
+      *
+      * @ApiDoc(
+      *      requirements={
+      *          {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
+      *      }
+      * )
+      *
+      * @Route(requirements={"_format"="epub|mobi|pdf|txt|csv"})
+      *
+      * @return Response
+      */
+     public function getEntryExportAction(Entry $entry, Request $request)
+     {
+         $this->validateAuthentication();
+         $this->validateUserAccess($entry->getUser()->getId());
+         return $this->get('wallabag_core.helper.entries_export')
+             ->setEntries($entry)
+             ->updateTitle('entry')
+             ->exportAs($request->attributes->get('_format'));
+     }
      /**
       * Create an entry.
       *
  
          $tags = $this->getDoctrine()
              ->getRepository('WallabagCoreBundle:Tag')
 -            ->findAllTagsWithEntries($this->getUser()->getId());
 +            ->findAllTags($this->getUser()->getId());
  
          $json = $this->get('serializer')->serialize($tags, 'json');
  
              ->getRepository('WallabagCoreBundle:Entry')
              ->removeTag($this->getUser()->getId(), $tag);
  
 +        $this->cleanOrphanTag($tag);
 +
          $json = $this->get('serializer')->serialize($tag, 'json');
  
          return (new JsonResponse())->setJson($json);
              ->getRepository('WallabagCoreBundle:Entry')
              ->removeTags($this->getUser()->getId(), $tags);
  
 +        $this->cleanOrphanTag($tags);
 +
          $json = $this->get('serializer')->serialize($tags, 'json');
  
          return (new JsonResponse())->setJson($json);
              ->getRepository('WallabagCoreBundle:Entry')
              ->removeTag($this->getUser()->getId(), $tag);
  
 +        $this->cleanOrphanTag($tag);
 +
          $json = $this->get('serializer')->serialize($tag, 'json');
  
          return (new JsonResponse())->setJson($json);
          return (new JsonResponse())->setJson($json);
      }
  
 +    /**
 +     * Remove orphan tag in case no entries are associated to it.
 +     *
 +     * @param Tag|array $tags
 +     */
 +    private function cleanOrphanTag($tags)
 +    {
 +        if (!is_array($tags)) {
 +            $tags = [$tags];
 +        }
 +
 +        $em = $this->getDoctrine()->getManager();
 +
 +        foreach ($tags as $tag) {
 +            if (count($tag->getEntries()) === 0) {
 +                $em->remove($tag);
 +            }
 +        }
 +
 +        $em->flush();
 +    }
 +
      /**
       * Validate that the first id is equal to the second one.
       * If not, throw exception. It means a user try to access information from an other user.
index 5dcb3e000dac75d68f0026851856dcdc0692973b,79353857c65f29824d706e37559f02117eecb80e..6bca3c8bb9b1931b84bc16394bd5e33eb6f6485b
@@@ -32,12 -32,55 +32,55 @@@ class WallabagRestControllerTest extend
          $this->assertEquals($entry->getUserEmail(), $content['user_email']);
          $this->assertEquals($entry->getUserId(), $content['user_id']);
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
+     }
+     public function testExportEntry()
+     {
+         $entry = $this->client->getContainer()
+             ->get('doctrine.orm.entity_manager')
+             ->getRepository('WallabagCoreBundle:Entry')
+             ->findOneBy(['user' => 1, 'isArchived' => false]);
+         if (!$entry) {
+             $this->markTestSkipped('No content found in db.');
+         }
+         $this->client->request('GET', '/api/entries/'.$entry->getId().'/export.epub');
+         $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
+         // epub format got the content type in the content
+         $this->assertContains('application/epub', $this->client->getResponse()->getContent());
+         $this->assertEquals('application/epub+zip', $this->client->getResponse()->headers->get('Content-Type'));
+         // re-auth client for mobi
+         $client = $this->createAuthorizedClient();
+         $client->request('GET', '/api/entries/'.$entry->getId().'/export.mobi');
+         $this->assertEquals(200, $client->getResponse()->getStatusCode());
+         $this->assertEquals('application/x-mobipocket-ebook', $client->getResponse()->headers->get('Content-Type'));
+         // re-auth client for pdf
+         $client = $this->createAuthorizedClient();
+         $client->request('GET', '/api/entries/'.$entry->getId().'/export.pdf');
+         $this->assertEquals(200, $client->getResponse()->getStatusCode());
+         $this->assertContains('PDF-', $client->getResponse()->getContent());
+         $this->assertEquals('application/pdf', $client->getResponse()->headers->get('Content-Type'));
+         // re-auth client for pdf
+         $client = $this->createAuthorizedClient();
+         $client->request('GET', '/api/entries/'.$entry->getId().'/export.txt');
+         $this->assertEquals(200, $client->getResponse()->getStatusCode());
+         $this->assertContains('text/plain', $client->getResponse()->headers->get('Content-Type'));
+         // re-auth client for pdf
+         $client = $this->createAuthorizedClient();
+         $client->request('GET', '/api/entries/'.$entry->getId().'/export.csv');
+         $this->assertEquals(200, $client->getResponse()->getStatusCode());
+         $this->assertContains('application/csv', $client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testGetOneEntryWrongUser()
          $this->assertEquals(1, $content['page']);
          $this->assertGreaterThanOrEqual(1, $content['pages']);
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testGetEntriesWithFullOptions()
              $this->assertContains('since=1443274283', $content['_links'][$link]['href']);
          }
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testGetStarredEntries()
              $this->assertContains('sort=updated', $content['_links'][$link]['href']);
          }
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testGetArchiveEntries()
              $this->assertContains('archive=1', $content['_links'][$link]['href']);
          }
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testGetTaggedEntries()
              $this->assertContains('tags='.urlencode('foo,bar'), $content['_links'][$link]['href']);
          }
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testGetDatedEntries()
              $this->assertContains('since=1443274283', $content['_links'][$link]['href']);
          }
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testGetDatedSupEntries()
              $this->assertContains('since='.($future->getTimestamp() + 1000), $content['_links'][$link]['href']);
          }
  
-         $this->assertTrue(
-             $this->client->getResponse()->headers->contains(
-                 'Content-Type',
-                 'application/json'
-             )
-         );
+         $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
      }
  
      public function testDeleteEntry()
       */
      public function testDeleteUserTag($tag)
      {
 +        $tagName = $tag['label'];
 +
          $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json');
  
          $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
              ->findAllByTagId($this->user->getId(), $tag['id']);
  
          $this->assertCount(0, $entries);
 +
 +        $tag = $this->client->getContainer()
 +            ->get('doctrine.orm.entity_manager')
 +            ->getRepository('WallabagCoreBundle:Tag')
 +            ->findOneByLabel($tagName);
 +
 +        $this->assertNull($tag, $tagName.' was removed because it begun an orphan tag');
      }
  
      public function testDeleteTagByLabel()
          $this->assertEquals(true, $content['exists']);
      }
  
 +    public function testGetEntriesExistsWithManyUrls()
 +    {
 +        $url1 = 'http://0.0.0.0/entry2';
 +        $url2 = 'http://0.0.0.0/entry10';
 +        $this->client->request('GET', '/api/entries/exists?urls[]='.$url1.'&urls[]='.$url2);
 +
 +        $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
 +
 +        $content = json_decode($this->client->getResponse()->getContent(), true);
 +
 +        $this->assertArrayHasKey($url1, $content);
 +        $this->assertArrayHasKey($url2, $content);
 +        $this->assertEquals(true, $content[$url1]);
 +        $this->assertEquals(false, $content[$url2]);
 +    }
 +
      public function testGetEntriesExistsWhichDoesNotExists()
      {
          $this->client->request('GET', '/api/entries/exists?url=http://google.com/entry2');