diff --git a/newscoop/application/configs/symfony/config.yml b/newscoop/application/configs/symfony/config.yml index 0ec8026396..a5d7476b7a 100644 --- a/newscoop/application/configs/symfony/config.yml +++ b/newscoop/application/configs/symfony/config.yml @@ -61,7 +61,7 @@ fos_rest: codes: 'Newscoop\Exception\ResourcesConflictException': 409 'Newscoop\Exception\InvalidParametersException': 422 - 'Newscoop\Exception\ResourceIsEmptyException': 204 + 'Newscoop\Exception\ResourceIsEmptyException': 200 'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404 'Doctrine\ORM\EntityNotFoundException': 404 'Symfony\Component\Form\Exception\InvalidArgumentException': 500 diff --git a/newscoop/application/configs/symfony/routing.yml b/newscoop/application/configs/symfony/routing.yml index 522381a612..db58b987cd 100644 --- a/newscoop/application/configs/symfony/routing.yml +++ b/newscoop/application/configs/symfony/routing.yml @@ -41,6 +41,10 @@ NewscoopGimmeBundleConfigureApi: newscoop: prefix: / resource: "@NewscoopNewscoopBundle/Resources/config/routing.yml" +articles: + prefix: / + prefix: /api + resource: "@NewscoopArticlesBundle/Resources/config/routing.yml" plugins: resource: . type: plugins diff --git a/newscoop/library/Newscoop/Gimme/PaginatorService.php b/newscoop/library/Newscoop/Gimme/PaginatorService.php index 76f14a5063..76892cd42f 100644 --- a/newscoop/library/Newscoop/Gimme/PaginatorService.php +++ b/newscoop/library/Newscoop/Gimme/PaginatorService.php @@ -93,7 +93,8 @@ public function setPagination(Pagination $pagination) * Get Pagination object * @return Pagination Pagination object */ - public function getPagination() { + public function getPagination() + { return $this->pagination; } @@ -104,6 +105,8 @@ public function getPagination() { public function setPartialResponse($partialResponse) { $this->partialResponse = $partialResponse; + + return $this; } /** @@ -163,21 +166,13 @@ public function setPaginationData(array $paginationData) /** * Paginate data * - * @param mixed $data Data to paginate - * @param array $params Parameters for Paginator - * @param bool $params['emptyResponse'] Sets behaviour for an empty response, Default true returns 204. False returns 404 - * Won't be send to the Paginator + * @param mixed $data Data to paginate + * @param array $params Parameters for Paginator * * @return array Paginated data */ public function paginate($data, $params = array()) { - $emptyResponse = true; - if (array_key_exists('emptyResponse', $params)) { - $emptyResponse = $params['emptyResponse']; - unset($params['emptyAllowed']); - } - $paginator = $this->paginator->paginate( $data, $this->pagination->getPage(), @@ -187,14 +182,6 @@ public function paginate($data, $params = array()) $items['items'] = $paginator->getItems(); - if (count($items['items']) == 0) { - if ($emptyResponse) { - throw new ResourceIsEmptyException('Result is empty.'); - } else { - throw new NotFoundHttpException('Results was not found.'); - } - } - /** * Set pagination object only when need */ @@ -214,10 +201,6 @@ public function paginate($data, $params = array()) */ private function getPaginationLinks($paginationData) { - // idea is that if you are somewhere and you use pagination - // and get link to go back it should be the very same uri you've visited - // in general it can filter all the params with default values - $data = array(); if ($paginationData['current'] < $paginationData['lastPageInRange']) { @@ -232,4 +215,4 @@ private function getPaginationLinks($paginationData) return $data; } -} \ No newline at end of file +} diff --git a/newscoop/library/Newscoop/Gimme/PartialResponse.php b/newscoop/library/Newscoop/Gimme/PartialResponse.php index 1dd019f231..a833da21d0 100644 --- a/newscoop/library/Newscoop/Gimme/PartialResponse.php +++ b/newscoop/library/Newscoop/Gimme/PartialResponse.php @@ -17,7 +17,7 @@ class PartialResponse { * @var string */ protected $fields = null; - + /** * Set fields * @param string $fields string with comma separated fields diff --git a/newscoop/src/Newscoop/ArticlesBundle/Controller/EditorialCommentsApiController.php b/newscoop/src/Newscoop/ArticlesBundle/Controller/EditorialCommentsApiController.php new file mode 100644 index 0000000000..b27f3027cf --- /dev/null +++ b/newscoop/src/Newscoop/ArticlesBundle/Controller/EditorialCommentsApiController.php @@ -0,0 +1,148 @@ +container->get('em'); + + $editorialComments = $em->getRepository('Newscoop\ArticlesBundle\Entity\EditorialComment')->getAll(); + + $paginator = $this->get('newscoop.paginator.paginator_service'); + $editorialComments = $paginator->paginate($editorialComments, array( + 'distinct' => false + )); + + return $editorialComments; + } + + /** + * Create editorial comments + * + * @ApiDoc( + * statusCodes={ + * 201="Returned when editorial comment is created", + * 404={ + * "Returned when article is not found", + * } + * } + * ) + * + * @Route("/articles/{number}/{language}/editorial_comments.{_format}", defaults={"_format"="json"}, options={"expose"=true}, name="newscoop_gimme_articles_create_editorial_comment") + * @Method("POST") + * @View(serializerGroups={"list"}) + */ + public function createCommentAction(Request $request, $number, $language) + { + $em = $this->container->get('em'); + $article = $em->getRepository('Newscoop\Entity\Article') + ->getArticle($number, $language) + ->getOneOrNullResult(); + + return $this->processForm($request, $article); + } + + /** + * Edit editorial comments + * + * @ApiDoc( + * statusCodes={ + * 201="Returned when editorial comment is created", + * 404={ + * "Returned when article is not found", + * } + * } + * ) + * + * @Route("/articles/{number}/{language}/editorial_comments/{commentId}.{_format}", defaults={"_format"="json"}, options={"expose"=true}, name="newscoop_gimme_articles_edit_editorial_comment") + * @Method("POST") + * @View(serializerGroups={"list"}) + */ + public function editCommentAction(Request $request, $number, $language, $commentId) + { + return $this->processForm($request, null, $commentId); + } + + public function removeCommentAction(Request $request, $number, $language, $commentId) + { + //return $this->processForm($request, null, $commentId); + } + + /** + * Process editorial comments form + * + * @param Request $request + * + * @return Form + */ + private function processForm($request, $article = null, $comment = null) + { + $em = $this->container->get('em'); + $editorialCommentService = $this->container->get('newscoop.editorial_comments'); + + if (!$comment) { + $statusCode = 201; + } else { + $statusCode = 200; + $comment = $em->getRepository('Newscoop\ArticlesBundle\Entity\EditorialComment')->findOneBy(array('id' => 1)); + + if (!$comment) { + throw new EntityNotFoundException('Result was not found.'); + } + } + + $form = $this->createForm(new EditorialCommentType(), array()); + $form->handleRequest($request); + + if ($form->isValid()) { + $attributes = $form->getData(); + $user = $this->container->get('user')->getCurrentUser(); + + $response = new Response(); + $response->setStatusCode($statusCode); + + if ($statusCode == 201 && $article) { + $comment = $editorialCommentService->create($attributes['comment'], $article, $user); + + // TODO: apply here new route + /* $response->headers->set( + 'X-Location', + $this->generateUrl('newscoop_gimme_attachments_getattachment', array( + 'number' => $comment->getId(), + ), true) + );*/ + } elseif ($statusCode == 200 && $comment) { + $comment = $editorialCommentService->edit($attributes['comment'], $comment, $user); + } + + return $response; + } + + return $form; + } +} diff --git a/newscoop/src/Newscoop/ArticlesBundle/Form/Type/EditorialCommentType.php b/newscoop/src/Newscoop/ArticlesBundle/Form/Type/EditorialCommentType.php new file mode 100644 index 0000000000..30b4b4e904 --- /dev/null +++ b/newscoop/src/Newscoop/ArticlesBundle/Form/Type/EditorialCommentType.php @@ -0,0 +1,42 @@ + + * @copyright 2014 Sourcefabric ź.u. + * @license http://www.gnu.org/licenses/gpl-3.0.txt + */ + +namespace Newscoop\ArticlesBundle\Form\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\Validator\Constraints as Assert; + +class EditorialCommentType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add('comment', null, array( + 'required' => true, + )); + $builder->add('resolved', 'checkbox', array( + 'required' => false, + )); + $builder->add('parent', 'number', array( + 'required' => false, + )); + } + + public function getName() + { + return 'editorial_comment'; + } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'csrf_protection' => false, + )); + } +} diff --git a/newscoop/src/Newscoop/ArticlesBundle/Resources/config/routing.yml b/newscoop/src/Newscoop/ArticlesBundle/Resources/config/routing.yml new file mode 100644 index 0000000000..97a681ce7d --- /dev/null +++ b/newscoop/src/Newscoop/ArticlesBundle/Resources/config/routing.yml @@ -0,0 +1,4 @@ +NewscoopArticlesBundleEditorialComments: + resource: "@NewscoopArticlesBundle/Controller/EditorialCommentsApiController.php" + prefix: / + type: annotation \ No newline at end of file diff --git a/newscoop/src/Newscoop/ArticlesBundle/Resources/config/services.yml b/newscoop/src/Newscoop/ArticlesBundle/Resources/config/services.yml index e69de29bb2..ff83ca4985 100644 --- a/newscoop/src/Newscoop/ArticlesBundle/Resources/config/services.yml +++ b/newscoop/src/Newscoop/ArticlesBundle/Resources/config/services.yml @@ -0,0 +1,4 @@ +services: + newscoop.editorial_comments: + class: Newscoop\ArticlesBundle\Services\EditorialCommentsService + arguments: ["@em"] \ No newline at end of file diff --git a/newscoop/src/Newscoop/GimmeBundle/Tests/ContainerAwareUnitTestCase.php b/newscoop/src/Newscoop/GimmeBundle/Tests/ContainerAwareUnitTestCase.php deleted file mode 100644 index 9671e27ef9..0000000000 --- a/newscoop/src/Newscoop/GimmeBundle/Tests/ContainerAwareUnitTestCase.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2012 Sourcefabric o.p.s. - * @license http://www.gnu.org/licenses/gpl-3.0.txt - */ - -namespace Newscoop\GimmeBundle\Tests; - -// This assumes that this class file is located at: -// src/Application/AcmeBundle/Tests/ContainerAwareUnitTestCase.php -// with Symfony 2.0 Standard Edition layout. You may need to change it -// to fit your own file system mapping. -require_once __DIR__.'/../../../../application/AppKernel.php'; -require_once __DIR__.'/../../../../constants.php'; - -class ContainerAwareUnitTestCase extends \PHPUnit_Framework_TestCase -{ - protected static $kernel; - protected static $container; - - public static function setUpBeforeClass() - { - self::$kernel = new \AppKernel('test', true); - self::$kernel->boot(); - - self::$container = self::$kernel->getContainer(); - } - - public function get($serviceId) - { - return self::$kernel->getContainer()->get($serviceId); - } -} diff --git a/newscoop/src/Newscoop/GimmeBundle/Tests/Newscoop/Gimme/PaginationTest.php b/newscoop/src/Newscoop/GimmeBundle/Tests/Newscoop/Gimme/PaginationTest.php deleted file mode 100644 index fdcb4316d2..0000000000 --- a/newscoop/src/Newscoop/GimmeBundle/Tests/Newscoop/Gimme/PaginationTest.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @copyright 2012 Sourcefabric o.p.s. - * @license http://www.gnu.org/licenses/gpl-3.0.txt - */ - -namespace Newscoop\GimmeBundle\Tests\Newscoop\Gimme; - -use Newscoop\GimmeBundle\Tests\ContainerAwareUnitTestCase; -use Newscoop\Gimme\Pagination; - -class PaginationTest extends ContainerAwareUnitTestCase -{ - protected $pagination; - - protected function setUp() - { - $this->pagination = new Pagination(); - } - - public function testSetPage() - { - $page = 1; - $this->pagination->setPage($page); - - $this->assertTrue($this->pagination->getPage() == $page); - } - - public function testSetSort() - { - $sort = array('nmuber' => 'desc'); - $this->pagination->setSort($sort); - - $this->assertTrue($this->pagination->getSort() == $sort); - } - - public function testSetItemsPerPage() - { - $itemsPerPage = 10; - $this->pagination->setItemsPerPage($itemsPerPage); - - $this->assertTrue($this->pagination->getItemsPerPage() == $itemsPerPage); - } -} diff --git a/newscoop/src/Newscoop/GimmeBundle/Tests/Newscoop/Gimme/PaginatorServiceTest.php b/newscoop/src/Newscoop/GimmeBundle/Tests/Newscoop/Gimme/PaginatorServiceTest.php deleted file mode 100644 index 030118ee68..0000000000 --- a/newscoop/src/Newscoop/GimmeBundle/Tests/Newscoop/Gimme/PaginatorServiceTest.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @copyright 2012 Sourcefabric o.p.s. - * @license http://www.gnu.org/licenses/gpl-3.0.txt - */ - -namespace Newscoop\GimmeBundle\Tests\Newscoop\Gimme; - -use Newscoop\GimmeBundle\Tests\ContainerAwareUnitTestCase; -use Newscoop\Gimme\PaginatorService; -use Newscoop\Gimme\Pagination; -use Newscoop\Gimme\PartialResponse; - -class PaginatorServiceTest extends ContainerAwareUnitTestCase -{ - protected $paginatorService; - - protected function setUp() - { - $this->paginatorService = $this->get('newscoop.paginator.paginator_service'); - $this->paginatorService->setPagination(new Pagination()); - $this->paginatorService->setPartialResponse(new PartialResponse()); - } - - public function testSetPagination() - { - $this->assertTrue( - get_class(new Pagination()) == get_class($this->paginatorService->getPagination()) - ); - } - - public function testSetPartialResponse() - { - $this->assertTrue( - get_class(new PartialResponse()) == get_class($this->paginatorService->getPartialResponse()) - ); - } -} \ No newline at end of file diff --git a/newscoop/src/Newscoop/GimmeBundle/Tests/Serializer/Article/AuthorHandlerTest.php b/newscoop/src/Newscoop/GimmeBundle/Tests/Serializer/Article/AuthorHandlerTest.php deleted file mode 100644 index 9f0e90bc34..0000000000 --- a/newscoop/src/Newscoop/GimmeBundle/Tests/Serializer/Article/AuthorHandlerTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @copyright 2012 Sourcefabric o.p.s. - * @license http://www.gnu.org/licenses/gpl-3.0.txt - */ - -namespace Newscoop\GimmeBundle\Tests\Serializer\Article; - -use Newscoop\GimmeBundle\Tests\ContainerAwareUnitTestCase; -use Newscoop\GimmeBundle\Serializer\Article\AuthorHandler; -use Newscoop\Entity\Article; -use JMS\SerializerBundle\Serializer\YamlSerializationVisitor; -use JMS\SerializerBundle\Serializer\Naming\SerializedNameAnnotationStrategy; -use JMS\SerializerBundle\Serializer\Naming\CamelCaseNamingStrategy; - -class AuthorHandlerTest extends ContainerAwareUnitTestCase -{ - protected $article; - protected $authorHandler; - protected $ymlSerializationVisitor; - - protected function setUp() - { - $this->article = new Article(10, new \Newscoop\Entity\Language()); - $this->authorHandler = new AuthorHandler($this->get('router')); - $this->ymlSerializationVisitor = new YamlSerializationVisitor( - new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()), - array() - ); - } - - public function testSerialize () - { - $visited = true; - $authorHandlerResult = $this->authorHandler->serialize( - $this->ymlSerializationVisitor, - $this->article, - get_class($this->article), - $visited - ); - - $this->assertNull($authorHandlerResult); - } - - public function testfailOnWrongClass () - { - $visited = true; - $authorHandlerResult = $this->authorHandler->serialize( - $this->ymlSerializationVisitor, - new \stdClass(), - get_class(new \stdClass()), - $visited - ); - - $this->assertFalse($authorHandlerResult); - } -} diff --git a/newscoop/src/Newscoop/GimmeBundle/Tests/Serializer/Article/CommentsLinkHandlerTest.php b/newscoop/src/Newscoop/GimmeBundle/Tests/Serializer/Article/CommentsLinkHandlerTest.php deleted file mode 100644 index 3cb081ce40..0000000000 --- a/newscoop/src/Newscoop/GimmeBundle/Tests/Serializer/Article/CommentsLinkHandlerTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @copyright 2012 Sourcefabric o.p.s. - * @license http://www.gnu.org/licenses/gpl-3.0.txt - */ - -namespace Newscoop\GimmeBundle\Tests\Serializer\Article; - -use Newscoop\GimmeBundle\Tests\ContainerAwareUnitTestCase; -use Newscoop\GimmeBundle\Serializer\Article\CommentsLinkHandler; -use Newscoop\Entity\Article; -use JMS\SerializerBundle\Serializer\YamlSerializationVisitor; -use JMS\SerializerBundle\Serializer\Naming\SerializedNameAnnotationStrategy; -use JMS\SerializerBundle\Serializer\Naming\CamelCaseNamingStrategy; - -class CommentsLinkHandlerTest extends ContainerAwareUnitTestCase -{ - protected $article; - protected $commentsHandler; - protected $ymlSerializationVisitor; - - protected function setUp() - { - $this->article = new Article(10, new \Newscoop\Entity\Language()); - $this->commentsHandler = new CommentsLinkHandler($this->get('router')); - $this->ymlSerializationVisitor = new YamlSerializationVisitor( - new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()), - array() - ); - } - - public function testSerialize () - { - $visited = true; - $authorHandlerResult = $this->commentsHandler->serialize( - $this->ymlSerializationVisitor, - $this->article, - get_class($this->article), - $visited - ); - - $this->assertTrue($authorHandlerResult); - } - - public function testfailOnWrongClass () - { - $visited = true; - $authorHandlerResult = $this->commentsHandler->serialize( - $this->ymlSerializationVisitor, - new \stdClass(), - get_class(new \stdClass()), - $visited - ); - - $this->assertFalse($authorHandlerResult); - } -} \ No newline at end of file diff --git a/phpspec.yml b/phpspec.yml index 23c7db960a..612d9be0b2 100644 --- a/phpspec.yml +++ b/phpspec.yml @@ -3,5 +3,9 @@ suites: namespace: Newscoop src_path: 'newscoop/src' spec_path: . + gimme_library: + namespace: Newscoop/Gimme + src_path: 'newscoop/library' + spec_path: . formatter.name: pretty \ No newline at end of file diff --git a/spec/Newscoop/ArticlesBundle/Controller/EditorialCommentsApiControllerSpec.php b/spec/Newscoop/ArticlesBundle/Controller/EditorialCommentsApiControllerSpec.php new file mode 100644 index 0000000000..843c2c60ba --- /dev/null +++ b/spec/Newscoop/ArticlesBundle/Controller/EditorialCommentsApiControllerSpec.php @@ -0,0 +1,114 @@ +get('em')->willReturn($entityManager); + $container->get('form.factory')->willReturn($formFactory); + $container->get('request')->willReturn($request); + $container->get('router')->willReturn($router); + $container->get('newscoop.editorial_comments')->willReturn($editorialCommentService); + $container->get('user')->willReturn($userService); + + $formBuilder->getForm(Argument::cetera())->willReturn($form); + $formFactory->create(Argument::cetera())->willReturn($form); + $form->createView()->willReturn($formView); + $form->handleRequest(Argument::cetera())->willReturn(true); + $form->isValid()->willReturn(true); + $userService->getCurrentUser()->willReturn($user); + + $entityManager->getRepository('Newscoop\ArticlesBundle\Entity\EditorialComment')->willReturn($editorialCommentRepository); + $entityManager->getRepository('Newscoop\Entity\Article')->willReturn($articleRepository); + + $articleRepository->getArticle(Argument::cetera())->willReturn($query); + $editorialCommentService->create(Argument::cetera())->willReturn($editorialComment); + $editorialCommentService->edit(Argument::cetera())->willReturn($editorialComment); + + $this->setContainer($container); + } + + function it_is_initializable() + { + $this->shouldHaveType('Newscoop\ArticlesBundle\Controller\EditorialCommentsApiController'); + $this->shouldImplement('FOS\RestBundle\Controller\FOSRestController'); + } + + function it_should_create_new_editorial_comment(Request $request, $form, $query, $article) + { + $form->getData()->willReturn(array( + 'comment' => 'test editorial comment', + )); + + $query->getOneOrNullResult()->willReturn($article); + $response = $this->createCommentAction($request, 1, 1); + + $response->shouldBeAnInstanceOf('Symfony\Component\HttpFoundation\Response'); + $response->getStatusCode()->shouldReturn(201); + } + + function it_should_edit_editorial_comment(Request $request, EditorialComment $comment, $form, $editorialCommentRepository) + { + $form->getData()->willReturn(array( + 'comment' => 'edit editorial comment', + )); + $editorialCommentRepository->findOneBy(array('id' => 1))->willReturn($comment); + + $response = $this->editCommentAction($request, 1, 1, 1); + + $response->shouldBeAnInstanceOf('Symfony\Component\HttpFoundation\Response'); + $response->getStatusCode()->shouldReturn(200); + } + + function it_should_resolve_editorial_comment(EditorialComment $comment) + { + // create form data + + $this->editCommentAction($comment)->shouldReturn(Argument::type('array')); + } + + function it_should_remove_editorial_comment(EditorialComment $comment) + { + $this->removeCommentAction($comment)->shouldReturn(Argument::type('array')); + } +} diff --git a/spec/Newscoop/Gimme/PaginatorServiceSpec.php b/spec/Newscoop/Gimme/PaginatorServiceSpec.php new file mode 100644 index 0000000000..c9b87ed163 --- /dev/null +++ b/spec/Newscoop/Gimme/PaginatorServiceSpec.php @@ -0,0 +1,77 @@ +paginate(array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20), null, null, array()) + ->willReturn($paginationView); + $paginationView->getItems()->willReturn(array(6,7,8,9,10)); + + $this->beConstructedWith($paginator, $router); + } + + function it_is_initializable() + { + $this->shouldHaveType('Newscoop\Gimme\PaginatorService'); + } + + function it_should_set_pagination(Pagination $pagination) + { + $this->setPagination($pagination)->shouldReturn($this); + $this->getPagination()->shouldReturn($pagination); + } + + function it_should_set_partial_response(PartialResponse $partialResponse) + { + $this->setPartialResponse($partialResponse)->shouldReturn($this); + $this->getPartialResponse()->shouldReturn($partialResponse); + + $newPartialResponse = new PartialResponse(); + $newPartialResponse->setFields('id,name,subject'); + $this->setPartialResponse($newPartialResponse)->shouldReturn($this); + $this->getPartialResponse()->shouldReturn($newPartialResponse); + } + + function it_shoud_set_used_route_params() + { + $this->setUsedRouteParams(array('id' => 5, 'number' => 34)) + ->shouldReturn($this); + } + + function it_should_paginate(Pagination $pagination) + { + $this->setPagination($pagination); + $this->setPaginationData(array( + 'numItemsPerPage' => 5, + 'current' => 2, + 'totalCount' => 20, + 'lastPageInRange' => 3, + 'firstPageInRange' => 1, + )); + + $this->paginate(array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20))->shouldReturn(array( + 'items' => array(6,7,8,9,10), + 'pagination' => array( + 'itemsPerPage' => 5, + 'currentPage' => 2, + 'itemsCount' => 20, + 'nextPageLink' => null, + 'previousPageLink' => null + ) + )); + } +}