]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #1890 from wallabag/v2-api-annotation-switched
authorNicolas LÅ“uillet <nicolas@loeuillet.org>
Mon, 24 Oct 2016 08:06:12 +0000 (10:06 +0200)
committerGitHub <noreply@github.com>
Mon, 24 Oct 2016 08:06:12 +0000 (10:06 +0200)
bring annotations to API

src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php
src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
src/Wallabag/ApiBundle/Controller/WallabagRestController.php
tests/Wallabag/AnnotationBundle/Controller/AnnotationControllerTest.php
tests/Wallabag/AnnotationBundle/WallabagAnnotationTestCase.php

index ad083e31c6fa2a29d6852cc6f001b2961e68f815..c13a034ffe58f27c2f7fab0a388ef0e686fed4b6 100644 (file)
@@ -3,9 +3,8 @@
 namespace Wallabag\AnnotationBundle\Controller;
 
 use FOS\RestBundle\Controller\FOSRestController;
-use Nelmio\ApiDocBundle\Annotation\ApiDoc;
+use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\Response;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
 use Wallabag\AnnotationBundle\Entity\Annotation;
 use Wallabag\CoreBundle\Entity\Entry;
@@ -15,42 +14,35 @@ class WallabagAnnotationController extends FOSRestController
     /**
      * Retrieve annotations for an entry.
      *
-     * @ApiDoc(
-     *      requirements={
-     *          {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
-     *      }
-     * )
+     * @param Entry $entry
+     *
+     * @see Wallabag\ApiBundle\Controller\WallabagRestController
      *
-     * @return Response
+     * @return JsonResponse
      */
     public function getAnnotationsAction(Entry $entry)
     {
         $annotationRows = $this
-                ->getDoctrine()
-                ->getRepository('WallabagAnnotationBundle:Annotation')
-                ->findAnnotationsByPageId($entry->getId(), $this->getUser()->getId());
+            ->getDoctrine()
+            ->getRepository('WallabagAnnotationBundle:Annotation')
+            ->findAnnotationsByPageId($entry->getId(), $this->getUser()->getId());
         $total = count($annotationRows);
         $annotations = ['total' => $total, 'rows' => $annotationRows];
 
         $json = $this->get('serializer')->serialize($annotations, 'json');
 
-        return $this->renderJsonResponse($json);
+        return (new JsonResponse())->setJson($json);
     }
 
     /**
      * Creates a new annotation.
      *
-     * @param Entry $entry
+     * @param Request $request
+     * @param Entry   $entry
      *
-     * @ApiDoc(
-     *      requirements={
-     *          {"name"="ranges", "dataType"="array", "requirement"="\w+", "description"="The range array for the annotation"},
-     *          {"name"="quote", "dataType"="string", "required"=false, "description"="Optional, quote for the annotation"},
-     *          {"name"="text", "dataType"="string", "required"=true, "description"=""},
-     *      }
-     * )
+     * @return JsonResponse
      *
-     * @return Response
+     * @see Wallabag\ApiBundle\Controller\WallabagRestController
      */
     public function postAnnotationAction(Request $request, Entry $entry)
     {
@@ -75,21 +67,20 @@ class WallabagAnnotationController extends FOSRestController
 
         $json = $this->get('serializer')->serialize($annotation, 'json');
 
-        return $this->renderJsonResponse($json);
+        return (new JsonResponse())->setJson($json);
     }
 
     /**
      * Updates an annotation.
      *
-     * @ApiDoc(
-     *      requirements={
-     *          {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
-     *      }
-     * )
+     * @see Wallabag\ApiBundle\Controller\WallabagRestController
      *
      * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
      *
-     * @return Response
+     * @param Annotation $annotation
+     * @param Request    $request
+     *
+     * @return JsonResponse
      */
     public function putAnnotationAction(Annotation $annotation, Request $request)
     {
@@ -104,21 +95,19 @@ class WallabagAnnotationController extends FOSRestController
 
         $json = $this->get('serializer')->serialize($annotation, 'json');
 
-        return $this->renderJsonResponse($json);
+        return (new JsonResponse())->setJson($json);
     }
 
     /**
      * Removes an annotation.
      *
-     * @ApiDoc(
-     *      requirements={
-     *          {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
-     *      }
-     * )
+     * @see Wallabag\ApiBundle\Controller\WallabagRestController
      *
      * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
      *
-     * @return Response
+     * @param Annotation $annotation
+     *
+     * @return JsonResponse
      */
     public function deleteAnnotationAction(Annotation $annotation)
     {
@@ -128,19 +117,6 @@ class WallabagAnnotationController extends FOSRestController
 
         $json = $this->get('serializer')->serialize($annotation, 'json');
 
-        return $this->renderJsonResponse($json);
-    }
-
-    /**
-     * Send a JSON Response.
-     * We don't use the Symfony JsonRespone, because it takes an array as parameter instead of a JSON string.
-     *
-     * @param string $json
-     *
-     * @return Response
-     */
-    private function renderJsonResponse($json, $code = 200)
-    {
-        return new Response($json, $code, ['application/json']);
+        return (new JsonResponse())->setJson($json);
     }
 }
