diff --git a/lib/Alchemy/Phrasea/ACL/BasketACL.php b/lib/Alchemy/Phrasea/ACL/BasketACL.php new file mode 100644 index 0000000000..fa120fb989 --- /dev/null +++ b/lib/Alchemy/Phrasea/ACL/BasketACL.php @@ -0,0 +1,40 @@ +isOwner($basket, $user)) { + return true; + } + + if ($basket->getValidation()) { + foreach ($basket->getValidation()->getParticipants() as $participant) { + if ($participant->getUsrId() === $user->get_id()) { + return true; + } + } + } + + return false; + } + + public function isOwner(Basket $basket, User_Adapter $user) + { + return $basket->getUsrId() === $user->get_id(); + } +} diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 298d1b010c..9077984241 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -77,6 +77,8 @@ use Alchemy\Phrasea\Core\Event\Subscriber\LogoutSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaLocaleSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\MaintenanceSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\CookiesDisablerSubscriber; +use Alchemy\Phrasea\Core\Middleware\BasketMiddlewareProvider; +use Alchemy\Phrasea\Core\Provider\ACLServiceProvider; use Alchemy\Phrasea\Core\Provider\AuthenticationManagerServiceProvider; use Alchemy\Phrasea\Core\Provider\BrowserServiceProvider; use Alchemy\Phrasea\Core\Provider\BorderManagerServiceProvider; @@ -195,6 +197,9 @@ class Application extends SilexApplication ini_set('error_log', $this['root.path'] . '/logs/php_error.log'); } + $this->register(new BasketMiddlewareProvider()); + + $this->register(new ACLServiceProvider()); $this->register(new AuthenticationManagerServiceProvider()); $this->register(new BorderManagerServiceProvider()); $this->register(new BrowserServiceProvider()); diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1.php b/lib/Alchemy/Phrasea/Controller/Api/V1.php index 5c3c36a1a3..3eb20acb8d 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V1.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V1.php @@ -17,6 +17,7 @@ use Alchemy\Phrasea\Authentication\Context; use Alchemy\Phrasea\Core\Event\PreAuthenticate; use Alchemy\Phrasea\Core\Event\ApiOAuth2StartEvent; use Alchemy\Phrasea\Core\Event\ApiOAuth2EndEvent; +use Alchemy\Phrasea\Model\Entities\Basket; use Silex\Application as SilexApplication; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; @@ -88,7 +89,7 @@ class V1 implements ControllerProviderInterface $app['dispatcher']->dispatch(PhraseaEvents::API_OAUTH2_END, new ApiOAuth2EndEvent()); return; - }, 256); + }); /** * OAuth log process @@ -604,11 +605,14 @@ class V1 implements ControllerProviderInterface * BASKET_ID : required INT * */ - $controllers->get('/baskets/{basket_id}/content/', function (SilexApplication $app, $basket_id) { - return $app['api']->get_basket($app['request'], $basket_id)->get_response(); - })->assert('basket_id', '\d+'); + $controllers->get('/baskets/{basket}/content/', function (SilexApplication $app, Basket $basket) { + return $app['api']->get_basket($app['request'], $basket)->get_response(); + }) + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-access']) + ->assert('basket', '\d+'); - $controllers->get('/baskets/{wrong_basket_id}/content/', $bad_request_exception); + $controllers->get('/baskets/{wrong_basket}/content/', $bad_request_exception); /** * Route : /baskets/BASKET_ID/settitle/ @@ -619,13 +623,16 @@ class V1 implements ControllerProviderInterface * BASKET_ID : required INT * */ - $controllers->post('/baskets/{basket_id}/setname/', function (SilexApplication $app, $basket_id) { + $controllers->post('/baskets/{basket}/setname/', function (SilexApplication $app, Basket $basket) { return $app['api'] - ->set_basket_title($app['request'], $basket_id) + ->set_basket_title($app['request'], $basket) ->get_response(); - })->assert('basket_id', '\d+'); + }) + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-is-owner']) + ->assert('basket', '\d+'); - $controllers->post('/baskets/{wrong_basket_id}/setname/', $bad_request_exception); + $controllers->post('/baskets/{wrong_basket}/setname/', $bad_request_exception); /** * Route : /baskets/BASKET_ID/setdescription/ @@ -636,13 +643,16 @@ class V1 implements ControllerProviderInterface * BASKET_ID : required INT * */ - $controllers->post('/baskets/{basket_id}/setdescription/', function (SilexApplication $app, $basket_id) { + $controllers->post('/baskets/{basket}/setdescription/', function (SilexApplication $app, Basket $basket) { return $app['api'] - ->set_basket_description($app['request'], $basket_id) + ->set_basket_description($app['request'], $basket) ->get_response(); - })->assert('basket_id', '\d+'); + }) + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-is-owner']) + ->assert('basket', '\d+'); - $controllers->post('/baskets/{wrong_basket_id}/setdescription/', $bad_request_exception); + $controllers->post('/baskets/{wrong_basket}/setdescription/', $bad_request_exception); /** * Route : /baskets/BASKET_ID/delete/ @@ -653,11 +663,14 @@ class V1 implements ControllerProviderInterface * BASKET_ID : required INT * */ - $controllers->post('/baskets/{basket_id}/delete/', function (SilexApplication $app, $basket_id) { - return $app['api']->delete_basket($app['request'], $basket_id)->get_response(); - })->assert('basket_id', '\d+'); + $controllers->post('/baskets/{basket}/delete/', function (SilexApplication $app, Basket $basket) { + return $app['api']->delete_basket($app['request'], $basket)->get_response(); + }) + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-is-owner']) + ->assert('basket', '\d+'); - $controllers->post('/baskets/{wrong_basket_id}/delete/', $bad_request_exception); + $controllers->post('/baskets/{wrong_basket}/delete/', $bad_request_exception); /** * Route : /feeds/list/ diff --git a/lib/Alchemy/Phrasea/Controller/Client/Baskets.php b/lib/Alchemy/Phrasea/Controller/Client/Baskets.php index 40a9cc72cc..5765c17388 100644 --- a/lib/Alchemy/Phrasea/Controller/Client/Baskets.php +++ b/lib/Alchemy/Phrasea/Controller/Client/Baskets.php @@ -86,9 +86,8 @@ class Baskets implements ControllerProviderInterface public function deleteBasket(Application $app, Request $request) { try { - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $basket = $repository->findUserBasket($app, $request->request->get('courChuId'), $app['authentication']->getUser(), true); + $basket = $app['converter.basket']->convert($request->request->get('courChuId')); + $app['acl.basket']->isOwner($basket, $app['authentication']->getUser()); $app['EM']->remove($basket); $app['EM']->flush(); @@ -137,25 +136,22 @@ class Baskets implements ControllerProviderInterface */ public function addElementToBasket(Application $app, Request $request) { - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $basket = $repository->findUserBasket($app, $request->request->get('courChuId'), $app['authentication']->getUser(), true); + $basket = $app['converter.basket']->convert($request->request->get('courChuId')); + $app['acl.basket']->isOwner($basket, $app['authentication']->getUser()); - if ($basket) { - try { - $record = new \record_adapter($app, $request->request->get('sbas'), $request->request->get('p0')); + try { + $record = new \record_adapter($app, $request->request->get('sbas'), $request->request->get('p0')); - $basketElement = new BasketElement(); - $basketElement->setRecord($record); - $basketElement->setBasket($basket); - $basket->addElement($basketElement); + $basketElement = new BasketElement(); + $basketElement->setRecord($record); + $basketElement->setBasket($basket); + $basket->addElement($basketElement); - $app['EM']->persist($basket); + $app['EM']->persist($basket); - $app['EM']->flush(); - } catch (\Exception $e) { + $app['EM']->flush(); + } catch (\Exception $e) { - } } return $app->redirectPath('get_client_baskets', array( @@ -181,7 +177,8 @@ class Baskets implements ControllerProviderInterface } if ('' !== $selectedBasketId) { - $selectedBasket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->findUserBasket($app, $selectedBasketId, $app['authentication']->getUser(), true); + $selectedBasket = $app['converter.basket']->convert($selectedBasketId); + $app['acl.basket']->isOwner($selectedBasket, $app['authentication']->getUser()); } $basketCollections = $baskets->partition(function ($key, $basket) { diff --git a/lib/Alchemy/Phrasea/Controller/Lightbox.php b/lib/Alchemy/Phrasea/Controller/Lightbox.php index 44afc04ac6..9d727b8808 100644 --- a/lib/Alchemy/Phrasea/Controller/Lightbox.php +++ b/lib/Alchemy/Phrasea/Controller/Lightbox.php @@ -57,14 +57,17 @@ class Lightbox implements ControllerProviderInterface break; case \random::TYPE_VALIDATE: case \random::TYPE_VIEW: - return $app->redirectPath('lightbox_validation', array('ssel_id' => $datas['datas'])); + return $app->redirectPath('lightbox_validation', array('basket' => $datas['datas'])); break; } }); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireAuthentication(); - }); + }) + // Silex\Route::convert is not used as this should be done prior the before middleware + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-access']); $controllers->get('/', function (SilexApplication $app) { try { @@ -75,8 +78,6 @@ class Lightbox implements ControllerProviderInterface $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $basket_collection = array_merge( $repository->findActiveByUser($app['authentication']->getUser()) , $repository->findActiveValidationByUser($app['authentication']->getUser()) @@ -117,7 +118,6 @@ class Lightbox implements ControllerProviderInterface ->assert('sselcont_id', '\d+'); $controllers->get('/ajax/LOAD_BASKET_ELEMENT/{sselcont_id}/', function (SilexApplication $app, $sselcont_id) { - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketElementRepository */ $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\BasketElement'); $BasketElement = $repository->findUserElement($sselcont_id, $app['authentication']->getUser()); @@ -201,7 +201,7 @@ class Lightbox implements ControllerProviderInterface ->assert('entry_id', '\d+') ->assert('item_id', '\d+'); - $controllers->get('/validate/{ssel_id}/', function (SilexApplication $app, $ssel_id) { + $controllers->get('/validate/{basket}/', function (SilexApplication $app, $basket) { try { \Session_Logger::updateClientInfos($app, 6); @@ -211,17 +211,10 @@ class Lightbox implements ControllerProviderInterface $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ $basket_collection = $repository->findActiveValidationAndBasketByUser( $app['authentication']->getUser() ); - $basket = $repository->findUserBasket( - $app, $ssel_id - , $app['authentication']->getUser() - , false - ); - if ($basket->getIsRead() === false) { $basket = $app['EM']->merge($basket); $basket->setIsRead(true); @@ -253,9 +246,9 @@ class Lightbox implements ControllerProviderInterface return $response; }) ->bind('lightbox_validation') - ->assert('ssel_id', '\d+'); + ->assert('basket', '\d+'); - $controllers->get('/compare/{ssel_id}/', function (SilexApplication $app, $ssel_id) { + $controllers->get('/compare/{basket}/', function (SilexApplication $app, Basket $basket) { try { \Session_Logger::updateClientInfos($app, 6); @@ -265,17 +258,10 @@ class Lightbox implements ControllerProviderInterface $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ $basket_collection = $repository->findActiveValidationAndBasketByUser( $app['authentication']->getUser() ); - $basket = $repository->findUserBasket( - $app, $ssel_id - , $app['authentication']->getUser() - , false - ); - if ($basket->getIsRead() === false) { $basket = $app['EM']->merge($basket); $basket->setIsRead(true); @@ -307,7 +293,7 @@ class Lightbox implements ControllerProviderInterface return $response; }) ->bind('lightbox_compare') - ->assert('ssel_id', '\d+'); + ->assert('basket', '\d+'); $controllers->get('/feeds/entry/{entry_id}/', function (SilexApplication $app, $entry_id) { @@ -344,26 +330,12 @@ class Lightbox implements ControllerProviderInterface ->bind('lightbox_feed_entry') ->assert('entry_id', '\d+'); - $controllers->get('/ajax/LOAD_REPORT/{ssel_id}/', function (SilexApplication $app, $ssel_id) { + $controllers->get('/ajax/LOAD_REPORT/{basket}/', function (SilexApplication $app, Basket $basket) { - $template = 'lightbox/basket_content_report.html.twig'; - - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $basket = $repository->findUserBasket( - $app, $ssel_id - , $app['authentication']->getUser() - , false - ); - - $response = new Response($app['twig']->render($template, array('basket' => $basket))); - $response->setCharset('UTF-8'); - - return $response; + return new Response($app['twig']->render('lightbox/basket_content_report.html.twig', array('basket' => $basket))); }) ->bind('lightbox_ajax_report') - ->assert('ssel_id', '\d+'); + ->assert('basket', '\d+'); $controllers->post('/ajax/SET_NOTE/{sselcont_id}/', function (SilexApplication $app, $sselcont_id) { $output = array('error' => true, 'datas' => _('Erreur lors de l\'enregistrement des donnees')); @@ -375,7 +347,6 @@ class Lightbox implements ControllerProviderInterface Return new Response('You must provide a note value', 400); } - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketElementRepository */ $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\BasketElement'); $basket_element = $repository->findUserElement($sselcont_id, $app['authentication']->getUser()); @@ -425,7 +396,6 @@ class Lightbox implements ControllerProviderInterface $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\BasketElement'); - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketElementRepository */ $basket_element = $repository->findUserElement( $sselcont_id , $app['authentication']->getUser() @@ -468,20 +438,11 @@ class Lightbox implements ControllerProviderInterface ->bind('lightbox_ajax_set_element_agreement') ->assert('sselcont_id', '\d+'); - $controllers->post('/ajax/SET_RELEASE/{ssel_id}/', function (SilexApplication $app, $ssel_id) { - - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); + $controllers->post('/ajax/SET_RELEASE/{basket}/', function (SilexApplication $app, Basket $basket) { $datas = array('error' => true, 'datas' => ''); try { - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $basket = $repository->findUserBasket( - $app, $ssel_id - , $app['authentication']->getUser() - , false - ); - if (!$basket->getValidation()) { throw new ControllerException('There is no validation session attached to this basket'); } @@ -536,7 +497,7 @@ class Lightbox implements ControllerProviderInterface return $app->json($datas); }) ->bind('lightbox_ajax_set_release') - ->assert('ssel_id', '\d+'); + ->assert('basket', '\d+'); return $controllers; } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php b/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php index 1df0fa4626..2d44f08bf8 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php @@ -34,49 +34,62 @@ class BasketController implements ControllerProviderInterface $controllers = $app['controllers_factory']; - $controllers->before(function (Request $request) use ($app) { - $app['firewall']->requireAuthentication(); - }); + $controllers + ->before(function (Request $request, Application $app) { + $app['firewall']->requireAuthentication(); + }) + // Silex\Route::convert is not used as this should be done prior the before middleware + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-access']); - $controllers->get('/{basket_id}/', 'controller.prod.basket:displayBasket') + $controllers->get('/{basket}/', 'controller.prod.basket:displayBasket') ->bind('prod_baskets_basket') - ->assert('basket_id', '\d+'); + ->assert('basket', '\d+'); $controllers->post('/', 'controller.prod.basket:createBasket') ->bind('prod_baskets'); - $controllers->post('/{basket_id}/delete/', 'controller.prod.basket:deleteBasket') - ->assert('basket_id', '\d+') - ->bind('basket_delete'); + $controllers->post('/{basket}/delete/', 'controller.prod.basket:deleteBasket') + ->assert('basket', '\d+') + ->bind('basket_delete') + ->before($app['middleware.basket.user-is-owner']); - $controllers->post('/{basket_id}/delete/{basket_element_id}/', 'controller.prod.basket:removeBasketElement') + $controllers->post('/{basket}/delete/{basket_element_id}/', 'controller.prod.basket:removeBasketElement') ->bind('prod_baskets_basket_element_remove') - ->assert('basket_id', '\d+') - ->assert('basket_element_id', '\d+'); + ->assert('basket', '\d+') + ->assert('basket_element_id', '\d+') + ->before($app['middleware.basket.user-is-owner']); - $controllers->post('/{basket_id}/update/', 'controller.prod.basket:updateBasket') + $controllers->post('/{basket}/update/', 'controller.prod.basket:updateBasket') ->bind('prod_baskets_basket_update') - ->assert('basket_id', '\d+'); + ->assert('basket', '\d+') + ->before($app['middleware.basket.user-is-owner']); - $controllers->get('/{basket_id}/update/', 'controller.prod.basket:displayUpdateForm') - ->assert('basket_id', '\d+'); + $controllers->get('/{basket}/update/', 'controller.prod.basket:displayUpdateForm') + ->assert('basket', '\d+') + ->before($app['middleware.basket.user-is-owner']); - $controllers->get('/{basket_id}/reorder/', 'controller.prod.basket:displayReorderForm') - ->assert('basket_id', '\d+') - ->bind('prod_baskets_basket_reorder'); + $controllers->get('/{basket}/reorder/', 'controller.prod.basket:displayReorderForm') + ->assert('basket', '\d+') + ->bind('prod_baskets_basket_reorder') + ->before($app['middleware.basket.user-is-owner']); - $controllers->post('/{basket_id}/reorder/', 'controller.prod.basket:reorder') - ->assert('basket_id', '\d+'); + $controllers->post('/{basket}/reorder/', 'controller.prod.basket:reorder') + ->assert('basket', '\d+') + ->before($app['middleware.basket.user-is-owner']); - $controllers->post('/{basket_id}/archive/', 'controller.prod.basket:archiveBasket') + $controllers->post('/{basket}/archive/', 'controller.prod.basket:archiveBasket') ->bind('prod_baskets_basket_archive') - ->assert('basket_id', '\d+'); + ->assert('basket', '\d+') + ->before($app['middleware.basket.user-is-owner']); - $controllers->post('/{basket_id}/addElements/', 'controller.prod.basket:addElements') - ->assert('basket_id', '\d+'); + $controllers->post('/{basket}/addElements/', 'controller.prod.basket:addElements') + ->assert('basket', '\d+') + ->before($app['middleware.basket.user-is-owner']); - $controllers->post('/{basket_id}/stealElements/', 'controller.prod.basket:stealElements') - ->assert('basket_id', '\d+'); + $controllers->post('/{basket}/stealElements/', 'controller.prod.basket:stealElements') + ->assert('basket', '\d+') + ->before($app['middleware.basket.user-is-owner']); $controllers->get('/create/', 'controller.prod.basket:displayCreateForm') ->bind('prod_baskets_create'); @@ -84,11 +97,8 @@ class BasketController implements ControllerProviderInterface return $controllers; } - public function displayBasket(Application $app, Request $request, $basket_id) + public function displayBasket(Application $app, Request $request, BasketEntity $basket) { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), false); - if ($basket->getIsRead() === false) { $basket->setIsRead(true); $app['EM']->flush(); @@ -111,9 +121,6 @@ class BasketController implements ControllerProviderInterface public function createBasket(Application $app, Request $request) { - $request = $app['request']; - /* @var $request \Symfony\Component\HttpFoundation\Request */ - $Basket = new BasketEntity(); $Basket->setName($request->request->get('name', '')); @@ -144,7 +151,7 @@ class BasketController implements ControllerProviderInterface $app['EM']->flush(); - if ($request->getRequestFormat() == 'json') { + if ($request->getRequestFormat() === 'json') { $data = array( 'success' => true , 'message' => _('Basket created') @@ -155,15 +162,12 @@ class BasketController implements ControllerProviderInterface return $app->json($data); } else { - return $app->redirectPath('prod_baskets_basket', array('basket_id' => $Basket->getId())); + return $app->redirectPath('prod_baskets_basket', array('basket' => $Basket->getId())); } } - public function deleteBasket(Application $app, Request $request, $basket_id) + public function deleteBasket(Application $app, Request $request, BasketEntity $basket) { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - $app['EM']->remove($basket); $app['EM']->flush(); @@ -172,21 +176,18 @@ class BasketController implements ControllerProviderInterface , 'message' => _('Basket has been deleted') ); - if ($request->getRequestFormat() == 'json') { + if ($request->getRequestFormat() === 'json') { return $app->json($data); } else { return $app->redirectPath('prod_workzone_show'); } } - public function removeBasketElement(Application $app, Request $request, $basket_id, $basket_element_id) + public function removeBasketElement(Application $app, Request $request, BasketEntity $basket, $basket_element_id) { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - foreach ($basket->getElements() as $basket_element) { /* @var $basket_element BasketElement */ - if ($basket_element->getId() == $basket_element_id) { + if ($basket_element->getId() === (int) $basket_element_id) { $app['EM']->remove($basket_element); } } @@ -198,21 +199,18 @@ class BasketController implements ControllerProviderInterface , 'message' => _('Record removed from basket') ); - if ($request->getRequestFormat() == 'json') { + if ($request->getRequestFormat() === 'json') { return $app->json($data); } else { return $app->redirectPath('prod_workzone_show'); } } - public function updateBasket(Application $app, Request $request, $basket_id) + public function updateBasket(Application $app, Request $request, BasketEntity $basket) { $success = false; try { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - $basket->setName($request->request->get('name', '')); $basket->setDescription($request->request->get('description')); @@ -232,41 +230,30 @@ class BasketController implements ControllerProviderInterface $data = array( 'success' => $success , 'message' => $msg - , 'basket' => array('id' => $basket_id) + , 'basket' => array('id' => $basket->getId()) ); - if ($request->getRequestFormat() == 'json') { + if ($request->getRequestFormat() === 'json') { return $app->json($data); } else { return $app->redirectPath('prod_workzone_show'); } } - public function displayUpdateForm(Application $app, $basket_id) + public function displayUpdateForm(Application $app, BasketEntity $basket) { - $basket = $app['EM'] - ->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - return $app['twig']->render('prod/Baskets/Update.html.twig', array('basket' => $basket)); } - public function displayReorderForm(Application $app, $basket_id) + public function displayReorderForm(Application $app, BasketEntity $basket) { - $basket = $app['EM'] - ->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - return $app['twig']->render('prod/Baskets/Reorder.html.twig', array('basket' => $basket)); } - public function reorder(Application $app, $basket_id) + public function reorder(Application $app, BasketEntity $basket) { $ret = array('success' => false, 'message' => _('An error occured')); try { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - $order = $app['request']->request->get('element'); /* @var $basket BasketEntity */ @@ -287,11 +274,8 @@ class BasketController implements ControllerProviderInterface return $app->json($ret); } - public function archiveBasket(Application $app, Request $request, $basket_id) + public function archiveBasket(Application $app, Request $request, BasketEntity $basket) { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - $archive_status = (Boolean) $request->query->get('archive'); $basket->setArchived($archive_status); @@ -311,18 +295,15 @@ class BasketController implements ControllerProviderInterface , 'message' => $message ); - if ($request->getRequestFormat() == 'json') { + if ($request->getRequestFormat() === 'json') { return $app->json($data); } else { return $app->redirectPath('prod_workzone_show'); } } - public function addElements(Application $app, Request $request, $basket_id) + public function addElements(Application $app, Request $request, BasketEntity $basket) { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - $n = 0; $records = RecordsRequest::fromRequest($app, $request, true); @@ -362,18 +343,15 @@ class BasketController implements ControllerProviderInterface , 'message' => sprintf(_('%d records added'), $n) ); - if ($request->getRequestFormat() == 'json') { + if ($request->getRequestFormat() === 'json') { return $app->json($data); } else { return $app->redirectPath('prod_workzone_show'); } } - public function stealElements(Application $app, Request $request, $basket_id) + public function stealElements(Application $app, Request $request, BasketEntity $basket) { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), true); - $n = 0; foreach ($request->request->get('elements') as $bask_element_id) { @@ -384,6 +362,7 @@ class BasketController implements ControllerProviderInterface continue; } + $basket_element->getBasket()->removeElement($basket_element); $basket_element->setBasket($basket); $basket->addElement($basket_element); $n++; @@ -396,7 +375,7 @@ class BasketController implements ControllerProviderInterface , 'message' => sprintf(_('%d records moved'), $n) ); - if ($request->getRequestFormat() == 'json') { + if ($request->getRequestFormat() === 'json') { return $app->json($data); } else { return $app->redirectPath('prod_workzone_show'); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Push.php b/lib/Alchemy/Phrasea/Controller/Prod/Push.php index eb0a72b2fa..bbc3690555 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Push.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Push.php @@ -221,7 +221,7 @@ class Push implements ControllerProviderInterface $app['EM']->flush(); $url = $app->url('lightbox_compare', array( - 'ssel_id' => $Basket->getId(), + 'basket' => $Basket->getId(), 'LOG' => $app['tokens']->getUrlToken( \random::TYPE_VIEW, $user_receiver->get_id(), @@ -419,7 +419,7 @@ class Push implements ControllerProviderInterface $app['EM']->flush(); $url = $app->url('lightbox_validation', array( - 'ssel_id' => $Basket->getId(), + 'basket' => $Basket->getId(), 'LOG' => $app['tokens']->getUrlToken( \random::TYPE_VALIDATE, $participant_user->get_id(), diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php b/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php index 91bdf13601..9023a49905 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Controller\Prod; +use Alchemy\Phrasea\Model\Entities\Basket; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Symfony\Component\HttpFoundation\Request; use Silex\Application; @@ -33,8 +34,10 @@ class Tooltip implements ControllerProviderInterface $app['firewall']->requireAuthentication(); }); - $controllers->post('/basket/{basket_id}/', 'controller.prod.tooltip:displayBasket') - ->assert('basket_id', '\d+') + $controllers->post('/basket/{basket}/', 'controller.prod.tooltip:displayBasket') + ->assert('basket', '\d+') + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-access']) ->bind('prod_tooltip_basket'); $controllers->post('/Story/{sbas_id}/{record_id}/', 'controller.prod.tooltip:displayStory') @@ -79,11 +82,8 @@ class Tooltip implements ControllerProviderInterface return $controllers; } - public function displayBasket(Application $app, $basket_id) + public function displayBasket(Application $app, Basket $basket) { - $basket = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), false); - return $app['twig']->render('prod/Tooltip/Basket.html.twig', array('basket' => $basket)); } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php b/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php index d5f4af6188..1a019f6d91 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php @@ -11,11 +11,12 @@ namespace Alchemy\Phrasea\Controller\Prod; +use Alchemy\Phrasea\Model\Entities\Basket; use Alchemy\Phrasea\Model\Entities\StoryWZ; +use Alchemy\Phrasea\Helper\WorkZone as WorkzoneHelper; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; -use Alchemy\Phrasea\Helper\WorkZone as WorkzoneHelper; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -35,7 +36,10 @@ class WorkZone implements ControllerProviderInterface $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireAuthentication(); - }); + }) + // Silex\Route::convert is not used as this should be done prior the before middleware + ->before($app['middleware.basket.converter']) + ->before($app['middleware.basket.user-access']);; $controllers->get('/', 'controller.prod.workzone:displayWorkzone') ->bind('prod_workzone_show'); @@ -46,9 +50,9 @@ class WorkZone implements ControllerProviderInterface $controllers->get('/Browse/Search/', 'controller.prod.workzone:browserSearch') ->bind('prod_workzone_search'); - $controllers->get('/Browse/Basket/{basket_id}/', 'controller.prod.workzone:browseBasket') + $controllers->get('/Browse/Basket/{basket}/', 'controller.prod.workzone:browseBasket') ->bind('prod_workzone_basket') - ->assert('basket_id', '\d+'); + ->assert('basket', '\d+'); $controllers->post('/attachStories/', 'controller.prod.workzone:attachStories'); @@ -113,12 +117,8 @@ class WorkZone implements ControllerProviderInterface return $app['twig']->render('prod/WorkZone/Browser/Results.html.twig', $params); } - public function browseBasket(Application $app, Request $request, $basket_id) + public function browseBasket(Application $app, Request $request, Basket $basket) { - $basket = $app['EM'] - ->getRepository('Alchemy\Phrasea\Model\Entities\Basket') - ->findUserBasket($app, $basket_id, $app['authentication']->getUser(), false); - return $app['twig']->render('prod/WorkZone/Browser/Basket.html.twig', array('Basket' => $basket)); } diff --git a/lib/Alchemy/Phrasea/Controller/RecordsRequest.php b/lib/Alchemy/Phrasea/Controller/RecordsRequest.php index 6b8fa58b5f..08c8399db2 100644 --- a/lib/Alchemy/Phrasea/Controller/RecordsRequest.php +++ b/lib/Alchemy/Phrasea/Controller/RecordsRequest.php @@ -206,9 +206,8 @@ class RecordsRequest extends ArrayCollection $basket = null; if ($request->get('ssel')) { - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - $basket = $repository->findUserBasket($app, $request->get('ssel'), $app['authentication']->getUser(), false); + $basket = $app['converter.basket']->convert($request->get('ssel')); + $app['acl.basket']->hasAccess($basket, $app['authentication']->getUser()); foreach ($basket->getElements() as $basket_element) { $received[$basket_element->getRecord($app)->get_serialize_key()] = $basket_element->getRecord($app); diff --git a/lib/Alchemy/Phrasea/Controller/Root/Login.php b/lib/Alchemy/Phrasea/Controller/Root/Login.php index a55dc2028d..28cf757e98 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Login.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Login.php @@ -852,7 +852,7 @@ class Login implements ControllerProviderInterface 'ssel_id' => $basketId, 'from' => $validationSession->getInitiatorId(), 'validate_id' => $validationSession->getId(), - 'url' => $app->url('lightbox_validation', array('ssel_id' => $basketId, 'LOG' => $token)), + 'url' => $app->url('lightbox_validation', array('basket' => $basketId, 'LOG' => $token)), )); $participant->setReminded(new \DateTime('now')); diff --git a/lib/Alchemy/Phrasea/Core/Middleware/BasketMiddlewareProvider.php b/lib/Alchemy/Phrasea/Core/Middleware/BasketMiddlewareProvider.php new file mode 100644 index 0000000000..85d8796c0e --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Middleware/BasketMiddlewareProvider.php @@ -0,0 +1,47 @@ +protect(function (Request $request, Application $app) { + if ($request->attributes->has('basket')) { + $request->attributes->set('basket', $app['converter.basket']->convert($request->attributes->get('basket'))); + } + }); + + $app['middleware.basket.user-access'] = $app->protect(function (Request $request, Application $app) { + if ($request->attributes->has('basket')) { + if (!$app['acl.basket']->hasAccess($request->attributes->get('basket'), $app['authentication']->getUser())) { + throw new AccessDeniedHttpException('Current user does not have access to the basket'); + } + } + }); + + $app['middleware.basket.user-is-owner'] = $app->protect(function (Request $request, Application $app) { + if (!$app['acl.basket']->isOwner($request->attributes->get('basket'), $app['authentication']->getUser())) { + throw new AccessDeniedHttpException('Only basket owner can modify the basket'); + } + }); + } + + public function boot(Application $app) + { + } +} diff --git a/lib/Alchemy/Phrasea/Core/Provider/ACLServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/ACLServiceProvider.php new file mode 100644 index 0000000000..67a3d4d943 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Provider/ACLServiceProvider.php @@ -0,0 +1,30 @@ +share(function ($app) { + return new BasketACL(); + }); + } + + public function boot(Application $app) + { + } +} diff --git a/lib/Alchemy/Phrasea/Core/Provider/ConvertersServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/ConvertersServiceProvider.php index 5866cb3823..023e1c6466 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/ConvertersServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/ConvertersServiceProvider.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Core\Provider; +use Alchemy\Phrasea\Model\Converter\BasketConverter; use Alchemy\Phrasea\Model\Converter\TaskConverter; use Silex\Application; use Silex\ServiceProviderInterface; @@ -22,6 +23,10 @@ class ConvertersServiceProvider implements ServiceProviderInterface $app['converter.task'] = $app->share(function ($app) { return new TaskConverter($app['EM']); }); + + $app['converter.basket'] = $app->share(function ($app) { + return new BasketConverter($app['EM']); + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/Helper/Record/Helper.php b/lib/Alchemy/Phrasea/Helper/Record/Helper.php index 8385792534..d165cab385 100644 --- a/lib/Alchemy/Phrasea/Helper/Record/Helper.php +++ b/lib/Alchemy/Phrasea/Helper/Record/Helper.php @@ -113,10 +113,8 @@ class Helper extends \Alchemy\Phrasea\Helper\Helper $this->selection = new \set_selection($app); if (trim($Request->get('ssel')) !== '') { - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - /* @var $$repository Alchemy\Phrasea\Model\\Repositories\BasketRepository */ - $Basket = $repository->findUserBasket($this->app, $Request->get('ssel'), $app['authentication']->getUser(), false); + $Basket = $app['converter.basket']->convert($Request->get('ssel')); + $app['acl.basket']->hasAccess($Basket, $app['authentication']->getUser()); $this->selection->load_basket($Basket); diff --git a/lib/Alchemy/Phrasea/Model/Converter/BasketConverter.php b/lib/Alchemy/Phrasea/Model/Converter/BasketConverter.php new file mode 100644 index 0000000000..30d55f857a --- /dev/null +++ b/lib/Alchemy/Phrasea/Model/Converter/BasketConverter.php @@ -0,0 +1,40 @@ +om = $om; + } + + /** + * {@inheritdoc} + * + * @return Basket + */ + public function convert($id) + { + if (null === $basket = $this->om->find('Alchemy\Phrasea\Model\Entities\Basket', (int) $id)) { + throw new NotFoundHttpException(sprintf('Basket %s not found.', $id)); + } + + return $basket; + } +} diff --git a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php index 836360d2d9..08e0d1bcc6 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php @@ -119,51 +119,6 @@ class BasketRepository extends EntityRepository return $query->getResult(); } - /** - * Find a basket specified by his basket_id and his owner - * - * @throws NotFoundHttpException - * @throws AccessDeniedHttpException - * @param type $basket_id - * @param \User_Adapter $user - * @return Basket - */ - public function findUserBasket(Application $app, $basket_id, \User_Adapter $user, $requireOwner) - { - $dql = 'SELECT b - FROM Alchemy\Phrasea\Model\Entities\Basket b - LEFT JOIN b.elements e - WHERE b.id = :basket_id'; - - $query = $this->_em->createQuery($dql); - $query->setParameters(array('basket_id' => $basket_id)); - - $basket = $query->getOneOrNullResult(); - - /* @var $basket Basket */ - if (null === $basket) { - throw new NotFoundHttpException(_('Basket is not found')); - } - - if ($basket->getOwner($app)->get_id() != $user->get_id()) { - $participant = false; - - if ($basket->getValidation() && !$requireOwner) { - try { - $basket->getValidation()->getParticipant($user, $app); - $participant = true; - } catch (\Exception $e) { - - } - } - if (!$participant) { - throw new AccessDeniedHttpException(_('You have not access to this basket')); - } - } - - return $basket; - } - public function findContainingRecordForUser(\record_adapter $record, \User_Adapter $user) { diff --git a/lib/classes/API/V1/Interface.php b/lib/classes/API/V1/Interface.php index eacc52567c..08671ca907 100644 --- a/lib/classes/API/V1/Interface.php +++ b/lib/classes/API/V1/Interface.php @@ -9,6 +9,7 @@ * file that was distributed with this source code. */ +use Alchemy\Phrasea\Model\Entities\Basket; use Symfony\Component\HttpFoundation\Request; use Silex\Application; @@ -203,7 +204,7 @@ interface API_V1_Interface * BASKET_ID : required INT * */ - public function delete_basket(Request $request, $basket_id); + public function delete_basket(Request $request, Basket $basket); /** * Route : /baskets/BASKET_ID/content/FORMAT/ @@ -214,7 +215,7 @@ interface API_V1_Interface * BASKET_ID : required INT * */ - public function get_basket(Request $request, $basket_id); + public function get_basket(Request $request, Basket $basket); /** * Route : /baskets/BASKET_ID/title/FORMAT/ @@ -225,7 +226,7 @@ interface API_V1_Interface * BASKET_ID : required INT * */ - public function set_basket_title(Request $request, $basket_id); + public function set_basket_title(Request $request, Basket $basket); /** * Route : /baskets/BASKET_ID/description/FORMAT/ @@ -236,7 +237,7 @@ interface API_V1_Interface * BASKET_ID : required INT * */ - public function set_basket_description(Request $request, $basket_id); + public function set_basket_description(Request $request, Basket $basket); /** * Route : /publications/list/FORMAT/ diff --git a/lib/classes/API/V1/adapter.php b/lib/classes/API/V1/adapter.php index 2ab6bb9b1e..4dcc4f705a 100644 --- a/lib/classes/API/V1/adapter.php +++ b/lib/classes/API/V1/adapter.php @@ -1297,17 +1297,12 @@ class API_V1_adapter extends API_V1_Abstract * Delete a basket * * @param Request $request - * @param int $basket_id + * @param Basket $basket * @return array */ - public function delete_basket(Request $request, $basket_id) + public function delete_basket(Request $request, Basket $basket) { - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - - $Basket = $repository->findUserBasket($this->app, $basket_id, $this->app['authentication']->getUser(), true); - $this->app['EM']->remove($Basket); + $this->app['EM']->remove($basket); $this->app['EM']->flush(); return $this->search_baskets($request); @@ -1317,23 +1312,17 @@ class API_V1_adapter extends API_V1_Abstract * Retrieve a basket * * @param Request $request - * @param int $basket_id + * @param Basket $basket * @return API_V1_result */ - public function get_basket(Request $request, $basket_id) + public function get_basket(Request $request, Basket $basket) { $result = new API_V1_result($this->app, $request, $this); - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - - $Basket = $repository->findUserBasket($this->app, $basket_id, $this->app['authentication']->getUser(), false); - $result->set_datas( array( - "basket" => $this->list_basket($Basket), - "basket_elements" => $this->list_basket_content($Basket) + "basket" => $this->list_basket($basket), + "basket_elements" => $this->list_basket_content($basket) ) ); @@ -1414,26 +1403,19 @@ class API_V1_adapter extends API_V1_Abstract * Change the name of one basket * * @param Request $request - * @param int $basket_id + * @param Basket $basket * @return API_V1_result */ - public function set_basket_title(Request $request, $basket_id) + public function set_basket_title(Request $request, Basket $basket) { $result = new API_V1_result($this->app, $request, $this); - $name = $request->get('name'); + $basket->setName($request->get('name')); - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - - $Basket = $repository->findUserBasket($this->app, $basket_id, $this->app['authentication']->getUser(), true); - $Basket->setName($name); - - $this->app['EM']->merge($Basket); + $this->app['EM']->persist($basket); $this->app['EM']->flush(); - $result->set_datas(array("basket" => $this->list_basket($Basket))); + $result->set_datas(array("basket" => $this->list_basket($basket))); return $result; } @@ -1442,26 +1424,19 @@ class API_V1_adapter extends API_V1_Abstract * Change the description of one basket * * @param Request $request - * @param type $basket_id + * @param Basket $basket * @return API_V1_result */ - public function set_basket_description(Request $request, $basket_id) + public function set_basket_description(Request $request, Basket $basket) { $result = new API_V1_result($this->app, $request, $this); - $desc = $request->get('description'); + $basket->setDescription($request->get('description')); - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - - $Basket = $repository->findUserBasket($this->app, $basket_id, $this->app['authentication']->getUser(), true); - $Basket->setDescription($desc); - - $this->app['EM']->merge($Basket); + $this->app['EM']->persist($basket); $this->app['EM']->flush(); - $result->set_datas(array("basket" => $this->list_basket($Basket))); + $result->set_datas(array("basket" => $this->list_basket($basket))); return $result; } diff --git a/lib/classes/eventsmanager/notify/orderdeliver.php b/lib/classes/eventsmanager/notify/orderdeliver.php index ca41782a65..c95636e67f 100644 --- a/lib/classes/eventsmanager/notify/orderdeliver.php +++ b/lib/classes/eventsmanager/notify/orderdeliver.php @@ -114,7 +114,7 @@ class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract if ($readyToSend) { $url = $this->app->url('lightbox_compare', array( - 'ssel_id' => $basket->getId(), + 'basket' => $basket->getId(), 'LOG' => $this->app['tokens']->getUrlToken( \random::TYPE_VIEW, $user_to->get_id(), @@ -159,9 +159,7 @@ class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract $sender = User_Adapter::getInstance($from, $this->app)->get_display_name(); try { - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - $basket = $repository->findUserBasket($this->app, $ssel_id, $this->app['authentication']->getUser(), false); + $basket = $this->app['converter.basket']->convert($ssel_id); } catch (Exception $e) { return array(); } diff --git a/lib/classes/eventsmanager/notify/validate.php b/lib/classes/eventsmanager/notify/validate.php index 491836d52f..6b499a809f 100644 --- a/lib/classes/eventsmanager/notify/validate.php +++ b/lib/classes/eventsmanager/notify/validate.php @@ -146,17 +146,14 @@ class eventsmanager_notify_validate extends eventsmanager_notifyAbstract $sender = User_Adapter::getInstance($from, $this->app)->get_display_name(); try { - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - $basket = $repository->findUserBasket($this->app, $ssel_id, $this->app['authentication']->getUser(), false); - + $basket = $this->app['converter.basket']->convert($ssel_id); $basket_name = trim($basket->getName()) ? : _('Une selection'); } catch (Exception $e) { $basket_name = _('Une selection'); } $bask_link = '' . $basket_name . ''; diff --git a/lib/classes/eventsmanager/notify/validationdone.php b/lib/classes/eventsmanager/notify/validationdone.php index 921e7570a7..f3cf41b933 100644 --- a/lib/classes/eventsmanager/notify/validationdone.php +++ b/lib/classes/eventsmanager/notify/validationdone.php @@ -140,9 +140,7 @@ class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract $sender = $registered_user->get_display_name(); try { - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - $basket = $repository->findUserBasket($this->app, $ssel_id, $this->app['authentication']->getUser(), false); + $basket = $this->app['converter.basket']->convert($ssel_id); } catch (Exception $e) { return array(); } diff --git a/lib/classes/eventsmanager/notify/validationreminder.php b/lib/classes/eventsmanager/notify/validationreminder.php index b8b898134f..2925583985 100644 --- a/lib/classes/eventsmanager/notify/validationreminder.php +++ b/lib/classes/eventsmanager/notify/validationreminder.php @@ -145,10 +145,7 @@ class eventsmanager_notify_validationreminder extends eventsmanager_notifyAbstra $sender = User_Adapter::getInstance($from, $this->app)->get_display_name(); try { - $repository = $this->app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - $basket = $repository->findUserBasket($this->app, $ssel_id, $this->app['authentication']->getUser(), false); - + $basket = $this->app['converter.basket']->convert($ssel_id); $basket_name = trim($basket->getName()) ? : _('Une selection'); } catch (Exception $e) { $basket_name = _('Une selection'); diff --git a/lib/classes/record/preview.php b/lib/classes/record/preview.php index c1d1ea392d..78c6404f28 100644 --- a/lib/classes/record/preview.php +++ b/lib/classes/record/preview.php @@ -144,10 +144,8 @@ class record_preview extends record_adapter break; case "BASK": - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); - - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $Basket = $repository->findUserBasket($app, $contId, $app['authentication']->getUser(), false); + $Basket = $app['converter.basket']->convert($contId); + $app['acl.basket']->hasAccess($Basket, $app['authentication']->getUser()); /* @var $Basket Basket */ $this->container = $Basket; diff --git a/lib/classes/set/export.php b/lib/classes/set/export.php index 2cba27ab0e..43d4791cf6 100644 --- a/lib/classes/set/export.php +++ b/lib/classes/set/export.php @@ -58,10 +58,9 @@ class set_export extends set_abstract } if ($sstid != "") { - $repository = $app['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket'); + $Basket = $app['converter.basket']->convert($sstid); + $app['acl.basket']->hasAccess($Basket, $app['authentication']->getUser()); - /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $Basket = $repository->findUserBasket($this->app, $sstid, $app['authentication']->getUser(), false); $this->exportName = str_replace(array(' ', '\\', '/'), '_', $Basket->getName()) . "_" . date("Y-n-d"); foreach ($Basket->getElements() as $basket_element) { diff --git a/templates/mobile/lightbox/basket_element.html.twig b/templates/mobile/lightbox/basket_element.html.twig index 683d9177c8..f98d193a67 100644 --- a/templates/mobile/lightbox/basket_element.html.twig +++ b/templates/mobile/lightbox/basket_element.html.twig @@ -29,7 +29,7 @@ {% set record = basket_element.getRecord(app) %}
- Back + Back

