diff --git a/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php b/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php index ad083e31c..c13a034ff 100644 --- a/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php +++ b/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php @@ -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 * - * @return Response + * @see Wallabag\ApiBundle\Controller\WallabagRestController + * + * @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); } } diff --git a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php index 5f7da70ec..8cccffba1 100644 --- a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php +++ b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php @@ -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() ; } diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php index 3437bb9b9..a73d44ca2 100644 --- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php @@ -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. * diff --git a/tests/Wallabag/AnnotationBundle/Controller/AnnotationControllerTest.php b/tests/Wallabag/AnnotationBundle/Controller/AnnotationControllerTest.php index 70849f741..cee0b8473 100644 --- a/tests/Wallabag/AnnotationBundle/Controller/AnnotationControllerTest.php +++ b/tests/Wallabag/AnnotationBundle/Controller/AnnotationControllerTest.php @@ -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'], + ]; + } - if (!$annotation) { - $this->markTestSkipped('No content found in db.'); + /** + * 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'); + + $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()); diff --git a/tests/Wallabag/AnnotationBundle/WallabagAnnotationTestCase.php b/tests/Wallabag/AnnotationBundle/WallabagAnnotationTestCase.php index 82790a5c4..ef3f1324e 100644 --- a/tests/Wallabag/AnnotationBundle/WallabagAnnotationTestCase.php +++ b/tests/Wallabag/AnnotationBundle/WallabagAnnotationTestCase.php @@ -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()));