index 5f7da70ecfa4cb1d375fdbc94f68d9a019c2c4ce..8cccffba1366bb51c46f68de2bcec354c2b3a616 100644 (file)
@@ -50,7 +50,8 @@ class AnnotationRepository extends EntityRepository
     {
         return $this->createQueryBuilder('a')
             ->andWhere('a.id = :annotationId')->setParameter('annotationId', $annotationId)
-            ->getQuery()->getSingleResult()
+            ->getQuery()
+            ->getSingleResult()
         ;
     }
 
@@ -67,7 +68,8 @@ class AnnotationRepository extends EntityRepository
         return $this->createQueryBuilder('a')
             ->where('a.entry = :entryId')->setParameter('entryId', $entryId)
             ->andwhere('a.user = :userId')->setParameter('userId', $userId)
-            ->getQuery()->getResult()
+            ->getQuery()
+            ->getResult()
         ;
     }
 
index 3437bb9b96d937d836d3268e5eabcff2c894ad17..a73d44ca2bc35f79be45dbe004df022b552baa22 100644 (file)
@@ -6,12 +6,14 @@ use FOS\RestBundle\Controller\FOSRestController;
 use Hateoas\Configuration\Route as HateoasRoute;
 use Hateoas\Representation\Factory\PagerfantaFactory;
 use Nelmio\ApiDocBundle\Annotation\ApiDoc;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
 use Symfony\Component\Security\Core\Exception\AccessDeniedException;
 use Wallabag\CoreBundle\Entity\Entry;
 use Wallabag\CoreBundle\Entity\Tag;
+use Wallabag\AnnotationBundle\Entity\Annotation;
 
 class WallabagRestController extends FOSRestController
 {
@@ -517,6 +519,104 @@ class WallabagRestController extends FOSRestController
         return (new JsonResponse())->setJson($json);
     }
 