{{basket_element.getOrd()}} - {{record.get_title()}}

Home
diff --git a/templates/mobile/lightbox/index.html.twig b/templates/mobile/lightbox/index.html.twig index 435b4d8464..2f10b3cbef 100644 --- a/templates/mobile/lightbox/index.html.twig +++ b/templates/mobile/lightbox/index.html.twig @@ -94,7 +94,7 @@ {% if basket.getElements().first() %} {% endif %} -

{{basket.getName()}}

+

{{basket.getName()}}

{{ basket.getDescription() }}

{{ basket_length }} @@ -123,7 +123,7 @@ {% if basket.getElements().first() %} {% endif %} -

{{ basket.getName() }}

+

{{ basket.getName() }}

{{ basket.getDescription() }}

{{basket_length}} diff --git a/templates/web/prod/Baskets/Reorder.html.twig b/templates/web/prod/Baskets/Reorder.html.twig index 38755b3287..fcb8797b86 100644 --- a/templates/web/prod/Baskets/Reorder.html.twig +++ b/templates/web/prod/Baskets/Reorder.html.twig @@ -9,7 +9,7 @@ -
+ {% for element in basket.getElements() %} {% endfor %} diff --git a/templates/web/prod/Baskets/Update.html.twig b/templates/web/prod/Baskets/Update.html.twig index 8ba493b31e..5d623c6d7b 100644 --- a/templates/web/prod/Baskets/Update.html.twig +++ b/templates/web/prod/Baskets/Update.html.twig @@ -1,5 +1,5 @@
- + diff --git a/templates/web/prod/WorkZone/Browser/Basket.html.twig b/templates/web/prod/WorkZone/Browser/Basket.html.twig index 03b4774663..9291895556 100644 --- a/templates/web/prod/WorkZone/Browser/Basket.html.twig +++ b/templates/web/prod/WorkZone/Browser/Basket.html.twig @@ -12,12 +12,12 @@

