mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-21 15:13:50 +00:00
first impl for global timeline: apply on activities
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
<?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\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;
|
||||
|
||||
|
||||
final class ActivityACLAwareRepository
|
||||
{
|
||||
private AuthorizationHelper $authorizationHelper;
|
||||
|
||||
private TokenStorageInterface $tokenStorage;
|
||||
|
||||
private ActivityRepository $repository;
|
||||
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
public function __construct(
|
||||
AuthorizationHelper $authorizationHelper,
|
||||
TokenStorageInterface $tokenStorage,
|
||||
ActivityRepository $repository,
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->repository = $repository;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function queryTimelineIndexer(string $context, array $args = []): array
|
||||
{
|
||||
$metadataActivity = $this->em->getClassMetadata(Activity::class);
|
||||
|
||||
$from = $this->getFromClauseCenter($args);
|
||||
$where = $this->getWhereClause($context, $args);
|
||||
|
||||
return [
|
||||
'id' => $metadataActivity->getTableName()
|
||||
.'.'.$metadataActivity->getColumnName('id'),
|
||||
'type' => 'activity',
|
||||
'date' => $metadataActivity->getTableName()
|
||||
.'.'.$metadataActivity->getColumnName('date'),
|
||||
'FROM' => $from,
|
||||
'WHERE' => $where
|
||||
];
|
||||
}
|
||||
|
||||
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 = [];
|
||||
|
||||
// condition will be:
|
||||
// FROM activity JOIN person -- not set by us
|
||||
// ON activity.person_id = person.id -- not set by us
|
||||
// WHERE -- not set by us
|
||||
// activity.person_id = ? AND -- only if $context = person
|
||||
// ( -- begin loop through centers, center#0
|
||||
// person.center_id = ?
|
||||
// AND ( -- begin loop for scopes within centers
|
||||
// activity.scope_id = ? -- scope#0
|
||||
// OR -- if scope#i where i > 0
|
||||
// activity.scope_id = ? -- scope#1
|
||||
// )
|
||||
// )
|
||||
// OR -- if center#i where i > 0
|
||||
// ( -- begin loop through centers, center#1
|
||||
// person.center_id = ?
|
||||
// AND ( -- begin loop for scopes within centers
|
||||
// activity.scope_id = ? -- scope#0
|
||||
// OR -- if scope#i where i > 0
|
||||
// activity.scope_id = ? -- scope#1
|
||||
// )
|
||||
// )
|
||||
|
||||
$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];
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
$qb = $this->repository->createQueryBuilder('a');
|
||||
$qb->select(['a.id', "'activity'", 'a.date']);
|
||||
$qb->join('a.person', 'p');
|
||||
|
||||
switch($context) {
|
||||
case 'center':
|
||||
$qb->where($this->queryTimelineIndexerWhereForCenter($qb, $args['centers']));
|
||||
break;
|
||||
default:
|
||||
throw new \LogicException('context not supported');
|
||||
}
|
||||
|
||||
if ($from) {
|
||||
$qb->andWhere($qb->gt('a.date', ':from'));
|
||||
$qb->setParameter('from', $from);
|
||||
}
|
||||
|
||||
if ($to) {
|
||||
$qb->andWhere($qb->gt('a.date', ':to'));
|
||||
$qb->setParameter('to', $to);
|
||||
}
|
||||
|
||||
return $qb->getQuery();
|
||||
}
|
||||
|
||||
private function queryTimelineIndexerWhereForCenter(QueryBuilder $qb, array $centers): Orx
|
||||
{
|
||||
$i = 0;
|
||||
$orx = $qb->expr()->orX();
|
||||
|
||||
foreach ($centers as $center) {
|
||||
$andx = $qb->expr()->andX();
|
||||
$andx->add($qb->expr()->eq('p.center', ":center_$i"));
|
||||
$qb->setParameter("center_$i", $center);
|
||||
$i++;
|
||||
|
||||
$scopes = $this->authorizationHelper->getReachableCircles(
|
||||
$this->tokenStorage->getToken()->getUser(),
|
||||
new Role(ActivityVoter::SEE_DETAILS),
|
||||
$center,
|
||||
);
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$andx->add($qb->expr()->eq('a.scope', ":scope_$i"));
|
||||
$qb->setParameter("scope_$i", $scope);
|
||||
$i++;
|
||||
}
|
||||
|
||||
$orx->add($andx);
|
||||
}
|
||||
|
||||
return $orx;
|
||||
}
|
||||
} */
|
@@ -0,0 +1,42 @@
|
||||
<?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 Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method AccompanyingPeriodParticipation[] findAll()
|
||||
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class ActivityRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Activity::class);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user