+    /**
+     * Retrieve annotations for an entry.
+     *
+     * @ApiDoc(
+     *      requirements={
+     *          {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
+     *      }
+     * )
+     *
+     * @param Entry $entry
+     *
+     * @return JsonResponse
+     */
+    public function getAnnotationsAction(Entry $entry)
+    {
+        $this->validateAuthentication();
+
+        return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:getAnnotations', [
+            'entry' => $entry,
+        ]);
+    }
+
+    /**
+     * Creates a new annotation.
+     *
+     * @ApiDoc(
+     *      requirements={
+     *          {"name"="ranges", "dataType"="array", "requirement"="\w+", "description"="The range array for the annotation"},
+     *          {"name"="quote", "dataType"="string", "required"=false, "description"="Optional, quote for the annotation"},
+     *          {"name"="text", "dataType"="string", "required"=true, "description"=""},
+     *      }
+     * )
+     *
+     * @param Request $request
+     * @param Entry   $entry
+     *
+     * @return JsonResponse
+     */
+    public function postAnnotationAction(Request $request, Entry $entry)
+    {
+        $this->validateAuthentication();
+
+        return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:postAnnotation', [
+            'request' => $request,
+            'entry' => $entry,
+        ]);
+    }
+
+    /**
+     * Updates an annotation.
+     *
+     * @ApiDoc(
+     *      requirements={
+     *          {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
+     *      }
+     * )
+     *
+     * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
+     *
+     * @param Annotation $annotation
+     * @param Request    $request
+     *
+     * @return JsonResponse
+     */
+    public function putAnnotationAction(Annotation $annotation, Request $request)
+    {
+        $this->validateAuthentication();
+
+        return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:putAnnotation', [
+            'annotation' => $annotation,
+            'request' => $request,
+        ]);
+    }
+
+    /**
+     * Removes an annotation.
+     *
+     * @ApiDoc(
+     *      requirements={
+     *          {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
+     *      }
+     * )
+     *
+     * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
+     *
+     * @param Annotation $annotation
+     *
+     * @return JsonResponse
+     */
+    public function deleteAnnotationAction(Annotation $annotation)
+    {
+        $this->validateAuthentication();
+
+        return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:deleteAnnotation', [
+            'annotation' => $annotation,
+        ]);
+    }
+
     /**
      * Retrieve version number.
      *
index 70849f74129000ca787a0a414396feb478516f81..cee0b8473dae5c6a766b33ed3e0bd8127493bfc6 100644 (file)
@@ -3,35 +3,80 @@
 namespace Tests\AnnotationBundle\Controller;
 
 use Tests\Wallabag\AnnotationBundle\WallabagAnnotationTestCase;
+use Wallabag\AnnotationBundle\Entity\Annotation;
+use Wallabag\CoreBundle\Entity\Entry;
 
 class AnnotationControllerTest extends WallabagAnnotationTestCase
 {
-    public function testGetAnnotations()
+    /**
+     * This data provider allow to tests annotation from the :
+     *     - API POV (when user use the api to manage annotations)
+     *     - and User POV (when user use the web interface - using javascript - to manage annotations)
+     */
+    public function dataForEachAnnotations()
     {
-        $annotation = $this->client->getContainer()
-            ->get('doctrine.orm.entity_manager')
-            ->getRepository('WallabagAnnotationBundle:Annotation')
-            ->findOneByUsername('admin');
+        return [
+            ['/api/annotations'],
+            ['annotations'],
+        ];
+    }
+
+    /**
+     * Test fetching annotations for an entry.
+     *
+     * @dataProvider dataForEachAnnotations
+     */
+    public function testGetAnnotations($prefixUrl)
+    {
+        $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
+
+        $user = $em
+            ->getRepository('WallabagUserBundle:User')
+            ->findOneByUserName('admin');
+        $entry = $em
+            ->getRepository('WallabagCoreBundle:Entry')
+            ->findOneByUsernameAndNotArchived('admin');
 
-        if (!$annotation) {
-            $this->markTestSkipped('No content found in db.');
+        $annotation = new Annotation($user);
+        $annotation->setEntry($entry);
+        $annotation->setText('This is my annotation /o/');
+        $annotation->setQuote('content');
+
+        $em->persist($annotation);
+        $em->flush();
+
+        if ('annotations' === $prefixUrl) {
+            $this->logInAs('admin');
         }
 
-        $this->logInAs('admin');
-        $crawler = $this->client->request('GET', 'annotations/'.$annotation->getEntry()->getId().'.json');
+        $this->client->request('GET', $prefixUrl.'/'.$entry->getId().'.json');
         $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
 
         $content = json_decode($this->client->getResponse()->getContent(), true);
-        $this->assertEquals(1, $content['total']);
+        $this->assertGreaterThanOrEqual(1, $content['total']);
         $this->assertEquals($annotation->getText(), $content['rows'][0]['text']);
+
+        // we need to re-fetch the annotation becase after the flush, it has been "detached" from the entity manager
+        $annotation = $em->getRepository('WallabagAnnotationBundle:Annotation')->findAnnotationById($annotation->getId());
+        $em->remove($annotation);
+        $em->flush();
     }
 
-    public function testSetAnnotation()
+    /**
+     * Test creating an annotation for an entry.
+     *
+     * @dataProvider dataForEachAnnotations
+     */
+    public function testSetAnnotation($prefixUrl)
     {
-        $this->logInAs('admin');
+        $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
 
-        $entry = $this->client->getContainer()
-            ->get('doctrine.orm.entity_manager')
+        if ('annotations' === $prefixUrl) {
+            $this->logInAs('admin');
+        }
+
+        /** @var Entry $entry */
+        $entry = $em
             ->getRepository('WallabagCoreBundle:Entry')
             ->findOneByUsernameAndNotArchived('admin');
 
@@ -41,7 +86,7 @@ class AnnotationControllerTest extends WallabagAnnotationTestCase
             'quote' => 'my quote',
             'ranges' => ['start' => '', 'startOffset' => 24, 'end' => '', 'endOffset' => 31],
         ]);