{% if Basket.getValidation() is empty or Basket.getValidation().isInitiator(app['authentication'].getUser()) %} - + - + diff --git a/templates/web/prod/WorkZone/Browser/Results.html.twig b/templates/web/prod/WorkZone/Browser/Results.html.twig index 6ce59a2519..d2333cbff7 100644 --- a/templates/web/prod/WorkZone/Browser/Results.html.twig +++ b/templates/web/prod/WorkZone/Browser/Results.html.twig @@ -34,7 +34,7 @@
{% for Basket in Baskets %}
- × + ×
@@ -51,18 +51,18 @@

{% if Basket.getValidation() is empty or Basket.getValidation().isInitiator(app['authentication'].getUser()) %} - + - + {% endif %} - + {{ Basket.getName() }}

diff --git a/templates/web/prod/WorkZone/Macros.html.twig b/templates/web/prod/WorkZone/Macros.html.twig index 33a231dc53..4d05c6a863 100644 --- a/templates/web/prod/WorkZone/Macros.html.twig +++ b/templates/web/prod/WorkZone/Macros.html.twig @@ -11,12 +11,12 @@ {% for basket in content.get(constant('\\Alchemy\\Phrasea\\Helper\\WorkZone::VALIDATIONS')) %} - {% if basket.getValidation() %}
- +
{% trans 'action::Valider' %}
@@ -86,12 +86,12 @@ {% for basket in content.get(constant('\\Alchemy\\Phrasea\\Helper\\WorkZone::BASKETS')) %} -
@@ -153,7 +153,7 @@ {% if basket.getValidation() %}
- +
{% trans 'action::Valider' %}
@@ -176,7 +176,7 @@
@@ -310,7 +310,7 @@ href="{{ path('prod_stories_story_remove_element', { 'sbas_id' : container.get_sbas_id(), 'record_id' : container.get_record_id(), 'child_sbas_id' : record.get_sbas_id(), 'child_record_id' : record.get_record_id() }) }}" {% elseif wz_scope == 'basket' %} id="WZEL_{{ container.getId() }}_{{ record.get_sbas_id() }}_{{ record.get_record_id() }}" - href="{{ path('prod_baskets_basket_element_remove', { 'basket_id' : container.getId(), 'basket_element_id' : contained.getId()}) }}" + href="{{ path('prod_baskets_basket_element_remove', { 'basket' : container.getId(), 'basket_element_id' : contained.getId()}) }}" {% elseif wz_scope == 'basket' %} href="#" {% endif %} diff --git a/templates/web/prod/preview/tools.html.twig b/templates/web/prod/preview/tools.html.twig index 5f9c53d163..fb2ddd4428 100644 --- a/templates/web/prod/preview/tools.html.twig +++ b/templates/web/prod/preview/tools.html.twig @@ -10,7 +10,7 @@ class="baskDeleter WorkZoneElementRemover" title="{% trans 'Remove from basket' %}" data-context="reg_train_basket" onclick="remove_from_basket($(this), false);return false;" - href="{{ path('prod_baskets_basket_element_remove', { 'basket_id' : record.get_container().getId(), 'basket_element_id' : record.get_original_item().getId()}) }}"> + href="{{ path('prod_baskets_basket_element_remove', { 'basket' : record.get_container().getId(), 'basket_element_id' : record.get_original_item().getId()}) }}"> {% endif %} diff --git a/tests/Alchemy/Tests/Phrasea/ACL/BasketACLTest.php b/tests/Alchemy/Tests/Phrasea/ACL/BasketACLTest.php new file mode 100644 index 0000000000..a47870b60b --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/ACL/BasketACLTest.php @@ -0,0 +1,64 @@ +insertOneBasketEnv(); + + $acl = new BasketACL(); + $this->assertTrue($acl->isOwner($basket, self::$DI['user'])); + } + + public function testParticipantIsNotAnOwner() + { + $basket = $this->insertOneBasketEnv(); + + $acl = new BasketACL(); + $this->assertFalse($acl->isOwner($basket, self::$DI['user_alt1'])); + } + + public function testUserIsNotTheOwner() + { + $basket = $this->insertOneBasket(); + + $acl = new BasketACL(); + $this->assertFalse($acl->isOwner($basket, self::$DI['user_alt1'])); + } + + public function testOwnerHasAccessInValidationEnv() + { + $basket = $this->insertOneBasketEnv(); + + $acl = new BasketACL(); + $this->assertTrue($acl->hasAccess($basket, self::$DI['user'])); + } + + public function testOwnerHasAccess() + { + $basket = $this->insertOneBasket(); + + $acl = new BasketACL(); + $this->assertTrue($acl->hasAccess($basket, self::$DI['user'])); + } + + public function testParticipantHasAccess() + { + $basket = $this->insertOneBasketEnv(); + + $acl = new BasketACL(); + $this->assertTrue($acl->hasAccess($basket, self::$DI['user_alt1'])); + } + + public function testUserHasNotAccess() + { + $basket = $this->insertOneBasket(); + + $acl = new BasketACL(); + $this->assertFalse($acl->hasAccess($basket, self::$DI['user_alt1'])); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Prod/BasketTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Prod/BasketTest.php index 5b0291ed8e..9b87a491f9 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Prod/BasketTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Prod/BasketTest.php @@ -3,6 +3,8 @@ namespace Alchemy\Tests\Phrasea\Controller\Prod; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Model\Entities\Basket; +use Alchemy\Phrasea\Model\Entities\BasketElement; class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract { @@ -57,7 +59,6 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $result = $query->getResult(); $basket = array_shift($result); - /* @var $basket \Alchemy\Phrasea\Model\Entities\Basket */ $this->assertEquals(2, $basket->getElements()->count()); } @@ -96,7 +97,6 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $crawler = self::$DI['client']->request('GET', $route); $response = self::$DI['client']->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); $filter = "form[action='/prod/baskets/']"; @@ -112,48 +112,39 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract public function testBasketGet() { $basket = $this->insertOneBasket(); - $route = sprintf('/prod/baskets/%s/', $basket->getId()); - - $crawler = self::$DI['client']->request('GET', $route); - + self::$DI['client']->request('GET', $route); $response = self::$DI['client']->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); } + public function testBasketGetAccessDenied() + { + $basket = $this->insertOneBasket(self::$DI['user_alt1']); + $route = sprintf('/prod/baskets/%s/', $basket->getId()); + self::$DI['client']->request('GET', $route); + $response = self::$DI['client']->getResponse(); + $this->assertEquals(403, $response->getStatusCode()); + } + public function testBasketDeleteElementPost() { - $basket = $this->insertOneBasket(); + $basketElement = $this->insertOneBasketElement(); + $basket = $basketElement->getBasket(); - $record = self::$DI['record_1']; - - $basket_element = new \Alchemy\Phrasea\Model\Entities\BasketElement(); - $basket_element->setBasket($basket); - $basket_element->setRecord($record); - $basket_element->setLastInBasket(); - - $basket->addElement($basket_element); - - self::$DI['app']['EM']->persist($basket); - self::$DI['app']['EM']->flush(); + $this->assertEquals(1, $basket->getElements()->count()); $route = sprintf( - "/prod/baskets/%s/delete/%s/", $basket->getId(), $basket_element->getId() + "/prod/baskets/%s/delete/%s/", $basket->getId(), $basketElement->getId() ); - $crawler = self::$DI['client']->request('POST', $route); - + self::$DI['client']->request('POST', $route); $response = self::$DI['client']->getResponse(); - - self::$DI['app']['EM']->refresh($basket); - $this->assertEquals(302, $response->getStatusCode()); - $this->assertEquals(0, $basket->getElements()->count()); } - public function testBasketDeleteElementPostJSON() + public function testBasketDeldeteElementPostJSON() { $basket = $this->insertOneBasket(); @@ -173,60 +164,51 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract "/prod/baskets/%s/delete/%s/", $basket->getId(), $basket_element->getId() ); - $crawler = self::$DI['client']->request( + self::$DI['client']->request( 'POST', $route, array(), array(), array( "HTTP_ACCEPT" => "application/json") ); $response = self::$DI['client']->getResponse(); - self::$DI['app']['EM']->refresh($basket); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals(0, $basket->getElements()->count()); } + public function testBasketDeletePostUnauthorized() + { + $basket = $this->insertOneBasket(self::$DI['user_alt1']); + $route = sprintf('/prod/baskets/%s/delete/', $basket->getId()); + self::$DI['client']->request('POST', $route); + $response = self::$DI['client']->getResponse(); + + $this->assertEquals(403, $response->getStatusCode()); + $query = self::$DI['app']['EM']->createQuery('SELECT COUNT(b.id) FROM \Alchemy\Phrasea\Model\Entities\Basket b'); + $count = $query->getSingleScalarResult(); + $this->assertEquals(1, $count); + } + public function testBasketDeletePost() { $basket = $this->insertOneBasket(); - $route = sprintf('/prod/baskets/%s/delete/', $basket->getId()); - - $crawler = self::$DI['client']->request('POST', $route); - + self::$DI['client']->request('POST', $route); $response = self::$DI['client']->getResponse(); - $query = self::$DI['app']['EM']->createQuery('SELECT COUNT(b.id) FROM \Alchemy\Phrasea\Model\Entities\Basket b'); - $count = $query->getSingleScalarResult(); - $this->assertEquals(0, $count); - $this->assertEquals(302, $response->getStatusCode()); } public function testBasketDeletePostJSON() { $basket = $this->insertOneBasket(); - $route = sprintf('/prod/baskets/%s/delete/', $basket->getId()); - - $crawler = self::$DI['client']->request( - 'POST', $route, array(), array(), array( - "HTTP_ACCEPT" => "application/json") - ); - - self::$DI['client']->getRequest()->setRequestFormat('json'); - + self::$DI['client']->request('POST', $route, array(), array(), array("HTTP_ACCEPT" => "application/json")); $response = self::$DI['client']->getResponse(); - $query = self::$DI['app']['EM']->createQuery('SELECT COUNT(b.id) FROM \Alchemy\Phrasea\Model\Entities\Basket b'); - $count = $query->getSingleScalarResult(); - $this->assertEquals(0, $count); - $this->assertEquals(200, $response->getStatusCode()); } @@ -236,29 +218,24 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $route = sprintf('/prod/baskets/%s/update/', $basket->getId()); - $crawler = self::$DI['client']->request( + self::$DI['client']->request( 'POST', $route, array( 'name' => 'new_name', 'description' => 'new_desc') ); $response = self::$DI['client']->getResponse(); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($basket->getId()); - $this->assertEquals('new_name', $basket->getName()); $this->assertEquals('new_desc', $basket->getDescription()); - $this->assertEquals(302, $response->getStatusCode()); } public function testBasketUpdatePostJSON() { $basket = $this->insertOneBasket(); - $route = sprintf('/prod/baskets/%s/update/', $basket->getId()); - $crawler = self::$DI['client']->request( + self::$DI['client']->request( 'POST', $route, array( 'name' => 'new_name', 'description' => 'new_desc' @@ -267,12 +244,8 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract ); $response = self::$DI['client']->getResponse(); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($basket->getId()); - $this->assertEquals('new_name', $basket->getName()); $this->assertEquals('new_desc', $basket->getDescription()); - $this->assertEquals(200, $response->getStatusCode()); } @@ -283,13 +256,11 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $route = sprintf("/prod/baskets/%s/reorder/", $basket->getId()); $crawler = self::$DI['client']->request("GET", $route); - $response = self::$DI['client']->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); foreach ($basket->getElements() as $elements) { - $filter = sprintf("form[action='/prod/baskets/%s/reorder/']", $elements->getId()); + $filter = sprintf("form[action='/prod/baskets/%s/reorder/'] input[name='element[%s]']", $basket->getId(), $elements->getId()); $this->assertEquals(1, $crawler->filter($filter)->count()); } } @@ -307,46 +278,27 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract ); $response = self::$DI['client']->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - $filter = "form[action='/prod/baskets/" . $basket->getId() . "/update/']"; $this->assertEquals($crawler->filter($filter)->count(), 1); - $node = $crawler - ->filter('input[name=name]'); - + $node = $crawler->filter('input[name=name]'); $this->assertEquals($basket->getName(), $node->attr('value')); - - $node = $crawler - ->filter('textarea[name=description]'); - + $node = $crawler->filter('textarea[name=description]'); $this->assertEquals($basket->getDescription(), $node->text()); } public function testBasketArchivedPost() { $basket = $this->insertOneBasket(); - $route = sprintf('/prod/baskets/%s/archive/?archive=1', $basket->getId()); - - $crawler = self::$DI['client']->request('POST', $route); - - $response = self::$DI['client']->getResponse(); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($basket->getId()); - + self::$DI['client']->request('POST', $route); $this->assertTrue($basket->getArchived()); - $route = sprintf('/prod/baskets/%s/archive/?archive=0', $basket->getId()); - $crawler = self::$DI['client']->request('POST', $route); - + self::$DI['client']->request('POST', $route); $response = self::$DI['client']->getResponse(); - self::$DI['app']['EM']->refresh($basket); - $this->assertFalse($basket->getArchived()); - $this->assertEquals(302, $response->getStatusCode()); } @@ -356,31 +308,24 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $route = sprintf('/prod/baskets/%s/archive/?archive=1', $basket->getId()); - $crawler = self::$DI['client']->request( + self::$DI['client']->request( 'POST', $route, array(), array(), array( "HTTP_ACCEPT" => "application/json" ) ); - $response = self::$DI['client']->getResponse(); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($basket->getId()); - $this->assertTrue($basket->getArchived()); $route = sprintf('/prod/baskets/%s/archive/?archive=0', $basket->getId()); - $crawler = self::$DI['client']->request( + self::$DI['client']->request( 'POST', $route, array(), array(), array( "HTTP_ACCEPT" => "application/json" ) ); $response = self::$DI['client']->getResponse(); - self::$DI['app']['EM']->refresh($basket); - $this->assertFalse($basket->getArchived()); - $this->assertEquals(200, $response->getStatusCode()); } @@ -406,9 +351,6 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $response = self::$DI['client']->getResponse(); $this->assertEquals(302, $response->getStatusCode()); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($basket->getId()); - $this->assertEquals(2, $basket->getElements()->count()); } @@ -461,13 +403,8 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $response = self::$DI['client']->getResponse(); $this->assertEquals(302, $response->getStatusCode()); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($basket->getId()); - $this->assertEquals(2, $basket->getElements()->count()); - $datas = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\ValidationData')->findAll(); - $this->assertTrue($countDatas < count($datas), 'assert that ' . count($datas) . ' > ' . $countDatas); } @@ -484,7 +421,7 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $lst = implode(';', $records); - $crawler = self::$DI['client']->request( + self::$DI['client']->request( 'POST', $route, array( 'lst' => $lst ), array(), array( @@ -494,8 +431,6 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $response = self::$DI['client']->getResponse(); - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($basket->getId()); - $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(2, $basket->getElements()->count()); @@ -521,13 +456,8 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $this->assertTrue($response->isRedirect()); - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($Basket_1->getId()); - $this->assertInstanceOf('\Alchemy\Phrasea\Model\Entities\Basket', $basket); - $this->assertEquals(0, $basket->getElements()->count()); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($Basket_2->getId()); - $this->assertInstanceOf('\Alchemy\Phrasea\Model\Entities\Basket', $basket); - $this->assertEquals(1, $basket->getElements()->count()); + $this->assertEquals(0, $Basket_1->getElements()->count()); + $this->assertEquals(1, $Basket_2->getElements()->count()); } public function testRouteStealElementsJson() @@ -559,54 +489,37 @@ class ControllerBasketTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $this->assertArrayHasKey('success', $datas); $this->assertTrue($datas['success']); - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($Basket_1->getId()); - $this->assertInstanceOf('\Alchemy\Phrasea\Model\Entities\Basket', $basket); - $this->assertEquals(0, $basket->getElements()->count()); - - $basket = self::$DI['app']['EM']->getRepository('Alchemy\Phrasea\Model\Entities\Basket')->find($Basket_2->getId()); - $this->assertInstanceOf('\Alchemy\Phrasea\Model\Entities\Basket', $basket); - $this->assertEquals(1, $basket->getElements()->count()); + $this->assertEquals(0, $Basket_1->getElements()->count()); + $this->assertEquals(1, $Basket_2->getElements()->count()); } - /** - * Test when i remove a basket, all relations are removed too : - * - basket elements - * - validations sessions - * - validation participants - */ public function testRemoveBasket() { $basket = $this->insertOneBasketEnv(); - $basket = self::$DI['app']['EM']->find("Alchemy\Phrasea\Model\Entities\Basket", $basket->getId()); + $route = sprintf('/prod/baskets/%s/delete/', $basket->getId()); + self::$DI['client']->request('POST', $route, array(), array(), array("HTTP_ACCEPT" => "application/json")); - self::$DI['app']['EM']->remove($basket); - self::$DI['app']['EM']->flush(); + $response = self::$DI['client']->getResponse(); + + $this->assertEquals(200, $response->getStatusCode()); + + $datas = (array) json_decode($response->getContent()); + + $this->assertArrayHasKey('message', $datas); + $this->assertArrayHasKey('success', $datas); + $this->assertTrue($datas['success']); $query = self::$DI['app']['EM']->createQuery('SELECT COUNT(v.id) FROM \Alchemy\Phrasea\Model\Entities\ValidationParticipant v'); + $this->assertEquals(0, $query->getSingleScalarResult()); - $count = $query->getSingleScalarResult(); - - $this->assertEquals(0, $count); - - $query = self::$DI['app']['EM']->createQuery( - 'SELECT COUNT(b.id) FROM \Alchemy\Phrasea\Model\Entities\BasketElement b' - ); - - $count = $query->getSingleScalarResult(); - - $this->assertEquals(0, $count); + $query = self::$DI['app']['EM']->createQuery('SELECT COUNT(b.id) FROM \Alchemy\Phrasea\Model\Entities\BasketElement b'); + $this->assertEquals(0, $query->getSingleScalarResult()); $query = self::$DI['app']['EM']->createQuery('SELECT COUNT(v.id) FROM \Alchemy\Phrasea\Model\Entities\ValidationSession v'); - - $count = $query->getSingleScalarResult(); - - $this->assertEquals(0, $count); + $this->assertEquals(0, $query->getSingleScalarResult()); $query = self::$DI['app']['EM']->createQuery('SELECT COUNT(b.id) FROM \Alchemy\Phrasea\Model\Entities\Basket b'); - - $count = $query->getSingleScalarResult(); - - $this->assertEquals(0, $count); + $this->assertEquals(0, $query->getSingleScalarResult()); } } diff --git a/tests/Alchemy/Tests/Phrasea/Core/Middleware/BasketMiddlewareProviderTest.php b/tests/Alchemy/Tests/Phrasea/Core/Middleware/BasketMiddlewareProviderTest.php new file mode 100644 index 0000000000..c5139fdb2a --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Middleware/BasketMiddlewareProviderTest.php @@ -0,0 +1,77 @@ +authenticate(self::$DI['app']); + self::$DI['app']->register(new BasketMiddlewareProvider()); + $request = new Request(); + call_user_func(self::$DI['app']['middleware.basket.converter'], $request, self::$DI['app']); + $this->assertNull($request->attributes->get('basket')); + } + + public function testConverterWithBasketParameter() + { + $this->authenticate(self::$DI['app']); + self::$DI['app']->register(new BasketMiddlewareProvider()); + $request = new Request(); + $basket = $this->insertOneBasket(self::$DI['user']); + $request->attributes->set('basket', $basket->getId()); + call_user_func(self::$DI['app']['middleware.basket.converter'], $request, self::$DI['app']); + $this->assertSame($basket, $request->attributes->get('basket')); + } + + public function testUserAccessWithNoParameter() + { + $this->authenticate(self::$DI['app']); + self::$DI['app']->register(new BasketMiddlewareProvider()); + $request = new Request(); + call_user_func(self::$DI['app']['middleware.basket.user-access'], $request, self::$DI['app']); + $this->assertNull($request->attributes->get('basket')); + } + + public function testUserAccessWithBasketOwner() + { + $this->authenticate(self::$DI['app']); + self::$DI['app']->register(new BasketMiddlewareProvider()); + $request = new Request(); + $basket = $this->insertOneBasket(self::$DI['user']); + $request->attributes->set('basket', $basket); + call_user_func(self::$DI['app']['middleware.basket.user-access'], $request, self::$DI['app']); + } + + public function testUserAccessWithoutBasketOwner() + { + $this->authenticate(self::$DI['app']); + self::$DI['app']->register(new BasketMiddlewareProvider()); + $request = new Request(); + $basket = $this->insertOneBasket(self::$DI['user_alt1']); + $request->attributes->set('basket', $basket); + $this->setExpectedException('Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException', 'Current user does not have access to the basket'); + call_user_func(self::$DI['app']['middleware.basket.user-access'], $request, self::$DI['app']); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Middleware/MiddlewareProviderTestCase.php b/tests/Alchemy/Tests/Phrasea/Core/Middleware/MiddlewareProviderTestCase.php new file mode 100644 index 0000000000..46bbc2436b --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Middleware/MiddlewareProviderTestCase.php @@ -0,0 +1,26 @@ +register(new $service()); + + $instance1 = self::$DI['app'][$key]; + $instance2 = self::$DI['app'][$key]; + + $this->assertTrue(is_callable($instance1)); + $this->assertSame($instance1, $instance2); + } + + abstract public function provideDescription(); +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Provider/ACLServiceProviderTest.php b/tests/Alchemy/Tests/Phrasea/Core/Provider/ACLServiceProviderTest.php new file mode 100644 index 0000000000..45f60539e2 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Provider/ACLServiceProviderTest.php @@ -0,0 +1,23 @@ +assertInstanceof($classname, $instance1); - $this->assertEquals($instance1, $instance2); + $this->assertSame($instance1, $instance2); } abstract public function provideServiceDescription(); diff --git a/tests/Alchemy/Tests/Phrasea/Model/Converter/BasketConverterTest.php b/tests/Alchemy/Tests/Phrasea/Model/Converter/BasketConverterTest.php new file mode 100644 index 0000000000..ab48be7c4e --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Model/Converter/BasketConverterTest.php @@ -0,0 +1,27 @@ +insertOneBasket(); + + $converter = new BasketConverter(self::$DI['app']['EM']); + $this->assertSame($basket, $converter->convert($basket->getId())); + } + + /** + * @expectedException Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @expectedExceptionMessage Basket prout not found. + */ + public function testConvertFailure() + { + $converter = new BasketConverter(self::$DI['app']['EM']); + $converter->convert('prout'); + } +} diff --git a/tests/classes/PhraseanetPHPUnitAbstract.php b/tests/classes/PhraseanetPHPUnitAbstract.php index e919549a7d..e83ac22474 100644 --- a/tests/classes/PhraseanetPHPUnitAbstract.php +++ b/tests/classes/PhraseanetPHPUnitAbstract.php @@ -5,6 +5,8 @@ use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Border\File; use Doctrine\Common\DataFixtures\Loader; use Alchemy\Phrasea\Model\Entities\AggregateToken; +use Alchemy\Phrasea\Model\Entities\Basket; +use Alchemy\Phrasea\Model\Entities\BasketElement; use Alchemy\Phrasea\Model\Entities\Feed; use Alchemy\Phrasea\Model\Entities\FeedEntry; use Alchemy\Phrasea\Model\Entities\FeedItem; @@ -12,6 +14,8 @@ use Alchemy\Phrasea\Model\Entities\FeedToken; use Alchemy\Phrasea\Model\Entities\Session; use Alchemy\Phrasea\Model\Entities\Task; use Alchemy\Phrasea\Model\Entities\User; +use Alchemy\Phrasea\Model\Entities\ValidationSession; +use Alchemy\Phrasea\Model\Entities\ValidationParticipant; use Silex\WebTestCase; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Client; @@ -329,22 +333,17 @@ abstract class PhraseanetPHPUnitAbstract extends WebTestCase * * @return \Alchemy\Phrasea\Model\Entities\Basket */ - protected function insertOneBasket() + protected function insertOneBasket(\User_Adapter $user = null) { - try { - $basketFixture = new PhraseaFixture\Basket\LoadOneBasket(); + $basket = new Basket(); + $basket->setOwner($user ?: self::$DI['user']); + $basket->setName('test'); + $basket->setName('description test'); - $basketFixture->setUser(self::$DI['user']); + self::$DI['app']['EM']->persist($basket); + self::$DI['app']['EM']->flush(); - $loader = new Loader(); - $loader->addFixture($basketFixture); - - $this->insertFixtureInDatabase($loader); - - return $basketFixture->basket; - } catch (\Exception $e) { - $this->fail('Fail load one Basket : ' . $e->getMessage()); - } + return $basket; } /** @@ -591,28 +590,21 @@ abstract class PhraseanetPHPUnitAbstract extends WebTestCase } /** - * * @return \Alchemy\Phrasea\Model\Entities\BasketElement */ - protected function insertOneBasketElement() + protected function insertOneBasketElement(\User_Adapter $user = null, \record_adapter $record = null) { - $basket = $this->insertOneBasket(); + $element = new BasketElement(); + $element->setRecord($record ?: self::$DI['record_1']); - $basketElement = new \Alchemy\Phrasea\Model\Entities\BasketElement(); - $basketElement->setRecord(self::$DI['record_1']); - $basketElement->setBasket($basket); + $basket = $this->insertOneBasket($user); + $basket->addElement($element); + $element->setBasket($basket); - $basket->addElement($basketElement); + self::$DI['app']['EM']->persist($element); + self::$DI['app']['EM']->flush(); - $em = self::$DI['app']['EM']; - - $em->persist($basketElement); - - $em->merge($basket); - - $em->flush(); - - return $basketElement; + return $element; } /** @@ -673,26 +665,39 @@ abstract class PhraseanetPHPUnitAbstract extends WebTestCase */ protected function insertOneBasketEnv() { - try { - $basketFixture = new PhraseaFixture\Basket\LoadOneBasketEnv(); + $basket = new Basket(); + $basket->setName('test'); + $basket->setDescription('description'); + $basket->setOwner(self::$DI['user']); + self::$DI['app']['EM']->persist($basket); - $basketFixture->setUser(self::$DI['user']); - - $basketFixture->addParticipant(self::$DI['user_alt1']); - $basketFixture->addParticipant(self::$DI['user_alt2']); - - $basketFixture->addElement(self::$DI['record_1']); - $basketFixture->addElement(self::$DI['record_2']); - - $loader = new Loader(); - $loader->addFixture($basketFixture); - - $this->insertFixtureInDatabase($loader); - - return $basketFixture->basket; - } catch (\Exception $e) { - $this->fail('Fail load one Basket context : ' . $e->getMessage()); + foreach (array(self::$DI['record_1'], self::$DI['record_2']) as $record) { + $basketElement = new BasketElement(); + $basketElement->setRecord($record); + $basketElement->setBasket($basket); + $basket->addElement($basketElement); + self::$DI['app']['EM']->persist($basketElement); } + + $validationSession = new ValidationSession(); + $validationSession->setBasket($basket); + $basket->setValidation($validationSession); + $expires = new \DateTime(); + $expires->modify('+1 week'); + $validationSession->setExpires($expires); + $validationSession->setInitiator(self::$DI['user']); + + foreach (array(self::$DI['user_alt1'], self::$DI['user_alt2']) as $user) { + $validationParticipant = new ValidationParticipant(); + $validationParticipant->setUser($user); + $validationParticipant->setSession($validationSession); + $validationSession->addParticipant($validationParticipant); + self::$DI['app']['EM']->persist($validationParticipant); + } + + self::$DI['app']['EM']->flush(); + + return $basket; } /** diff --git a/tests/classes/api/v1/api_v1_adapterTest.php b/tests/classes/api/v1/api_v1_adapterTest.php index d9331d8b09..7b31e20c23 100644 --- a/tests/classes/api/v1/api_v1_adapterTest.php +++ b/tests/classes/api/v1/api_v1_adapterTest.php @@ -557,12 +557,10 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $this->assertArrayHasKey('basket', $response['response']); $em = self::$DI['app']['EM']; - $repo = $em->getRepository('\Alchemy\Phrasea\Model\Entities\Basket'); - /* @var $repo Alchemy\Phrasea\Model\Repositories\BasketRepository */ - $basket = $repo->findUserBasket(self::$DI['app'], $response['response']['basket']['basket_id'], self::$DI['app']['authentication']->getUser(), true); + $basket = self::$DI['app']['converter.basket']->convert($response['response']['basket']['basket_id']); + self::$DI['app']['acl.basket']->isOwner($basket, self::$DI['app']['authentication']->getUser()); - $this->assertTrue($basket instanceof \Alchemy\Phrasea\Model\Entities\Basket); $em->remove($basket); $em->flush(); } @@ -581,20 +579,17 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $em->persist($Basket); $em->flush(); - $ssel_id = $Basket->getId(); - $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); - $result = $this->object->delete_basket($request, $ssel_id); + $result = $this->object->delete_basket($request, $Basket); $this->assertEquals(200, $result->get_http_code()); $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); - $repo = $em->getRepository('\Alchemy\Phrasea\Model\Entities\Basket'); - try { - $repo->findUserBasket(self::$DI['app'], $ssel_id, $user, true); + $basket = self::$DI['app']['converter.basket']->convert($Basket->getId()); + self::$DI['app']['acl.basket']->isOwner($basket, $user); $this->fail('An exception should have been raised'); - } catch (NotFoundHttpException $e) { + } catch (\Exception $e) { } } @@ -606,7 +601,7 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $basket = $this->insertOneBasket(); $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); - $result = $this->object->get_basket($request, $basket->getId()); + $result = $this->object->get_basket($request, $basket); $this->assertEquals(200, $result->get_http_code()); $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); @@ -619,7 +614,7 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $basket = $this->insertOneBasket(); $request = new Request(array(), array(), array('name' => 'PROUTO'), array(), array(), array('HTTP_Accept' => 'application/json')); - $result = $this->object->set_basket_title($request, $basket->getId()); + $result = $this->object->set_basket_title($request, $basket); $this->assertEquals(200, $result->get_http_code()); $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); @@ -638,7 +633,7 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $basket = $this->insertOneBasket(); $request = new Request(array(), array(), array('description' => 'une belle description'), array(), array(), array('HTTP_Accept' => 'application/json')); - $result = $this->object->set_basket_description($request, $basket->getId()); + $result = $this->object->set_basket_description($request, $basket); $this->assertEquals(200, $result->get_http_code()); $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true)));