diff --git a/Controller/ExportController.php b/Controller/ExportController.php index 193569fdd..d18b90510 100644 --- a/Controller/ExportController.php +++ b/Controller/ExportController.php @@ -47,7 +47,7 @@ class ExportController extends Controller { $exportManager = $this->get('chill.main.export_manager'); - $exports = $exportManager->getExports(); + $exports = $exportManager->getExports(true); return $this->render('ChillMainBundle:Export:layout.html.twig', array( 'exports' => $exports @@ -72,6 +72,15 @@ class ExportController extends Controller */ public function newAction(Request $request, $alias) { + // first check for ACL + $exportManager = $this->get('chill.main.export_manager'); + $export = $exportManager->getExport($alias); + $centers = $this->get('chill.main.security.authorization.helper') + ->getReachableCenters($this->getUser(), $export->requiredRole()); + if ($exportManager->isGrantedForElement($export, $centers) === FALSE) { + throw $this->createAccessDeniedException('The user does not have access to this export'); + } + $step = $request->query->getAlpha('step', 'centers'); switch ($step) { @@ -93,6 +102,7 @@ class ExportController extends Controller public function selectCentersStep(Request $request, $alias) { + /* @var $exportManager \Chill\MainBundle\Export\ExportManager */ $exportManager = $this->get('chill.main.export_manager'); $form = $this->createCreateFormExport($alias, 'centers'); @@ -106,6 +116,14 @@ class ExportController extends Controller 'location' => __METHOD__)); $data = $form->getData(); + + // check ACL + if ($exportManager->isGrantedForElement($export, + $exportManager->getPickedCenters($data['centers'])) === FALSE) { + throw $this->createAccessDeniedException('you do not have ' + . 'access to this export for those centers'); + } + $this->get('session')->set('centers_step_raw', $request->request->all()); $this->get('session')->set('centers_step', $data); @@ -138,9 +156,20 @@ class ExportController extends Controller { $exportManager = $this->get('chill.main.export_manager'); + // check we have data from the previous step (export step) + $data = $this->get('session')->get('centers_step', null); + + if ($data === null) { + + return $this->redirectToRoute('chill_main_export_new', array( + 'step' => $this->getNextStep('export', true), + 'alias' => $alias + )); + } + $export = $exportManager->getExport($alias); - $form = $this->createCreateFormExport($alias, 'export'); + $form = $this->createCreateFormExport($alias, 'export', $data); if ($request->getMethod() === 'POST') { $form->handleRequest($request); @@ -196,13 +225,14 @@ class ExportController extends Controller if ($step === 'centers') { $builder->add('centers', PickCenterType::class, array( - 'export_alias' => $alias + 'export_alias' => $alias )); } if ($step === 'export' or $step === 'generate_export') { $builder->add('export', ExportType::class, array( - 'export_alias' => $alias, + 'export_alias' => $alias, + 'picked_centers' => $exportManager->getPickedCenters($data['centers']) )); } @@ -323,6 +353,7 @@ class ExportController extends Controller */ protected function forwardToGenerate(Request $request, $alias) { + $dataCenters = $this->get('session')->get('centers_step_raw', null); $dataFormatter = $this->get('session')->get('formatter_step_raw', null); $dataExport = $this->get('session')->get('export_step_raw', null); @@ -341,6 +372,7 @@ class ExportController extends Controller $redirectParameters = array_merge( $dataFormatter, $dataExport, + $dataCenters, array('alias' => $alias) ); unset($redirectParameters['_token']); diff --git a/Entity/Center.php b/Entity/Center.php index a526c2468..8eb5331f0 100644 --- a/Entity/Center.php +++ b/Entity/Center.php @@ -25,7 +25,7 @@ namespace Chill\MainBundle\Entity; * * @author Julien Fastré */ -class Center +class Center implements HasCenterInterface { /** * @@ -82,5 +82,9 @@ class Center return $this->getName(); } + public function getCenter() + { + return $this; + } } diff --git a/Export/ExportElementInterface.php b/Export/ExportElementInterface.php new file mode 100644 index 000000000..0ea32f22f --- /dev/null +++ b/Export/ExportElementInterface.php @@ -0,0 +1,33 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\MainBundle\Export; + +/** + * The common methods between different object used to build export (i.e. : ExportInterface, + * FilterInterface, AggregatorInterface + * + * @author Julien Fastré + */ +interface ExportElementInterface +{ + public function requiredRole(); + + public function getTitle(); +} diff --git a/Export/ExportInterface.php b/Export/ExportInterface.php index a44a9ef6d..14cb21424 100644 --- a/Export/ExportInterface.php +++ b/Export/ExportInterface.php @@ -26,7 +26,7 @@ use Symfony\Component\Form\FormBuilderInterface; * * @author Julien Fastré */ -interface ExportInterface +interface ExportInterface extends ExportElementInterface { public function getType(); diff --git a/Export/ExportManager.php b/Export/ExportManager.php index f042f72fb..b9c7ad1d9 100644 --- a/Export/ExportManager.php +++ b/Export/ExportManager.php @@ -27,6 +27,9 @@ use Symfony\Component\HttpFoundation\Response; use Psr\Log\LoggerInterface; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; /** * Collects all agregators, filters and export from @@ -73,10 +76,33 @@ class ExportManager */ private $em; - public function __construct(LoggerInterface $logger, EntityManagerInterface $em) + /** + * + * @var AuthorizationChecker + */ + private $authorizationChecker; + + /** + * + * @var AuthorizationHelper + */ + private $authorizationHelper; + + /** + * + * @var \Symfony\Component\Security\Core\User\UserInterface + */ + private $user; + + public function __construct(LoggerInterface $logger, EntityManagerInterface $em, + AuthorizationChecker $authorizationChecker, AuthorizationHelper $authorizationHelper, + TokenStorageInterface $tokenStorage) { $this->logger = $logger; $this->em = $em; + $this->authorizationChecker = $authorizationChecker; + $this->authorizationHelper = $authorizationHelper; + $this->user = $tokenStorage->getToken()->getUser(); } public function addFilter(FilterInterface $filter, $alias) @@ -119,11 +145,22 @@ class ExportManager /** * Return all exports. The exports's alias are the array's keys. * + * @param boolean $whereUserIsGranted if true (default), restrict to user which are granted the right to execute the export * @return ExportInterface[] an array where export's alias are keys */ - public function getExports() + public function getExports($whereUserIsGranted = true) { - return $this->exports; + foreach ($this->exports as $alias => $export) { + if ($whereUserIsGranted) { + $centers = $this->authorizationHelper->getReachableCenters($this->user, + $export->requiredRole()); + if ($this->isGrantedForElement($export, $centers)) { + yield $alias => $export; + } + } else { + yield $alias => $export; + } + } } /** @@ -206,20 +243,49 @@ class ExportManager /** - * Return a \Generator containing filter which support type + * Return a \Generator containing filter which support type. If `$centers` is + * not null, restrict the given filters to the center the user have access to. * * @param string[] $types + * @param \Chill\MainBundle\Entity\Center[] $centers the centers where the user have access to * @return FilterInterface[] a \Generator that contains filters. The key is the filter's alias */ - public function &getFiltersApplyingOn(array $types) + public function &getFiltersApplyingOn(array $types, array $centers = null) { foreach ($this->filters as $alias => $filter) { - if (in_array($filter->applyOn(), $types)) { + if (in_array($filter->applyOn(), $types) + && $this->isGrantedForElement($filter, $centers)) { yield $alias => $filter; } } } + /** + * Return true if the current user has access to the ExportElement for every + * center, false if the user hasn't access to element for at least one center. + * + * @param \Chill\MainBundle\Export\ExportElementInterface $element + * @param array $centers + * @return boolean + */ + public function isGrantedForElement(ExportElementInterface $element, array $centers) + { + foreach($centers as $center) { + if ($this->authorizationChecker->isGranted( + $element->requiredRole()->getRole(), $center) === FALSE) { + //debugging + $this->logger->debug('user has no access to element', array( + 'method' => __METHOD__, + 'type' => get_class($element), 'center' => $center->getName() + )); + + return false; + } + } + + return TRUE; + } + /** * Return a \Generator containing filter which support type * @@ -314,6 +380,11 @@ class ExportManager return $data['pick_formatter']['alias']; } + public function getPickedCenters(array $data) + { + return $data['c']; + } + /** * parse the data to retrieve the used filters and aggregators * diff --git a/Export/FilterInterface.php b/Export/FilterInterface.php index da43a6845..0011376a5 100644 --- a/Export/FilterInterface.php +++ b/Export/FilterInterface.php @@ -27,13 +27,11 @@ use Symfony\Component\Form\FormBuilderInterface; * * @author Julien Fastré */ -interface FilterInterface +interface FilterInterface extends ExportElementInterface { public function applyOn(); public function buildForm(FormBuilderInterface $builder); public function alterQuery(QueryBuilder $qb, $data); - - public function getTitle(); } diff --git a/Form/Type/Export/ExportType.php b/Form/Type/Export/ExportType.php index 15e9d622f..21d525b7e 100644 --- a/Form/Type/Export/ExportType.php +++ b/Form/Type/Export/ExportType.php @@ -59,7 +59,8 @@ class ExportType extends AbstractType } */ //add filters - $filters = $this->exportManager->getFiltersApplyingOn($export->supportsModifiers()); + $filters = $this->exportManager->getFiltersApplyingOn($export->supportsModifiers(), + $options['picked_centers']); $filterBuilder = $builder->create('filters', 'form', array('compound' => true)); foreach($filters as $alias => $filter) { @@ -97,7 +98,7 @@ class ExportType extends AbstractType public function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired(array('export_alias')) + $resolver->setRequired(array('export_alias', 'picked_centers')) ->setAllowedTypes('export_alias', array('string')) ->setDefault('compound', true) ; diff --git a/Resources/config/services.yml b/Resources/config/services.yml index e3c408584..26c0157ff 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -154,6 +154,9 @@ services: arguments: - "@logger" - "@doctrine.orm.entity_manager" + - "@security.authorization_checker" + - "@chill.main.security.authorization.helper" + - "@security.token_storage" chill.main.form.type.export: class: Chill\MainBundle\Form\Type\Export\ExportType