-        $crawler = $this->client->request('POST', 'annotations/'.$entry->getId().'.json', [], [], $headers, $content);
+        $this->client->request('POST', $prefixUrl.'/'.$entry->getId().'.json', [], [], $headers, $content);
 
         $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
 
@@ -52,6 +97,7 @@ class AnnotationControllerTest extends WallabagAnnotationTestCase
         $this->assertEquals('my annotation', $content['text']);
         $this->assertEquals('my quote', $content['quote']);
 
+        /** @var Annotation $annotation */
         $annotation = $this->client->getContainer()
             ->get('doctrine.orm.entity_manager')
             ->getRepository('WallabagAnnotationBundle:Annotation')
@@ -60,20 +106,35 @@ class AnnotationControllerTest extends WallabagAnnotationTestCase
         $this->assertEquals('my annotation', $annotation->getText());
     }
 
-    public function testEditAnnotation()
+    /**
+     * Test editing an existing annotation.
+     *
+     * @dataProvider dataForEachAnnotations
+     */
+    public function testEditAnnotation($prefixUrl)
     {
-        $annotation = $this->client->getContainer()
-            ->get('doctrine.orm.entity_manager')
-            ->getRepository('WallabagAnnotationBundle:Annotation')
-            ->findOneByUsername('admin');
+        $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
 
-        $this->logInAs('admin');
+        $user = $em
+            ->getRepository('WallabagUserBundle:User')
+            ->findOneByUserName('admin');
+        $entry = $em
+            ->getRepository('WallabagCoreBundle:Entry')
+            ->findOneByUsernameAndNotArchived('admin');
+
+        $annotation = new Annotation($user);
+        $annotation->setEntry($entry);
+        $annotation->setText('This is my annotation /o/');
+        $annotation->setQuote('my quote');
+
+        $em->persist($annotation);
+        $em->flush();
 
         $headers = ['CONTENT_TYPE' => 'application/json'];
         $content = json_encode([
             'text' => 'a modified annotation',
         ]);
-        $crawler = $this->client->request('PUT', 'annotations/'.$annotation->getId().'.json', [], [], $headers, $content);
+        $this->client->request('PUT', $prefixUrl.'/'.$annotation->getId().'.json', [], [], $headers, $content);
         $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
 
         $content = json_decode($this->client->getResponse()->getContent(), true);
@@ -83,35 +144,56 @@ class AnnotationControllerTest extends WallabagAnnotationTestCase
         $this->assertEquals('a modified annotation', $content['text']);
         $this->assertEquals('my quote', $content['quote']);
 
-        $annotationUpdated = $this->client->getContainer()
-            ->get('doctrine.orm.entity_manager')
+        /** @var Annotation $annotationUpdated */
+        $annotationUpdated = $em
             ->getRepository('WallabagAnnotationBundle:Annotation')
             ->findOneById($annotation->getId());
         $this->assertEquals('a modified annotation', $annotationUpdated->getText());
+
+        $em->remove($annotationUpdated);
+        $em->flush();
     }
 
