* * 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\ActivityBundle\Timeline; use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\ActivityBundle\Repository\ActivityACLAwareRepository; use Doctrine\ORM\EntityManager; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; use Doctrine\ORM\Mapping\ClassMetadata; use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\Scope; use Chill\ActivityBundle\Entity\Activity; use Chill\MainBundle\Timeline\TimelineSingleQuery; /** * Provide activity for inclusion in timeline * */ class TimelineActivityProvider implements TimelineProviderInterface { /** * * @var EntityManager */ protected $em; /** * * @var AuthorizationHelper */ protected $helper; /** * * @var \Chill\MainBundle\Entity\User */ protected $user; protected ActivityACLAwareRepository $aclAwareRepository; private const SUPPORTED_CONTEXTS = [ 'center', 'person']; /** * TimelineActivityProvider constructor. * * @param EntityManager $em * @param AuthorizationHelper $helper * @param TokenStorageInterface $storage */ public function __construct( EntityManager $em, AuthorizationHelper $helper, TokenStorageInterface $storage, ActivityACLAwareRepository $aclAwareRepository ) { $this->em = $em; $this->helper = $helper; $this->aclAwareRepository = $aclAwareRepository; if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) { throw new \RuntimeException('A user should be authenticated !'); } $this->user = $storage->getToken()->getUser(); } /** * * {@inheritDoc} */ public function fetchQuery($context, array $args) { if ('center' === $context) { return TimelineSingleQuery::fromArray($this->aclAwareRepository ->queryTimelineIndexer($context, $args)); } $metadataActivity = $this->em->getClassMetadata(Activity::class); [$where, $parameters] = $this->getWhereClauseForPerson($args['person']); return TimelineSingleQuery::fromArray([ 'id' => $metadataActivity->getTableName() .'.'.$metadataActivity->getColumnName('id'), 'type' => 'activity', 'date' => $metadataActivity->getTableName() .'.'.$metadataActivity->getColumnName('date'), 'FROM' => $this->getFromClausePerson($args['person']), 'WHERE' => $where, 'parameters' => $parameters ]); } private function getWhereClauseForPerson(Person $person) { $parameters = []; $metadataActivity = $this->em->getClassMetadata(Activity::class); $associationMapping = $metadataActivity->getAssociationMapping('person'); $role = new Role('CHILL_ACTIVITY_SEE'); $reachableScopes = $this->helper->getReachableScopes($this->user, $role, $person->getCenter()); $whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) '); $scopes_ids = []; // first parameter: activity.person_id $parameters[] = $person->getId(); // loop on reachable scopes foreach ($reachableScopes as $scope) { if (\in_array($scope->getId(), $scopes_ids)) { continue; } $scopes_ids[] = '?'; $parameters[] = $scope->getId(); } return [ \strtr( $whereClause, [ '{activity.person_id}' => $associationMapping['joinColumns'][0]['name'], '{activity.scope_id}' => $metadataActivity->getTableName().'.'. $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], '{scopes_ids}' => \implode(", ", $scopes_ids) , ] ), $parameters ]; } private function getFromClausePerson() { $metadataActivity = $this->em->getClassMetadata(Activity::class); $metadataPerson = $this->em->getClassMetadata(Person::class); $associationMapping = $metadataActivity->getAssociationMapping('person'); return $metadataActivity->getTableName().' JOIN ' .$metadataPerson->getTableName().' ON ' .$metadataPerson->getTableName().'.'. $associationMapping['joinColumns'][0]['referencedColumnName'] .' = ' .$associationMapping['joinColumns'][0]['name'] ; } /** * * {@inheritDoc} */ public function getEntities(array $ids) { $activities = $this->em->getRepository(Activity::class) ->findBy(array('id' => $ids)); $result = array(); foreach($activities as $activity) { $result[$activity->getId()] = $activity; } return $result; } /** * * {@inheritDoc} */ public function getEntityTemplate($entity, $context, array $args) { $this->checkContext($context); return [ 'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', 'template_data' => [ 'activity' => $entity, 'context' => $context ] ]; } /** * * {@inheritDoc} */ public function supportsType($type) { return $type === 'activity'; } /** * check if the context is supported * * @param string $context * @throws \LogicException if the context is not supported */ private function checkContext($context) { if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) { throw new \LogicException("The context '$context' is not " . "supported. Currently only 'person' is supported"); } } }