From 7574b5bfac3c637ce1912ca1dde5a2db99b36220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 9 Nov 2021 17:04:32 +0100 Subject: [PATCH 01/37] doc for authorization --- .../development/access_control_model.rst | 788 ++++++++++++++++-- 1 file changed, 704 insertions(+), 84 deletions(-) diff --git a/docs/source/development/access_control_model.rst b/docs/source/development/access_control_model.rst index 58fe44319..e159f7fb6 100644 --- a/docs/source/development/access_control_model.rst +++ b/docs/source/development/access_control_model.rst @@ -23,15 +23,196 @@ Every time an entity is created, viewed or updated, the software check if the us The user must be granted access to the action on this particular entity, with this scope and center. +TL;DR +===== + +Resolve scope and center +------------------------ + +In a service, resolve the center and scope of an entity + +.. code-block:: php + + use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; + use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher; + + + class MyService { + private ScopeResolverDispatcher $scopeResolverDispatcher; + private CenterResolverDispatcher $centerResolverDispatcher; + + public function myFunction($entity) { + /** @var null|Center[]|Center $center */ + $center = $this->centerResolverDispatcher->resolveCenter($entity); + // $center may be null, an array of center, or an instance of Center + + if ($this->scopeResolverDispatcher->isConcerned($entity) { + /** @var null|Scope[]|Scope */ + $scope = $this-scopeResolverDispatcher->resolveScope($entity); + // $scope may be null, an array of Scope, or an instance of Scope + } + + } + + } + +In twig template, resolve the center: + +.. code-block:: twig + + {# resolve a center #} + + {% if person|chill_resolve_center is not null%} + + {% if person|chill_resolve_center is iterable %} + {% set centers = person|chill_resolve_center %} + {% else %} + {% set centers = [ person|chill_resolve_center ] %} + {% endif %} + + + {{ 'Center'|trans|upper}} : + + {% for c in centers %} + {{ c.name|upper }} + {% if not loop.last %}, {% endif %} + {% endfor %} + {%- endif -%} + +In twig template, resolve the scope: + +.. code-block:: twig + + {% if entity|chill_is_scope_concerned %} + + {% if entity|chill_resolve_scope is iterable %} + {% set scopes = entity|chill_resolve_scope %} + {% else %} + {% set scopes = [ entity|chill_resolve_scope ] %} + {% endif %} + + Scopes : + {% for s in scopes %} + {{ c.name|localize_translatable_string }} + {% if not loop.last %}, {% endif %} + {% endfor %} + {%- endif -%} + +Build a ``Voter`` +----------------- + +.. code-block:: php + + security = $security; + + // we build here a voter helper. This will ease the operations below. + // when the authorization model is changed, it will be easy to make a different implementation + // of the helper, instead of writing all Voters + + $this->voterHelper = $voterHelperFactory + // create a builder with some context + ->generate(self::class) + // add the support of given roles for given class: + ->addCheckFor(Person::class, [self::SEE, self::CREATE]) + ->addCheckFor(PersonDocument::class, $this->getRoles()) + ->build(); + } + + + protected function supports($attribute, $subject) + { + return $this->voterHelper->supports($attribute, $subject); + } + + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + // basic check + if (!$token->getUser() instanceof User) { + return false; + } + + // we first check the acl for associated elements. + // here, we must be able to see the person associated to the document: + if ($subject instanceof PersonDocument + && !$this->security->isGranted(PersonVoter::SEE, $subject->getPerson())) { + + // not possible to see the associated person ? Then, not possible to see the document! + return false; + } + + // the voter helper will implements the logic: + return $this->voterHelper->voteOnAttribute($attribute, $subject, $token); + } + + // all the method below are used to register roles into the admin part + public function getRoles() + { + return [ + self::CREATE, + self::SEE, + self::SEE_DETAILS, + self::UPDATE, + self::DELETE + ]; + } + + public function getRolesWithoutScope() + { + return array(); + } + + + public function getRolesWithHierarchy() + { + return ['PersonDocument' => $this->getRoles() ]; + } + } + + + + From an user point of view --------------------------- +========================== The software is design to allow fine tuned access rights for complicated installation and team structure. The administrators may also decide that every user has the right to see all resources, where team have a more simple structure. Here is an overview of the model. Chill can be multi-center -^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------- Chill is designed to be installed once for social center who work with multiple teams separated, or for social services's federation who would like to share the same installation of the software for all their members. @@ -42,7 +223,7 @@ Otherwise, it is not required to create multiple center: Chill can also work for Obviously, users working in the different centers are not allowed to see the entities (_persons_, _reports_, _activities_) of other centers. But users may be attached to multiple centers: consequently they will be able to see the entities of the multiple centers they are attached to. Inside center, scope divide team -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------- Users are attached to one or more center and, inside to those center, there may exists differents scopes. The aim of those _scopes_ is to divide the whole team of social worker amongst different departement, for instance: the social team, the psychologist team, the nurse team, the administrative team, ... Each team is granted of different rights amongst scope. For instance, the social team may not see the _activities_ of the psychologist team. The administrative team may see the date & time's activities, but is not allowed to see the detail of those entities (the personal notes, ...). @@ -52,8 +233,38 @@ As entities have only one scopes, if some entities must be shared across two dif Example: if some activities must be seen and updated between nurses and psychologists, the administrator will create a scope "nurse and psy" and add the ability for both team "nurse" and "psychologist" to "create", "see", and "update" the activities belonging to scope "nurse and psy". + +Where does the ``scope`` and ``center`` comes from ? +==================================================== + +Most often, scope and center comes from user's input: + +* when person is created, Chill asks the associated center to the user. Then, every entity associated to the user (Activity, ...) is associated to this center; +* when an entity is created, Chill asks the associated scope. + +The UI check the model before adding those input into form. If the user hae access to only one center or scope, this scope or center is filled automatically, and the UI does not ask the user. Most of the times, the user does not see "Pick a scope" and "Pick a center" inputs. + +Scope and Center are associated to entities through ``ManyToOne`` properties, which are then mapped to ``FOREIGN KEY`` in tables, ... + +But sometimes, this implementation does not fits the needs: + +* persons are associated to center *geographically*: the address of each person contains lat/lon coordinates, and the center is resolved from this coordinated; +* some would like to associated persons to multiple center, or one center; +* entities are associated to scope through the job reached by "creator" (an user); +* some would like not to use scope at all; +* … + +For this reasons, associated center and scopes must be resolved programmatically. The default implementation rely on the model association, as described above. But it becomes possible to change the behaviour on different implementations. + +Is my entity "concerned" by scopes ? +------------------------------------ + +Some entities are concerned by scope, some not. + +This is also programmatically resolved. + The concepts translated into code ------------------------------------ +=================================== .. figure:: /_static/access_control_model.png @@ -81,7 +292,7 @@ At each step of his lifetime (creation, view of the entity and eventually of his All those action are executed through symfony voters and helpers. How to check authorization ? ----------------------------- +============================ Just use the symfony way-of-doing, but do not forget to associate the entity you want to check access. For instance, in controller : @@ -100,34 +311,23 @@ Just use the symfony way-of-doing, but do not forget to associate the entity you And in template : -.. code-block:: html+jinja +.. code-block:: twig {{ if is_granted('CHILL_ENTITY_SEE', entity) %}print something{% endif %} -Retrieving reachable scopes and centers ----------------------------------------- +Retrieving reachable scopes and centers for a user +-------------------------------------------------- -The class :class:`Chill\\MainBundle\\Security\\Authorization\\AuthorizationHelper` helps you to get centers and scope reachable by a user. +The class :class:`Chill\\MainBundle\\Security\\Authorization\\AuthorizationHelperInterface` helps you to get centers and scope reachable by a user. Those methods are intentionnaly build to give information about user rights: - getReachableCenters: to get reachable centers for a user - getReachableScopes : to get reachable scopes for a user -.. note:: - - The service is reachable through the Depedency injection with the key `chill.main.security.authorization.helper`. Example : - - .. code-block:: php - - $helper = $container->get('chill.main.security.authorization.helper'); - -.. todo:: - - Waiting for a link between our api and this doc, we invite you to read the method signatures `here `_ Adding your own roles -===================== +--------------------- Extending Chill will requires you to define your own roles and rules for your entities. You will have to define your own voter to do so. @@ -152,7 +352,7 @@ To create your own roles, you should: Declare your role ------------------- +^^^^^^^^^^^^^^^^^^ To declare new role, implement the class :class:`Chill\\MainBundle\\Security\\ProvideRoleInterface`. @@ -212,69 +412,8 @@ Example of an implementation of :class:`Chill\\MainBundle\\Security\\ProvideRole } -Implement your voter --------------------- - -Inside this class, you might use the :class:`Chill\\MainBundle\\Security\\Authorization\\AuthorizationHelper` to check permission (do not re-invent the wheel). This is a real-world example: - -.. code-block:: php - - namespace Chill\ReportBundle\Security\Authorization; - use Chill\MainBundle\Security\Authorization\AbstractChillVoter; - use Chill\MainBundle\Security\Authorization\AuthorizationHelper; - - - class ReportVoter extends AbstractChillVoter - { - const CREATE = 'CHILL_REPORT_CREATE'; - const SEE = 'CHILL_REPORT_SEE'; - const UPDATE = 'CHILL_REPORT_UPDATE'; - - /** - * - * @var AuthorizationHelper - */ - protected $helper; - - public function __construct(AuthorizationHelper $helper) - { - $this->helper = $helper; - } - - protected function getSupportedAttributes() - { - return array(self::CREATE, self::SEE, self::UPDATE); - } - protected function getSupportedClasses() - { - return array('Chill\ReportBundle\Entity\Report'); - } - protected function isGranted($attribute, $report, $user = null) - { - if (! $user instanceof \Chill\MainBundle\Entity\User){ - - return false; - } - - return $this->helper->userHasAccess($user, $report, $attribute); - } - } - -Then, you will have to declare the service and tag it as a voter : - -.. code-block:: yaml - - services: - chill.report.security.authorization.report_voter: - class: Chill\ReportBundle\Security\Authorization\ReportVoter - arguments: - - "@chill.main.security.authorization.helper" - tags: - - { name: security.voter } - - Adding role hierarchy ---------------------- +^^^^^^^^^^^^^^^^^^^^^ You should prepend Symfony's security component directly from your code. @@ -312,3 +451,484 @@ You should prepend Symfony's security component directly from your code. } + +Implement your voter +^^^^^^^^^^^^^^^^^^^^ + +Most of the time, Voter will check that: + +1. The given role is reachable (= ``$attribute``) +2. for the given center, +3. and, if any, for the given role +4. if the entity is associated to another entity, this entity should be, at least, viewable by the user. + +Thats what we call the "autorization logic". But this logic may be replace by a new one, and developers should take care of it. + + +Then voter implementation should take care of: + +* check the access to associated entities. For instance, if an ``Activity`` is associated to a ``Person``, the voter should first check that the user can show the associated ``Person``; +* as far as possible, delegates the check for associated center, scopes, and check for authorization using the authorization logic. VoterHelper will ease the most common operation of this logic. + +This is an example of implementation: + + +.. code-block:: php + + security = $security; + + // we build here a voter helper. This will ease the operations below. + // when the authorization model is changed, it will be easy to make a different implementation + // of the helper, instead of writing all Voters + + $this->voterHelper = $voterHelperFactory + // create a builder with some context + ->generate(self::class) + // add the support of given roles for given class: + ->addCheckFor(Person::class, [self::SEE, self::CREATE]) + ->addCheckFor(PersonDocument::class, $this->getRoles()) + ->build(); + } + + + protected function supports($attribute, $subject) + { + return $this->voterHelper->supports($attribute, $subject); + } + + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + // basic check + if (!$token->getUser() instanceof User) { + return false; + } + + // we first check the acl for associated elements. + // here, we must be able to see the person associated to the document: + if ($subject instanceof PersonDocument + && !$this->security->isGranted(PersonVoter::SEE, $subject->getPerson())) { + + // not possible to see the associated person ? Then, not possible to see the document! + return false; + } + + // the voter helper will implements the logic of checking: + // 1. that the center is reachable + // 2. for this given entity + // 3. for this given scope + // 4. and for the given role + return $this->voterHelper->voteOnAttribute($attribute, $subject, $token); + } + + public function getRoles() + { + // ... + } + + public function getRolesWithoutScope() + { + // ... + } + + + public function getRolesWithHierarchy() + { + // ... + } + } + +Then, you will have to declare the service and tag it as a voter : + +.. code-block:: yaml + + services: + chill.report.security.authorization.report_voter: + class: Chill\ReportBundle\Security\Authorization\ReportVoter + arguments: + - "@chill.main.security.authorization.helper" + tags: + - { name: security.voter } + + +How to resolve scope and center programmatically ? +================================================== + +In a service, resolve the center and scope of an entity + +.. code-block:: php + + use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; + use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher; + + + class MyService { + private ScopeResolverDispatcher $scopeResolverDispatcher; + private CenterResolverDispatcher $centerResolverDispatcher; + + public function myFunction($entity) { + /** @var null|Center[]|Center $center */ + $center = $this->centerResolverDispatcher->resolveCenter($entity); + // $center may be null, an array of center, or an instance of Center + + if ($this->scopeResolverDispatcher->isConcerned($entity) { + /** @var null|Scope[]|Scope */ + $scope = $this-scopeResolverDispatcher->resolveScope($entity); + // $scope may be null, an array of Scope, or an instance of Scope + } + + } + + } + +In twig template, resolve the center: + +.. code-block:: twig + + {# resolve a center #} + + {% if person|chill_resolve_center is not null%} + + {% if person|chill_resolve_center is iterable %} + {% set centers = person|chill_resolve_center %} + {% else %} + {% set centers = [ person|chill_resolve_center ] %} + {% endif %} + + + {{ 'Center'|trans|upper}} : + + {% for c in centers %} + {{ c.name|upper }} + {% if not loop.last %}, {% endif %} + {% endfor %} + {%- endif -%} + +In twig template, resolve the scope: + +.. code-block:: twig + + {% if entity|chill_is_scope_concerned %} + + {% if entity|chill_resolve_scope is iterable %} + {% set scopes = entity|chill_resolve_scope %} + {% else %} + {% set scopes = [ entity|chill_resolve_scope ] %} + {% endif %} + + Scopes : + {% for s in scopes %} + {{ c.name|localize_translatable_string }} + {% if not loop.last %}, {% endif %} + {% endfor %} + {%- endif -%} + +What is the default implementation of Scope and Center resolver ? +----------------------------------------------------------------- + +By default, the implementation rely on association into entities. + +* implements ``Chill\MainBundle\Entity\HasCenterInterface`` on entities which have one or any center; +* implements ``Chill\MainBundle\Entity\HasCentersInterface`` on entities which have one, multiple or any centers; +* implements ``Chill\MainBundle\Entity\HasScopeInterface`` on entities which have one or any scope; +* implements ``Chill\MainBundle\Entity\HasScopesInterface`` on entities which have one or any scopes; + +Then, the default implementation will resolve the center and scope based on the implementation in your model. + +How to change the default behaviour ? +------------------------------------- + +Implements those interface into services: + +* ``Chill\MainBundle\Security\Resolver\CenterResolverInterface``; +* ``Chill\MainBundle\Security\Resolver\ScopeResolverInterface``; + +Authorization into lists and index pages +======================================== + +Due to the fact that authorization model may be overriden, "list" and "index" pages should not rely on center and scope from controller. This must be delegated to dedicated service, which will be aware of the authorization model. We call them ``ACLAwareRepository``. This service must implements an interface, in order to allow to change the implementation. + +The controller **must not** performs any DQL or SQL query. + +Example in a controller: + +.. code-block:: php + + namespace Chill\TaskBundle\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Chill\TaskBundle\Repository\SingleTaskAclAwareRepositoryInterface; + + + final class SingleTaskController extends AbstractController + { + + private SingleTaskAclAwareRepositoryInterface $singleTaskAclAwareRepository; + + /** + * + * @Route( + * "/{_locale}/task/single-task/list", + * name="chill_task_singletask_list" + * ) + */ + public function listAction( + Request $request + ) { + $this->denyAccessUnlessGranted(TaskVoter::SHOW, null); + + $nb = $this->singleTaskAclAwareRepository->countByAllViewable( + '', // search pattern + [] // search flags + ); + $paginator = $this->paginatorFactory->create($nb); + + if (0 < $nb) { + $tasks = $this->singleTaskAclAwareRepository->findByAllViewable( + '', // search pattern + [] // search flags + $paginator->getCurrentPageFirstItemNumber(), + $paginator->getItemsPerPage(), + // ordering: + [ + 'startDate' => 'DESC', + 'endDate' => 'DESC', + ] + ); + } else { + $tasks = []; + } + + return $this->render('@ChillTask/SingleTask/List/index.html.twig', [ + 'tasks' => $tasks, + 'paginator' => $paginator, + 'filter_order' => $filterOrder + ]); + } + } + +Writing ``ACLAwareRepository`` +------------------------------ + +The ACLAwareRepository should rely on interfaces +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As described above, the ACLAwareRepository will perform the query for listing entities, and take care of authorization. + +Those "ACLAwareRepositories" must be described into ``interfaces``. + +The service must rely on this interface, and not on the default implementation. + +Example: at first, we design an interface for listing ``SingleTask`` entities: + + +.. code-block:: php + + buildQuery($criterias); + + return $this->addAuthorizations($qb)->select("COUNT(e)")->getQuery()->getResult()->getSingleScalarResult(); + } + + public function findByAuthorized(array $criteria, int $start, int $limit, array $orderBy): array + { + $qb = $this->buildQuery($criterias); + + return $this->getResult($this->addAuthorizations($qb), $start, $limit, $orderBy); + } + + public function getResult(QueryBuilder $qb, int $start, int $limit, array $orderBy): array + { + $qb + ->setFirstResult($start) + ->setMaxResults($limit) + ; + + // add order by logic + + return $qb->getQuery()->getResult(); + } + + public function buildQuery(array $criterias): QueryBuilder + { + $qb = $this->em->createQueryBuilder(); + + // implement you logic with search criteria here + + return $qb; + } + + private function addAuthorizations(QueryBuilder $qb): QueryBuilder + { + // add authorization logic here + return $qb; + } + + } + +Once this logic is executed, it becomes easy to make a new implementation of the repository: + +.. code-block:: php + + namespace Chill\MyOtherBundle\Repository; + + use Doctrine\ORM\EntityManagerInterface; + use Doctrine\ORM\QueryBuilder; + use Chill\MyBundle\Repository\MyEntityACLAwareRepository + + + final class AnotherEntityACLAwareRepository implements MyEntityACLAwareRepositoryInterface { + + private EntityManagerInterface $em; + private \Chill\MyBundle\Repository\MyEntityACLAwareRepository $initial; + + public function __construct( + EntityManagerInterface $em, + \Chill\MyBundle\Repository\MyEntityACLAwareRepository $initial + ) { + $this->em = $em; + $this->initial = $initial; + } + + public function countByAuthorized(array $criterias): int + { + $qb = $this->initial->buildQuery($criterias); + + return $this->addAuthorizations($qb)->select("COUNT(e)")->getQuery()->getResult()->getSingleScalarResult(); + } + + public function findByAuthorized(array $criteria, int $start, int $limit, array $orderBy): array + { + $qb = $this->initial->buildQuery($criterias); + + return $this->initial->getResult($this->addAuthorizations($qb), $start, $limit, $orderBy); + } + + private function addAuthorizations(QueryBuilder $qb): QueryBuilder + { + // add a different authorization logic here + return $qb; + } + + } + +Then, register this service and decorates the old one: + +.. code-block:: yaml + + services: + Chill\MyOtherBundle\Repository\AnotherEntityACLAwareRepository: + autowire: true + autoconfigure: true + decorates: Chill\MyBundle\Repository\MyEntityACLAwareRepositoryInterface: + + + + From e7fcebc99ebd68c0a88f346bf27fff5f1ec798e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 9 Nov 2021 17:04:49 +0100 Subject: [PATCH 02/37] add some method for resolving scope in twig --- .../DataFixtures/ORM/LoadActivity.php | 2 ++ .../Authorization/PersonDocumentVoter.php | 25 ------------- .../Resolver/ResolverTwigExtension.php | 30 +++++++++++++--- .../Helper/RandomPersonHelperTrait.php | 35 +++++++++++++++++++ .../Resources/views/Entity/person.html.twig | 10 +++++- .../Controller/SingleTaskController.php | 12 ------- 6 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php index a23b2d73f..15db14b75 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php @@ -22,6 +22,7 @@ namespace Chill\ActivityBundle\DataFixtures\ORM; +use Chill\PersonBundle\DataFixtures\Helper\RandomPersonHelperTrait; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; @@ -41,6 +42,7 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface; class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface { use \Symfony\Component\DependencyInjection\ContainerAwareTrait; + use RandomPersonHelperTrait; /** * @var \Faker\Generator diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php index 3eb21ed19..73254278b 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php @@ -1,44 +1,19 @@ . - */ - namespace Chill\DocStoreBundle\Security\Authorization; -use App\Security\Authorization\VoterHelperFactory; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface; use Chill\MainBundle\Security\Authorization\VoterHelperInterface; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\DocStoreBundle\Entity\PersonDocument; -use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Role\Role; use Psr\Log\LoggerInterface; use Symfony\Component\Security\Core\Security; -/** - * - */ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { const CREATE = 'CHILL_PERSON_DOCUMENT_CREATE'; diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php b/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php index 21ece21a3..c8fdea5ff 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php @@ -7,19 +7,20 @@ use Twig\TwigFilter; final class ResolverTwigExtension extends \Twig\Extension\AbstractExtension { private CenterResolverDispatcher $centerResolverDispatcher; + private ScopeResolverInterface $scopeResolverDispatcher; - /** - * @param CenterResolverDispatcher $centerResolverDispatcher - */ - public function __construct(CenterResolverDispatcher $centerResolverDispatcher) + public function __construct(CenterResolverDispatcher $centerResolverDispatcher, ScopeResolverInterface $scopeResolverDispatcher) { $this->centerResolverDispatcher = $centerResolverDispatcher; + $this->scopeResolverDispatcher = $scopeResolverDispatcher; } public function getFilters() { return [ - new TwigFilter('chill_resolve_center', [$this, 'resolveCenter']) + new TwigFilter('chill_resolve_center', [$this, 'resolveCenter']), + new TwigFilter('chill_resolve_scope', [$this, 'resolveScope']), + new TwigFilter('chill_is_scope_concerned', [$this, 'isScopeConcerned']), ]; } @@ -33,4 +34,23 @@ final class ResolverTwigExtension extends \Twig\Extension\AbstractExtension return $this->centerResolverDispatcher->resolveCenter($entity, $options); } + /** + * @param $entity + * @param array|null $options + * @return bool + */ + public function isScopeConcerned($entity, ?array $options = []) + { + return $this->scopeResolverDispatcher->isConcerned($entity, $options); + } + + /** + * @param $entity + * @param array|null $options + * @return array|\Chill\MainBundle\Entity\Scope|\Chill\MainBundle\Entity\Scope[] + */ + public function resolveScope($entity, ?array $options = []) + { + return $this->scopeResolverDispatcher->resolveScope(); + } } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php new file mode 100644 index 000000000..c6cef7aa0 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php @@ -0,0 +1,35 @@ +createQueryBuilder(); + $qb + ->from(Person::class, 'p') + ; + + if (null === $this->nbOfPersons) { + $this->nbOfPersons = $qb + ->select('COUNT(p)') + ->getQuery() + ->getSingleScalarResult() + ; + } + + return $qb + ->select('p') + ->setMaxResults(1) + ->setFirstResult(\random_int(0, $this->nbOfPersons)) + ->getQuery() + ->getSingleResult() + ; + } +} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig index d2ed09135..1bf08602a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig @@ -149,9 +149,17 @@ {% endif %} {% if options['addCenter'] and person|chill_resolve_center is not null %} + {% if person|chill_resolve_center is iterable %} + {% set centers = person|chill_resolve_center %} + {% else %} + {% set centers = [ person|chill_resolve_center ] %} + {% endif %}
  • - {{ person|chill_resolve_center.name }} + {% for c in centers %} + {{ c.name|upper }} + {% if not loop.last %}, {% endif %} + {% endfor %}
  • {% endif %} diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index d8944ae93..d10f18c4c 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -2,9 +2,7 @@ namespace Chill\TaskBundle\Controller; -use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; -use Chill\MainBundle\Security\Resolver\CenterResolverInterface; use Chill\MainBundle\Templating\Listing\FilterOrderHelper; use Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface; use Chill\PersonBundle\Privacy\PrivacyEvent; @@ -18,26 +16,16 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Chill\TaskBundle\Entity\SingleTask; use Chill\TaskBundle\Form\SingleTaskType; -use Chill\TaskBundle\Form\SingleTaskListType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormFactoryInterface; use Chill\TaskBundle\Security\Authorization\TaskVoter; use Symfony\Component\Security\Core\Role\Role; use Chill\MainBundle\Pagination\PaginatorFactory; -use Chill\TaskBundle\Repository\SingleTaskRepository; -use Chill\MainBundle\Entity\User; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Chill\PersonBundle\Repository\PersonRepository; use Chill\TaskBundle\Event\TaskEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Chill\TaskBundle\Event\UI\UIEvent; -use Chill\MainBundle\Repository\CenterRepository; use Chill\MainBundle\Timeline\TimelineBuilder; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; -use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface as TranslationTranslatorInterface; From 02f6a1d1101ca1cd78d11b970dec669f085f13c1 Mon Sep 17 00:00:00 2001 From: nobohan Date: Tue, 16 Nov 2021 17:35:58 +0100 Subject: [PATCH 03/37] user: add location to user entity --- src/Bundle/ChillMainBundle/Entity/User.php | 25 ++++++++++++++ .../migrations/Version20211116162847.php | 33 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/Bundle/ChillMainBundle/migrations/Version20211116162847.php diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index 2048667e1..2d87bcaf1 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -6,6 +6,7 @@ use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; use Chill\MainBundle\Entity\UserJob; +use Chill\MainBundle\Entity\Location; use Symfony\Component\Security\Core\User\AdvancedUserInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; @@ -138,6 +139,12 @@ class User implements AdvancedUserInterface { */ private ?UserJob $userJob = null; + /** + * @var Location|null + * @ORM\ManyToOne(targetEntity=Location::class) + */ + private ?Location $location = null; + /** * User constructor. */ @@ -485,4 +492,22 @@ class User implements AdvancedUserInterface { $this->userJob = $userJob; return $this; } + + /** + * @return Location|null + */ + public function getLocation(): ?Location + { + return $this->location; + } + + /** + * @param Location|null $location + * @return User + */ + public function setLocation(?Location $location): User + { + $this->location = $location; + return $this; + } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php b/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php new file mode 100644 index 000000000..3971841c7 --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE users ADD location_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE users ADD CONSTRAINT FK_1483A5E964D218E FOREIGN KEY (location_id) REFERENCES chill_main_location (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_1483A5E964D218E ON users (location_id)'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E964D218E'); + $this->addSql('DROP INDEX IDX_1483A5E964D218E'); + $this->addSql('ALTER TABLE users DROP location_id'); + } +} From 32c7695d80bdee6c6c0a14638fc8bf26a1a98001 Mon Sep 17 00:00:00 2001 From: nobohan Date: Tue, 16 Nov 2021 17:51:05 +0100 Subject: [PATCH 04/37] user: correct property name --- src/Bundle/ChillMainBundle/Entity/User.php | 10 +++++----- .../migrations/Version20211116162847.php | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index 2d87bcaf1..c6fd42859 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -143,7 +143,7 @@ class User implements AdvancedUserInterface { * @var Location|null * @ORM\ManyToOne(targetEntity=Location::class) */ - private ?Location $location = null; + private ?Location $currentLocation = null; /** * User constructor. @@ -496,18 +496,18 @@ class User implements AdvancedUserInterface { /** * @return Location|null */ - public function getLocation(): ?Location + public function getCurrentLocation(): ?Location { - return $this->location; + return $this->currentLocation; } /** * @param Location|null $location * @return User */ - public function setLocation(?Location $location): User + public function setCurrentLocation(?Location $currentLocation): User { - $this->location = $location; + $this->currentLocation = $currentLocation; return $this; } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php b/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php index 3971841c7..04680b381 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php @@ -8,26 +8,26 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; /** - * Add location to User entity + * Add current location to User entity */ final class Version20211116162847 extends AbstractMigration { public function getDescription(): string { - return 'Add location to User entity'; + return 'Add current location to User entity'; } public function up(Schema $schema): void { - $this->addSql('ALTER TABLE users ADD location_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE users ADD CONSTRAINT FK_1483A5E964D218E FOREIGN KEY (location_id) REFERENCES chill_main_location (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE INDEX IDX_1483A5E964D218E ON users (location_id)'); + $this->addSql('ALTER TABLE users ADD currentLocation_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE users ADD CONSTRAINT FK_1483A5E93C219753 FOREIGN KEY (currentLocation_id) REFERENCES chill_main_location (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_1483A5E93C219753 ON users (currentLocation_id)'); } public function down(Schema $schema): void { - $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E964D218E'); - $this->addSql('DROP INDEX IDX_1483A5E964D218E'); - $this->addSql('ALTER TABLE users DROP location_id'); + $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E93C219753'); + $this->addSql('DROP INDEX IDX_1483A5E93C219753'); + $this->addSql('ALTER TABLE users DROP currentLocation_id'); } } From 59050384257220e251cea4bcb38e2ed1b476e2c4 Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 17 Nov 2021 11:35:54 +0100 Subject: [PATCH 05/37] user: current location edit form and page --- .../Controller/UserController.php | 96 ++++++++++++++----- .../Form/UserCurrentLocationType.php | 23 +++++ .../User/edit_current_location.html.twig | 23 +++++ .../translations/messages.fr.yml | 4 + 4 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php create mode 100644 src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig diff --git a/src/Bundle/ChillMainBundle/Controller/UserController.php b/src/Bundle/ChillMainBundle/Controller/UserController.php index bb8203011..3e6bade41 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserController.php +++ b/src/Bundle/ChillMainBundle/Controller/UserController.php @@ -18,6 +18,7 @@ use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\UserType; use Chill\MainBundle\Entity\GroupCenter; use Chill\MainBundle\Form\Type\ComposedGroupCenterType; +use Chill\MainBundle\Form\UserCurrentLocationType; use Chill\MainBundle\Form\UserPasswordType; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; @@ -87,7 +88,7 @@ class UserController extends CRUDController [ 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($entity, $request)->createView(), 'delete_groupcenter_form' => array_map( - function(\Symfony\Component\Form\Form $form) { + function (\Symfony\Component\Form\Form $form) { return $form->createView(); }, iterator_to_array($this->getDeleteLinkGroupCenterByUser($entity, $request), true) @@ -145,11 +146,10 @@ class UserController extends CRUDController private function createEditPasswordForm(User $user) { return $this->createForm(UserPasswordType::class, null, array( - 'user' => $user - )) + 'user' => $user + )) ->add('submit', SubmitType::class, array('label' => 'Change password')) - ->remove('actual_password') - ; + ->remove('actual_password'); } /** @@ -167,7 +167,7 @@ class UserController extends CRUDController } $groupCenter = $em->getRepository('ChillMainBundle:GroupCenter') - ->find($gcid); + ->find($gcid); if (!$groupCenter) { throw $this->createNotFoundException('Unable to find groupCenter entity'); @@ -184,10 +184,9 @@ class UserController extends CRUDController $em->flush(); $this->addFlash('success', $this->get('translator') - ->trans('The permissions where removed.')); + ->trans('The permissions where removed.')); return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', array('id' => $uid))); - } /** @@ -209,24 +208,26 @@ class UserController extends CRUDController if ($form->isValid()) { $groupCenter = $this->getPersistedGroupCenter( - $form[self::FORM_GROUP_CENTER_COMPOSED]->getData()); + $form[self::FORM_GROUP_CENTER_COMPOSED]->getData() + ); $user->addGroupCenter($groupCenter); if ($this->validator->validate($user)->count() === 0) { $em->flush(); - $this->addFlash('success', $this->get('translator')->trans('The ' + $this->addFlash('success', $this->get('translator')->trans('The ' . 'permissions have been successfully added to the user')); - $returnPathParams = $request->query->has('returnPath') ? - ['returnPath' => $request->query->get('returnPath')] : []; - - return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', - \array_merge(['id' => $uid], $returnPathParams))); + $returnPathParams = $request->query->has('returnPath') ? + ['returnPath' => $request->query->get('returnPath')] : []; + return $this->redirect($this->generateUrl( + 'chill_crud_admin_user_edit', + \array_merge(['id' => $uid], $returnPathParams) + )); } - foreach($this->validator->validate($user) as $error) { + foreach ($this->validator->validate($user) as $error) { $this->addFlash('error', $error->getMessage()); } } @@ -236,7 +237,7 @@ class UserController extends CRUDController 'edit_form' => $this->createEditForm($user)->createView(), 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user, $request)->createView(), 'delete_groupcenter_form' => array_map( - static fn(Form $form) => $form->createView(), + static fn (Form $form) => $form->createView(), iterator_to_array($this->getDeleteLinkGroupCenterByUser($user, $request), true) ) ]); @@ -247,10 +248,10 @@ class UserController extends CRUDController $em = $this->getDoctrine()->getManager(); $groupCenterManaged = $em->getRepository('ChillMainBundle:GroupCenter') - ->findOneBy(array( - 'center' => $groupCenter->getCenter(), - 'permissionsGroup' => $groupCenter->getPermissionsGroup() - )); + ->findOneBy(array( + 'center' => $groupCenter->getCenter(), + 'permissionsGroup' => $groupCenter->getPermissionsGroup() + )); if (!$groupCenterManaged) { $em->persist($groupCenter); @@ -270,8 +271,10 @@ class UserController extends CRUDController $returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : []; return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_user_delete_groupcenter', - array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()]))) + ->setAction($this->generateUrl( + 'admin_user_delete_groupcenter', + array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()]) + )) ->setMethod('DELETE') ->add('submit', SubmitType::class, array('label' => 'Delete')) ->getForm(); @@ -285,8 +288,10 @@ class UserController extends CRUDController $returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : []; return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_user_add_groupcenter', - array_merge($returnPathParams, ['uid' => $user->getId()]))) + ->setAction($this->generateUrl( + 'admin_user_add_groupcenter', + array_merge($returnPathParams, ['uid' => $user->getId()]) + )) ->setMethod('POST') ->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class) ->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter')) @@ -299,4 +304,45 @@ class UserController extends CRUDController yield $groupCenter->getId() => $this->createDeleteLinkGroupCenterForm($user, $groupCenter, $request); } } + + + /** + * @param User $user + * @return \Symfony\Component\Form\Form + */ + private function createEditLocationForm() + { + return $this->createForm(UserCurrentLocationType::class) + ->add('submit', SubmitType::class, ['label' => 'Change current location']); + } + + /** + * Displays a form to edit the user current location. + * + * @Route("/{_locale}/main/user/{id}/current-location/edit", name="chill_main_user_currentlocation_edit") + */ + public function editCurrentLocationAction(User $user, Request $request) + { + $editForm = $this->createEditLocationForm(); + $editForm->handleRequest($request); + + if ($editForm->isSubmitted() && $editForm->isValid()) { + $currentLocation = $editForm->get('location')->getData(); + + $user->setCurrentLocation($currentLocation); + + $this->getDoctrine()->getManager()->flush(); + $this->addFlash('success', $this->get('translator')->trans('Current location successfully updated')); + + return $this->redirect( + $request->query->has('returnPath') ? $request->query->get('returnPath') : + $this->generateUrl('chill_main_homepage') + ); + } + + return $this->render('@ChillMain/User/edit_current_location.html.twig', [ + 'entity' => $user, + 'edit_form' => $editForm->createView() + ]); + } } diff --git a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php new file mode 100644 index 000000000..fa24d987e --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php @@ -0,0 +1,23 @@ +add('location', EntityType::class, [ + 'class' => Location::class, + 'choice_label' => function (Location $entity) { + return $entity->getName(); + }, + ]); + } +} diff --git a/src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig b/src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig new file mode 100644 index 000000000..aa1f248ef --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig @@ -0,0 +1,23 @@ +{% extends 'ChillMainBundle::layout.html.twig' %} + +{% block title %}{{ 'Edit my current location'|trans }}{% endblock %} + +{% block content -%} +

    {{ 'Edit my current location'|trans }}

    + + {{ form_start(edit_form) }} + {{ form_row(edit_form.location) }} + + + + {{ form_end(edit_form) }} +{% endblock %} diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 598edaec6..c3078938d 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -176,6 +176,10 @@ Flags: Drapeaux # admin section for users jobs User jobs: Métiers +# user page for current location +Edit my current location: Éditer ma localisation actuelle +Change current location: Changer ma localisation actuelle +Current location successfully updated: Localisation actuelle mise à jour #admin section for circles (old: scopes) List circles: Cercles From 480e02af01182a5384add71d236d771b07f85f37 Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 17 Nov 2021 13:54:32 +0100 Subject: [PATCH 06/37] user: add change location for user in user menu --- .../Controller/UserController.php | 27 +++++++------------ .../Form/UserCurrentLocationType.php | 2 +- .../User/edit_current_location.html.twig | 2 +- .../Routing/MenuBuilder/UserMenuBuilder.php | 21 ++++++++++----- .../translations/messages.fr.yml | 2 ++ 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/UserController.php b/src/Bundle/ChillMainBundle/Controller/UserController.php index 3e6bade41..722a1d04f 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserController.php +++ b/src/Bundle/ChillMainBundle/Controller/UserController.php @@ -305,29 +305,20 @@ class UserController extends CRUDController } } - - /** - * @param User $user - * @return \Symfony\Component\Form\Form - */ - private function createEditLocationForm() - { - return $this->createForm(UserCurrentLocationType::class) - ->add('submit', SubmitType::class, ['label' => 'Change current location']); - } - /** * Displays a form to edit the user current location. * - * @Route("/{_locale}/main/user/{id}/current-location/edit", name="chill_main_user_currentlocation_edit") + * @Route("/{_locale}/main/user/current-location/edit", name="chill_main_user_currentlocation_edit") */ - public function editCurrentLocationAction(User $user, Request $request) + public function editCurrentLocationAction(Request $request) { - $editForm = $this->createEditLocationForm(); - $editForm->handleRequest($request); + $user = $this->getUser(); + $form = $this->createForm(UserCurrentLocationType::class, $user) + ->add('submit', SubmitType::class, ['label' => 'Change current location']) + ->handleRequest($request); - if ($editForm->isSubmitted() && $editForm->isValid()) { - $currentLocation = $editForm->get('location')->getData(); + if ($form->isSubmitted() && $form->isValid()) { + $currentLocation = $form->get('currentLocation')->getData(); $user->setCurrentLocation($currentLocation); @@ -342,7 +333,7 @@ class UserController extends CRUDController return $this->render('@ChillMain/User/edit_current_location.html.twig', [ 'entity' => $user, - 'edit_form' => $editForm->createView() + 'edit_form' => $form->createView() ]); } } diff --git a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php index fa24d987e..23dc99696 100644 --- a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php +++ b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php @@ -13,7 +13,7 @@ class UserCurrentLocationType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('location', EntityType::class, [ + ->add('currentLocation', EntityType::class, [ 'class' => Location::class, 'choice_label' => function (Location $entity) { return $entity->getName(); diff --git a/src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig b/src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig index aa1f248ef..206c96642 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/User/edit_current_location.html.twig @@ -6,7 +6,7 @@

    {{ 'Edit my current location'|trans }}

    {{ form_start(edit_form) }} - {{ form_row(edit_form.location) }} + {{ form_row(edit_form.currentLocation) }}
    • diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php index 010f5609d..bbe160371 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php @@ -38,28 +38,37 @@ class UserMenuBuilder implements LocalMenuBuilderInterface { $this->tokenStorage = $tokenStorage; } - + public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters) { if ($this->tokenStorage->getToken()->getUser() instanceof User) { + $menu + ->addChild( + 'Change location', + ['route' => 'chill_main_user_currentlocation_edit'] + ) + ->setExtras([ + 'order' => 99999999997 + ]); $menu ->addChild( 'Change password', - [ 'route' => 'change_my_password'] + ['route' => 'change_my_password'] ) ->setExtras([ 'order' => 99999999998 ]); } - + $menu ->addChild( - 'Logout', + 'Logout', [ 'route' => 'logout' - ]) + ] + ) ->setExtras([ - 'order'=> 99999999999, + 'order' => 99999999999, 'icon' => 'power-off' ]); } diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index c3078938d..340cb0e29 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -177,8 +177,10 @@ Flags: Drapeaux User jobs: Métiers # user page for current location +Current location: Localisation actuelle Edit my current location: Éditer ma localisation actuelle Change current location: Changer ma localisation actuelle +Change location: Changer ma localisation Current location successfully updated: Localisation actuelle mise à jour #admin section for circles (old: scopes) From 593817f12e15c27eaa1c4b76b0aaeeb9ff631226 Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 17 Nov 2021 14:12:22 +0100 Subject: [PATCH 07/37] user: refine display of location name (as usual, service injection does not work) --- .../Form/UserCurrentLocationType.php | 17 ++++++++++++++++- .../ChillMainBundle/config/services/form.yaml | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php index 23dc99696..607b9c31e 100644 --- a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php +++ b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php @@ -3,6 +3,7 @@ namespace Chill\MainBundle\Form; use Chill\MainBundle\Entity\Location; +// use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -10,13 +11,27 @@ use Symfony\Component\Form\FormBuilderInterface; class UserCurrentLocationType extends AbstractType { + + // private TranslatableStringHelper $translatableStringHelper; + + // /** + // * @param TranslatableStringHelper $translatableStringHelper + // */ + // public function __construct(TranslatableStringHelper $translatableStringHelper) + // { + // $this->translatableStringHelper = $translatableStringHelper; + // } + public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('currentLocation', EntityType::class, [ 'class' => Location::class, 'choice_label' => function (Location $entity) { - return $entity->getName(); + return $entity->getName() ? + $entity->getName() : + //$this->translatableStringHelper->localize($entity->getLocationType()->getTitle()); //TODO does not work + $entity->getLocationType()->getTitle()['fr']; }, ]); } diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml index 27d018229..b20f9e226 100644 --- a/src/Bundle/ChillMainBundle/config/services/form.yaml +++ b/src/Bundle/ChillMainBundle/config/services/form.yaml @@ -141,5 +141,9 @@ services: autowire: true Chill\MainBundle\Form\Type\LocationFormType: + autowire: true + autoconfigure: true + + Chill\MainBundle\Form\Type\UserCurrentLocationType: autowire: true autoconfigure: true \ No newline at end of file From f0ff4c18afed77b9e809174676302e205b730726 Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 17 Nov 2021 14:20:18 +0100 Subject: [PATCH 08/37] upd CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc54473f..7487fe9d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to +* [main] Add currentLocation to the User entity + add a page for selecting this location + add in the user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/133) +* [activity] + * [main] fix adding multiple AddresseDeRelais (combine PickAddressType with ChillCollection) * [person]: do not suggest the current household of the person (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/51) * [person]: display other phone numbers in view + add message in case no others phone numbers (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/184) From cd4de2e2443772d0104a83b08309377688e621b9 Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 17 Nov 2021 15:19:24 +0100 Subject: [PATCH 09/37] activity: fix type error + add new property for new form --- .../Controller/ActivityController.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index 9b1f3f48a..36dd609f3 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -266,16 +266,19 @@ final class ActivityController extends AbstractController $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); + $defaultLocationId = $this->getUser()->getCurrentLocation()->getId(); + return $this->render($view, [ 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, 'entity' => $entity, 'form' => $form->createView(), - 'activity_json' => $activity_array + 'activity_json' => $activity_array, + 'default_location_id' => $defaultLocationId ]); } - public function showAction(Request $request, $id): Response + public function showAction(Request $request, int $id): Response { $view = null; $em = $this->getDoctrine()->getManager(); @@ -330,7 +333,7 @@ final class ActivityController extends AbstractController * Displays a form to edit an existing Activity entity. * */ - public function editAction($id, Request $request): Response + public function editAction(int $id, Request $request): Response { $view = null; $em = $this->getDoctrine()->getManager(); From 63e5220084da6bdac54c6dff1d3d031e1188e20d Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 17 Nov 2021 15:21:53 +0100 Subject: [PATCH 10/37] activity: add user current location as default for a new activity --- .../vuejs/Activity/components/Location.vue | 17 +++++++++-------- .../Activity/newAccompanyingCourse.html.twig | 1 + .../Form/UserCurrentLocationType.php | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue index c8d1472bd..5fa3360b7 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue @@ -55,16 +55,17 @@ export default { } }, mounted() { - this.getLocationsList(); + getLocations().then(response => new Promise(resolve => { + console.log('getLocations', response); + this.locations = response.results; + if (window.default_location_id) { + let location = this.locations.filter(l => l.id === window.default_location_id); + this.$store.dispatch('updateLocation', location); + } + resolve(); + })) }, methods: { - getLocationsList() { - getLocations().then(response => new Promise(resolve => { - console.log('getLocations', response); - this.locations = response.results; - resolve(); - })) - }, customLabel(value) { return `${value.locationType.title.fr} ${value.name ? value.name : ''}`; } diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig index 101ad5502..d8f02a37d 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig @@ -22,6 +22,7 @@ '{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}'); }); window.activity = {{ activity_json|json_encode|raw }}; + window.default_location_id = {{ default_location_id }}; {{ encore_entry_script_tags('vue_activity') }} {% endblock %} diff --git a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php index 607b9c31e..6d3d5f6df 100644 --- a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php +++ b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php @@ -29,7 +29,7 @@ class UserCurrentLocationType extends AbstractType 'class' => Location::class, 'choice_label' => function (Location $entity) { return $entity->getName() ? - $entity->getName() : + $entity->getLocationType()->getTitle()['fr'] . ' ' . $entity->getName() : //$this->translatableStringHelper->localize($entity->getLocationType()->getTitle()); //TODO does not work $entity->getLocationType()->getTitle()['fr']; }, From 11b82f746830f3cc84335563682a14bfea241431 Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 17 Nov 2021 15:22:55 +0100 Subject: [PATCH 11/37] upd CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7487fe9d1..840b8e4f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to * [main] Add currentLocation to the User entity + add a page for selecting this location + add in the user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/133) -* [activity] +* [activity] add user current location as default location for a new activity (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/133) * [main] fix adding multiple AddresseDeRelais (combine PickAddressType with ChillCollection) * [person]: do not suggest the current household of the person (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/51) From 0e98010d0ebcaa55067f0a21b99951c6326917c3 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 17 Nov 2021 16:05:30 +0100 Subject: [PATCH 12/37] #101 improve translations + hide title --- .../Resources/public/vuejs/AccompanyingCourse/js/i18n.js | 2 +- .../views/AccompanyingCourse/_join_household.html.twig | 2 +- .../views/AccompanyingCourse/_warning_address.html.twig | 2 +- .../Resources/views/AccompanyingCourse/index.html.twig | 5 ++--- .../list_recent_by_accompanying_period.html.twig | 7 ------- .../translations/messages+intl-icu.fr.yaml | 6 +++--- src/Bundle/ChillPersonBundle/translations/messages.fr.yml | 1 + 7 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js index 10b656e4a..f5e38fefc 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js @@ -52,7 +52,7 @@ const appMessages = { show_household_number: "Voir le ménage (n° {id})", show_household: "Voir le ménage", person_without_household_warning: "Certaines usagers n'appartiennent actuellement à aucun ménage. Renseignez leur appartenance dès que possible.", - update_household: "Modifier l'appartenance", + update_household: "Renseigner l'appartenance", participation_not_valid: "Sélectionnez ou créez au minimum 1 usager", }, requestor: { diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_join_household.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_join_household.html.twig index 7ef2de466..fda36da85 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_join_household.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_join_household.html.twig @@ -6,7 +6,7 @@ - Corriger + {{ 'fix it'|trans }}
    diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig index f04a8a376..2febc7967 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig @@ -8,7 +8,7 @@ - Corriger + {{ 'fix it'|trans }} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig index 612c3a46b..1c9814a10 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig @@ -83,7 +83,7 @@ @@ -101,8 +101,7 @@ {% set accompanying_course_id = accompanyingCourse.id %} {% endif %} -

    {{ 'Last activities' |trans }}

    - +

    {{ 'Last activities' |trans }}

    {% include 'ChillActivityBundle:Activity:list_recent.html.twig' with { 'context': 'accompanyingCourse', 'no_action': true } %} {% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/list_recent_by_accompanying_period.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/list_recent_by_accompanying_period.html.twig index 61f48aa76..979488ff3 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/list_recent_by_accompanying_period.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/list_recent_by_accompanying_period.html.twig @@ -1,10 +1,3 @@ - {% if works|length == 0 %} -

    {{ 'accompanying_course_work.Any work'|trans }} - {# TODO link #} -

    - {% endif %} -
    {% for w in works | slice(0,5) %} diff --git a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml index e815153c8..43f83059b 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml +++ b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml @@ -16,7 +16,7 @@ household: Household: Ménage Household number: Ménage {household_num} Household members: Membres du ménage - Household editor: Modifier l'appartenance + Household editor: Renseigner l'appartenance Members at same time: Membres simultanés Any simultaneous members: Aucun membre simultanément Select people to move: Choisir les usagers @@ -51,7 +51,7 @@ household: is holder: Est titulaire is not holder: N'est pas titulaire holder: Titulaire - Edit member household: Modifier l'appartenance au ménage + Edit member household: Renseigner l'appartenance au ménage Edit his household: Modifier son appartenance au ménage Current household members: Membres actuels Household summary: Résumé du ménage @@ -61,7 +61,7 @@ household: Household relationships: Filiations dans le ménage Current address: Adresse actuelle Household does not have any address currently: Le ménage n'a pas d'adresse renseignée actuellement - Edit household members: Modifier l'appartenance au ménage + Edit household members: Renseigner l'appartenance au ménage and x other persons: >- {x, plural, one {et une autre personne} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 7f9527b91..09ca5bb81 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -390,6 +390,7 @@ This course has a temporarily location: Localisation temporaire Choose a person to locate by: Localiser auprès d'un usager concerné Associate at least one member with an household, and set an address to this household: Associez au moins un membre du parcours à un ménage, et indiquez une adresse à ce ménage. Locate by: Localiser auprès de +fix it: Compléter # Household Household: Ménage From 2492a9281f0943b7ea14c42fa5513b251a49abb0 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 17 Nov 2021 16:06:55 +0100 Subject: [PATCH 13/37] improve household button in course participation --- .../PersonsAssociated/ParticipationItem.vue | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/PersonsAssociated/ParticipationItem.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/PersonsAssociated/ParticipationItem.vue index fd3f59cef..a9138e0b3 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/PersonsAssociated/ParticipationItem.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/PersonsAssociated/ParticipationItem.vue @@ -5,7 +5,7 @@ addId : false, addEntity: false, addLink: false, - addHouseholdLink: true, + addHouseholdLink: false, addAltNames: true, addAge : true, hLevel : 3, @@ -20,14 +20,15 @@ v-if="hasCurrentHouseholdAddress" v-bind:person="participation.person"> +
  • + + + +
  • -
  • -
      +
      • - {{ p.text }} + + + {{ p.text }} +
    diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups/PersonBadge.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups/PersonBadge.vue index bef11159c..0b2dd6613 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups/PersonBadge.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups/PersonBadge.vue @@ -4,7 +4,7 @@ {{ textCutted }} - diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig index e11ab863b..a30034257 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig @@ -55,7 +55,7 @@ {% endif %}

    {{ 'Concerned groups'|trans }}

    -{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'bloc' } %} +{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'bloc', 'badge_person': 'true' } %}

    {{ 'Activity data'|trans }}

    From a6001961519d2b3660969f79836eeef82a2842fc Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Thu, 18 Nov 2021 16:25:36 +0100 Subject: [PATCH 17/37] vue_accourse referrer: style for suggestions, add and remove items --- .../AccompanyingCourse/components/Referrer.vue | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue index c39e043c6..b67bbc038 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue @@ -19,16 +19,16 @@ @select="updateReferrer"> - - -
    From aba47600ff2501b54aa8a0bbf30784a334b5db27 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Thu, 18 Nov 2021 17:56:46 +0100 Subject: [PATCH 18/37] hop --- .../Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue index 5bb52358b..b3ddffbd7 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue @@ -119,9 +119,9 @@

    {{ $t('persons_involved') }}

    -
    + + diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig index e55b39f64..2f1e75a7f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig @@ -23,11 +23,28 @@
    -
    +
    - {# vue teleport fragment here #} - +
    + +
    diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig index 1c9814a10..434a87759 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig @@ -23,32 +23,6 @@ {% block content %}
    -
    - {% for h in participationsByHousehold %} - {% set householdClass = (h.household is not null) ? 'household-' ~ h.household.id : 'no-household alert alert-warning' %} - {% set householdTitle = (h.household is not null) ? - 'household.Household number'|trans({'household_num': h.household.id }) : 'household.Never in any household'|trans %} - - {% if h.household is not null %} - - {% endif %} - {% for p in h.members %} - - {# include vue_onthefly component #} - {% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with { - targetEntity: { name: 'person', id: p.person.id }, - action: 'show', - displayBadge: true, - buttonText: p.person|chill_entity_render_string - } %} - - {% endfor %} - - {% endfor %} -
    - {% if 'DRAFT' == accompanyingCourse.step %}
    {% include '@ChillPerson/AccompanyingCourse/_still_draft.html.twig' %} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 09ca5bb81..5054a3922 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -430,3 +430,5 @@ accompanying_course_work: Person addresses: Adresses de résidence Household addresses: Adresses de domicile Insert an address: Insérer une adresse +see social issues: Voir les problématiques sociales +see persons associated: Voir les usagers concernés From 31ec15507025825c29aba4f3fb8c3720f2bffd83 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 19 Nov 2021 17:27:53 +0100 Subject: [PATCH 22/37] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31c3e1b5d..48ac6aa2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to * [person] do not ask for center any more on person creation * [3party] do not ask for center any more on 3party creation * [task] Select2 field in task form to allow search for a user (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/167) +* [accompanying course] Add associated persons in banner details. social-issues and associated-persons are slides in same space. ## Test releases From fec852b0447aefebb55b3f07cd808d6b8d23ad0b Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 19 Nov 2021 18:25:07 +0100 Subject: [PATCH 23/37] carousel: fix span household position --- .../AccompanyingCourse/components/Banner/PersonsAssociated.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue index 1e6eeb9fa..005350b96 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue @@ -65,6 +65,7 @@ export default {