-    public function testDeleteAnnotation()
+    /**
+     * Test deleting an annotation.
+     *
+     * @dataProvider dataForEachAnnotations
+     */
+    public function testDeleteAnnotation($prefixUrl)
     {
-        $annotation = $this->client->getContainer()
-            ->get('doctrine.orm.entity_manager')
-            ->getRepository('WallabagAnnotationBundle:Annotation')
-            ->findOneByUsername('admin');
+        $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
 
-        $this->logInAs('admin');
+        $user = $em
+            ->getRepository('WallabagUserBundle:User')
+            ->findOneByUserName('admin');
+        $entry = $em
+            ->getRepository('WallabagCoreBundle:Entry')
+            ->findOneByUsernameAndNotArchived('admin');
+
+        $annotation = new Annotation($user);
+        $annotation->setEntry($entry);
+        $annotation->setText('This is my annotation /o/');
+        $annotation->setQuote('my quote');
+
+        $em->persist($annotation);
+        $em->flush();
+
+        if ('annotations' === $prefixUrl) {
+            $this->logInAs('admin');
+        }
 
         $headers = ['CONTENT_TYPE' => 'application/json'];
         $content = json_encode([
             'text' => 'a modified annotation',
         ]);
-        $crawler = $this->client->request('DELETE', 'annotations/'.$annotation->getId().'.json', [], [], $headers, $content);
+        $this->client->request('DELETE', $prefixUrl.'/'.$annotation->getId().'.json', [], [], $headers, $content);
         $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
 
         $content = json_decode($this->client->getResponse()->getContent(), true);
 
-        $this->assertEquals('a modified annotation', $content['text']);
+        $this->assertEquals('This is my annotation /o/', $content['text']);
 
-        $annotationDeleted = $this->client->getContainer()
-            ->get('doctrine.orm.entity_manager')
+        $annotationDeleted = $em
             ->getRepository('WallabagAnnotationBundle:Annotation')
             ->findOneById($annotation->getId());
 
index 82790a5c43c350d7bca672d3a19380b85b525421..ef3f1324eb3937fe2f76c0e370dc976844543232 100644 (file)
@@ -8,7 +8,7 @@ use Symfony\Component\BrowserKit\Cookie;
 abstract class WallabagAnnotationTestCase extends WebTestCase
 {
     /**
-     * @var Client
+     * @var \Symfony\Bundle\FrameworkBundle\Client
      */
     protected $client = null;
 
@@ -35,7 +35,7 @@ abstract class WallabagAnnotationTestCase extends WebTestCase
     }
 
     /**
-     * @return Client
+     * @return \Symfony\Bundle\FrameworkBundle\Client
      */
     protected function createAuthorizedClient()
     {
@@ -49,7 +49,7 @@ abstract class WallabagAnnotationTestCase extends WebTestCase
         $firewallName = $container->getParameter('fos_user.firewall_name');
 
         $this->user = $userManager->findUserBy(['username' => 'admin']);
-        $loginManager->loginUser($firewallName, $this->user);
+        $loginManager->logInUser($firewallName, $this->user);
 
         // save the login token into the session and put it in a cookie
         $container->get('session')->set('_security_'.$firewallName, serialize($container->get('security.token_storage')->getToken()));