mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
220 lines
8.0 KiB
PHP
220 lines
8.0 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS,
|
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
namespace Chill\ActivityBundle\Repository;
|
|
|
|
use Chill\ActivityBundle\Entity\Activity;
|
|
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
|
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|
use Chill\PersonBundle\Entity\Person;
|
|
use Chill\ActivityBundle\Repository\ActivityRepository;
|
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
|
use Chill\MainBundle\Entity\Scope;
|
|
use Doctrine\ORM\QueryBuilder;
|
|
use Doctrine\ORM\Query\Expr\Orx;
|
|
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\EntityManagerInterface;
|
|
use Symfony\Component\Security\Core\Security;
|
|
|
|
|
|
final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInterface
|
|
{
|
|
private AuthorizationHelper $authorizationHelper;
|
|
|
|
private TokenStorageInterface $tokenStorage;
|
|
|
|
private ActivityRepository $repository;
|
|
|
|
private EntityManagerInterface $em;
|
|
|
|
private Security $security;
|
|
|
|
private CenterResolverDispatcher $centerResolverDispatcher;
|
|
|
|
public function __construct(
|
|
AuthorizationHelper $authorizationHelper,
|
|
CenterResolverDispatcher $centerResolverDispatcher,
|
|
TokenStorageInterface $tokenStorage,
|
|
ActivityRepository $repository,
|
|
EntityManagerInterface $em,
|
|
Security $security
|
|
) {
|
|
$this->authorizationHelper = $authorizationHelper;
|
|
$this->centerResolverDispatcher = $centerResolverDispatcher;
|
|
$this->tokenStorage = $tokenStorage;
|
|
$this->repository = $repository;
|
|
$this->em = $em;
|
|
$this->security = $security;
|
|
}
|
|
|
|
/**
|
|
* @param Person $person
|
|
* @param string $role
|
|
* @param int|null $start
|
|
* @param int|null $limit
|
|
* @param array $orderBy
|
|
* @return array|Activity[]
|
|
*/
|
|
public function findByPerson(Person $person, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array
|
|
{
|
|
$user = $this->security->getUser();
|
|
$center = $this->centerResolverDispatcher->resolveCenter($person);
|
|
if (0 === count($orderBy)) {
|
|
$orderBy = ['date' => 'DESC'];
|
|
}
|
|
|
|
$reachableScopes = $this->authorizationHelper
|
|
->getReachableCircles($user, $role, $center);
|
|
|
|
return $this->em->getRepository(Activity::class)
|
|
->findByPersonImplied($person, $reachableScopes, $orderBy, $limit, $start);
|
|
;
|
|
}
|
|
|
|
public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array
|
|
{
|
|
$user = $this->security->getUser();
|
|
$center = $this->centerResolverDispatcher->resolveCenter($period);
|
|
if (0 === count($orderBy)) {
|
|
$orderBy = ['date' => 'DESC'];
|
|
}
|
|
|
|
$scopes = $this->authorizationHelper
|
|
->getReachableCircles($user, $role, $center);
|
|
|
|
return $this->em->getRepository(Activity::class)
|
|
->findByAccompanyingPeriod($period, $scopes, true, $limit, $start, $orderBy);
|
|
}
|
|
|
|
public function queryTimelineIndexer(string $context, array $args = []): array
|
|
{
|
|
$metadataActivity = $this->em->getClassMetadata(Activity::class);
|
|
|
|
$from = $this->getFromClauseCenter($args);
|
|
[$where, $parameters] = $this->getWhereClause($context, $args);
|
|
|
|
return [
|
|
'id' => $metadataActivity->getTableName()
|
|
.'.'.$metadataActivity->getColumnName('id'),
|
|
'type' => 'activity',
|
|
'date' => $metadataActivity->getTableName()
|
|
.'.'.$metadataActivity->getColumnName('date'),
|
|
'FROM' => $from,
|
|
'WHERE' => $where,
|
|
'parameters' => $parameters
|
|
];
|
|
}
|
|
|
|
private function getFromClauseCenter(array $args): string
|
|
{
|
|
$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']
|
|
;
|
|
}
|
|
|
|
private function getWhereClause(string $context, array $args): array
|
|
{
|
|
$where = '';
|
|
$parameters = [];
|
|
|
|
$metadataActivity = $this->em->getClassMetadata(Activity::class);
|
|
$metadataPerson = $this->em->getClassMetadata(Person::class);
|
|
$activityToPerson = $metadataActivity->getAssociationMapping('person')['joinColumns'][0]['name'];
|
|
$activityToScope = $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'];
|
|
$personToCenter = $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'];
|
|
|
|
|
|
// acls:
|
|
$role = new Role(ActivityVoter::SEE);
|
|
$reachableCenters = $this->authorizationHelper->getReachableCenters($this->tokenStorage->getToken()->getUser(),
|
|
$role);
|
|
|
|
if (count($reachableCenters) === 0) {
|
|
// insert a dummy condition
|
|
return 'FALSE = TRUE';
|
|
}
|
|
|
|
if ($context === 'person') {
|
|
// we start with activities having the person_id linked to person
|
|
$where .= sprintf('%s = ? AND ', $activityToPerson);
|
|
$parameters[] = $person->getId();
|
|
}
|
|
|
|
// we add acl (reachable center and scopes)
|
|
$where .= '('; // first loop for the for centers
|
|
$centersI = 0; // like centers#i
|
|
foreach ($reachableCenters as $center) {
|
|
// we pass if not in centers
|
|
if (!\in_array($center, $args['centers'])) {
|
|
continue;
|
|
}
|
|
// we get all the reachable scopes for this center
|
|
$reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), $role, $center);
|
|
// we get the ids for those scopes
|
|
$reachablesScopesId = array_map(
|
|
function(Scope $scope) { return $scope->getId(); },
|
|
$reachableScopes
|
|
);
|
|
|
|
// if not the first center
|
|
if ($centersI > 0) {
|
|
$where .= ') OR (';
|
|
}
|
|
|
|
// condition for the center
|
|
$where .= sprintf(' %s.%s = ? ', $metadataPerson->getTableName(), $personToCenter);
|
|
$parameters[] = $center->getId();
|
|
|
|
// begin loop for scopes
|
|
$where .= ' AND (';
|
|
$scopesI = 0; //like scope#i
|
|
|
|
foreach ($reachablesScopesId as $scopeId) {
|
|
if ($scopesI > 0) {
|
|
$where .= ' OR ';
|
|
}
|
|
$where .= sprintf(' %s.%s = ? ', $metadataActivity->getTableName(), $activityToScope);
|
|
$parameters[] = $scopeId;
|
|
$scopesI ++;
|
|
}
|
|
// close loop for scopes
|
|
$where .= ') ';
|
|
$centersI++;
|
|
}
|
|
// close loop for centers
|
|
$where .= ')';
|
|
|
|
return [$where, $parameters];
|
|
}
|
|
|
|
}
|