diff --git a/.env b/.env deleted file mode 100644 index 619f471ca..000000000 --- a/.env +++ /dev/null @@ -1,64 +0,0 @@ -## -## Manually dump .env files in .env.local.php with -## `$ composer symfony:dump-env prod` -## - -## Project environment -APP_ENV=dev - -## Enable debug -APP_DEBUG=true - -## Locale -LOCALE=fr - -## Framework secret -APP_SECRET=ThisTokenIsNotSoSecretChangeIt - -## Symfony/swiftmailer -MAILER_TRANSPORT=smtp -MAILER_HOST=smtp -MAILER_PORT=1025 -MAILER_CRYPT= -MAILER_AUTH= -MAILER_USER= -MAILER_PASSWORD= -MAILER_URL=${MAILER_TRANSPORT}://${MAILER_HOST}:${MAILER_PORT}?encryption=${MAILER_CRYPT}&auth_mode=${MAILER_AUTH}&username=${MAILER_USER}&password=${MAILER_PASSWORD} - -## Notifications -NOTIFICATION_HOST=localhost:8001 -NOTIFICATION_FROM_EMAIL=admin@chill.social -NOTIFICATION_FROM_NAME=Chill - -## Gelf -GELF_HOST=gelf -GELF_PORT=12201 - -## OVH OpenStack Storage User/Role -OS_USERNAME= -OS_PASSWORD= -OS_TENANT_ID= -OS_REGION_NAME=GRA -OS_AUTH_URL=https://auth.cloud.ovh.net/v2.0/ - -## OVH OpenStack Storage Container -ASYNC_UPLOAD_TEMP_URL_KEY= -ASYNC_UPLOAD_TEMP_URL_BASE_PATH= -ASYNC_UPLOAD_TEMP_URL_CONTAINER= - -## Redis Cache -REDIS_HOST=redis -REDIS_PORT=6379 -REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT} - -## Twilio -TWILIO_SID=~ -TWILIO_SECRET=~ - -## DOCKER IMAGES REGISTRY -#IMAGE_PHP= -#IMAGE_NGINX= - -## DOCKER IMAGES VERSION -#VERSION=test -VERSION=prod diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b00be8bc..8e718317c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,27 @@ and this project adheres to ## Unreleased +* fix normalisation of accompanying course requestor api (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/378) +* [person] add a returnPath when clicking on some Person or ThirdParty badge (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/427) +* [person] accompanying course work: fix on-the-fly update of thirdParty +* [on-the-fly] close modal only after validation +* [person] correct thirdparty PATCH url + add email and altnames in AddPerson and serializer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/433) +* change order for accompanying course work list +* [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414) +* [person]: style fix in parcours listing per person. (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/432) +* [household]: display address of current household (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/415) +* ajoute un ordre dans les localisation (api) +* [pick entity]: fix translations in modal (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/419) +* [homepage_widget]: fix translation on emergency badge (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/440) +* [person]: create person and household added to button dropdown (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/454) +* display full address in address.text in normalization. Adapt AddressRenderBox +* [address]: Correction residential address 'depuis le' (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/459) +* [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414) + +## Test releases + +### test release 2021-02-01 + * renommer "dossier numéro" en "parcours numéro" dans les résultats de recherche * renomme date de début en date d'ouverture dans le formulaire parcours * [homepage widget] improve content tables, improve counter pluralization with style on number @@ -19,7 +40,7 @@ and this project adheres to * [parcours]: validation + message for closing parcours adjusted. * [household]: household composition double edit button replaced by a delete action (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/426) [fast_actions] improve fast-actions buttons override mechanism, fix https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/413 -[homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc. +[homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc. * [person]: Comment on marital status is possible even if marital status is not defined (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/421) * [parcours]: In the list of person results the requestor is not displayed if defined as anonymous (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/424) * [bugfix]: modal closes and newly created person/thirdparty is selected when multiple persons/thirdparties are created through the modal (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/429) @@ -27,10 +48,7 @@ and this project adheres to * [workflow][notification] improve how notifications and workflows are 'attached' to entities: contextual list, counter, buttons and vue modal * [AddAddress] disable multiselect search, and rely only on most pertinent Cities and Street computed backend * [fast_actions] improve fast-actions buttons override mechanism, fix https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/413 -* [homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc. - - -## Test releases +* [homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc. ### test release 2021-01-31 @@ -79,7 +97,7 @@ and this project adheres to * [popover] add popover html popup mechanism (used by workflow breadcrumb) * [templates] improve updatedBy macro in item metadatas * [parcours]: bug fix when comment is pinned all other comments remain in the collection (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/385) -* [workflow] +* [workflow] * add My workflow section with my opened subscriptions * apply workflow on documents, accompanyingCourseWork and Evaluations * [wopi-link] a new vue component allow to open wopi link in a fullscreen chill-themed modal diff --git a/phpstan-deprecations.neon b/phpstan-deprecations.neon index bc372e96b..7489d4d80 100644 --- a/phpstan-deprecations.neon +++ b/phpstan-deprecations.neon @@ -408,24 +408,6 @@ parameters: count: 1 path: src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php - - - message: - """ - #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: - Use getReachableCircles$# - """ - count: 1 - path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php - - - - message: - """ - #^Parameter \\$translator of method Chill\\\\DocStoreBundle\\\\Controller\\\\DocumentPersonController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: - since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# - """ - count: 1 - path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php - - message: """ @@ -927,15 +909,6 @@ parameters: count: 1 path: src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php - - - message: - """ - #^Parameter \\$trans of method Chill\\\\PersonBundle\\\\Controller\\\\AccompanyingCourseWorkController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: - since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# - """ - count: 1 - path: src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php - - message: """ diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index d46136173..3858979ef 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -220,7 +220,7 @@ final class ActivityController extends AbstractController $this->entityManager->persist($entity); $this->entityManager->flush(); - if ($form->has('gendocTemplateId') && '' !== $form['gendocTemplateId']) { + if ($form->has('gendocTemplateId') && null !== $form['gendocTemplateId']->getData()) { return $this->redirectToRoute( 'chill_docgenerator_generate_from_template', [ @@ -437,7 +437,7 @@ final class ActivityController extends AbstractController $this->entityManager->persist($entity); $this->entityManager->flush(); - if ($form->has('gendocTemplateId') && '' !== $form['gendocTemplateId']) { + if ($form->has('gendocTemplateId') && null !== $form['gendocTemplateId']->getData()) { return $this->redirectToRoute( 'chill_docgenerator_generate_from_template', [ diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/_list_item.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/_list_item.html.twig index fadf7ff14..3a4749f3c 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/_list_item.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/_list_item.html.twig @@ -68,7 +68,7 @@

{{ 'Referrer'|trans }}

- {{ activity.user|chill_entity_render_string|capitalize }} + {{ activity.user|chill_entity_render_box }}

diff --git a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php index 8966ecca8..05dc362b4 100644 --- a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php +++ b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php @@ -97,7 +97,6 @@ class CalendarType extends AbstractType return $res; }, static function (?string $dateAsString): DateTimeImmutable { - return new DateTimeImmutable($dateAsString); } )); diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php index a5ad5cfa1..199f88c60 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php @@ -13,7 +13,9 @@ namespace Chill\DocStoreBundle\Controller; use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument; use Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType; +use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository; use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\PersonBundle\Entity\AccompanyingPeriod; use DateTime; @@ -29,20 +31,15 @@ use Symfony\Contracts\Translation\TranslatorInterface; */ class DocumentAccompanyingCourseController extends AbstractController { - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; + protected AuthorizationHelper $authorizationHelper; - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; + protected EventDispatcherInterface $eventDispatcher; - /** - * @var TranslatorInterface - */ - protected $translator; + protected TranslatorInterface $translator; + + private AccompanyingCourseDocumentRepository $courseRepository; + + private PaginatorFactory $paginatorFactory; /** * DocumentAccompanyingCourseController constructor. @@ -50,11 +47,15 @@ class DocumentAccompanyingCourseController extends AbstractController public function __construct( TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher, - AuthorizationHelper $authorizationHelper + AuthorizationHelper $authorizationHelper, + PaginatorFactory $paginatorFactory, + AccompanyingCourseDocumentRepository $courseRepository ) { $this->translator = $translator; $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; + $this->paginatorFactory = $paginatorFactory; + $this->courseRepository = $courseRepository; } /** @@ -130,11 +131,15 @@ class DocumentAccompanyingCourseController extends AbstractController $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::SEE, $course); - $documents = $em - ->getRepository('ChillDocStoreBundle:AccompanyingCourseDocument') + $total = $this->courseRepository->countByCourse($course); + $pagination = $this->paginatorFactory->create($total); + + $documents = $this->courseRepository ->findBy( ['course' => $course], - ['date' => 'DESC'] + ['date' => 'DESC'], + $pagination->getItemsPerPage(), + $pagination->getCurrentPageFirstItemNumber() ); return $this->render( @@ -142,6 +147,7 @@ class DocumentAccompanyingCourseController extends AbstractController [ 'documents' => $documents, 'accompanyingCourse' => $course, + 'pagination' => $pagination, ] ); } diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php index 5028757bd..fcb3a4958 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php @@ -13,7 +13,8 @@ namespace Chill\DocStoreBundle\Controller; use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\DocStoreBundle\Form\PersonDocumentType; -use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; +use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Privacy\PrivacyEvent; @@ -24,7 +25,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * Class DocumentPersonController. @@ -35,20 +36,15 @@ use Symfony\Component\Translation\TranslatorInterface; */ class DocumentPersonController extends AbstractController { - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; + protected AuthorizationHelper $authorizationHelper; - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; + protected EventDispatcherInterface $eventDispatcher; - /** - * @var TranslatorInterface - */ - protected $translator; + protected TranslatorInterface $translator; + + private PaginatorFactory $paginatorFactory; + + private PersonDocumentACLAwareRepositoryInterface $personDocumentACLAwareRepository; /** * DocumentPersonController constructor. @@ -56,11 +52,15 @@ class DocumentPersonController extends AbstractController public function __construct( TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher, - AuthorizationHelper $authorizationHelper + AuthorizationHelper $authorizationHelper, + PaginatorFactory $paginatorFactory, + PersonDocumentACLAwareRepositoryInterface $personDocumentACLAwareRepository ) { $this->translator = $translator; $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; + $this->paginatorFactory = $paginatorFactory; + $this->personDocumentACLAwareRepository = $personDocumentACLAwareRepository; } /** @@ -156,19 +156,15 @@ class DocumentPersonController extends AbstractController $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); - $reachableScopes = $this->authorizationHelper - ->getReachableScopes( - $this->getUser(), - PersonDocumentVoter::SEE, - $person->getCenter() - ); + $total = $this->personDocumentACLAwareRepository->countByPerson($person); + $pagination = $this->paginatorFactory->create($total); - $documents = $em - ->getRepository('ChillDocStoreBundle:PersonDocument') - ->findBy( - ['person' => $person, 'scope' => $reachableScopes], - ['date' => 'DESC'] - ); + $documents = $this->personDocumentACLAwareRepository->findByPerson( + $person, + [], + $pagination->getItemsPerPage(), + $pagination->getCurrentPageFirstItemNumber() + ); $event = new PrivacyEvent($person, [ 'element_class' => PersonDocument::class, @@ -181,6 +177,7 @@ class DocumentPersonController extends AbstractController [ 'documents' => $documents, 'person' => $person, + 'pagination' => $pagination, ] ); } diff --git a/src/Bundle/ChillDocStoreBundle/Entity/Document.php b/src/Bundle/ChillDocStoreBundle/Entity/Document.php index 874a60f0b..e26469573 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/Document.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/Document.php @@ -11,7 +11,13 @@ declare(strict_types=1); namespace Chill\DocStoreBundle\Entity; +use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; +use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; +use Chill\MainBundle\Doctrine\Model\TrackCreationTrait; +use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; +use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait; use Chill\MainBundle\Entity\HasScopeInterface; +use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use DateTimeInterface; use Doctrine\ORM\Mapping as ORM; @@ -20,8 +26,12 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\MappedSuperclass */ -class Document implements HasScopeInterface +class Document implements HasScopeInterface, TrackCreationInterface, TrackUpdateInterface { + use TrackCreationTrait; + + use TrackUpdateTrait; + /** * @ORM\ManyToOne(targetEntity="Chill\DocStoreBundle\Entity\DocumentCategory") * @ORM\JoinColumns({ @@ -67,6 +77,11 @@ class Document implements HasScopeInterface */ private $scope; + /** + * @ORM\ManyToOne(targetEntity="Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate") + */ + private $template; + /** * @ORM\Column(type="text") * @Assert\Length( @@ -82,9 +97,6 @@ class Document implements HasScopeInterface */ private $user; - /** - * @return DocumentCategory - */ public function getCategory(): ?DocumentCategory { return $this->category; @@ -115,11 +127,16 @@ class Document implements HasScopeInterface * * @return \Chill\MainBundle\Entity\Scope */ - public function getScope() + public function getScope(): ?Scope { return $this->scope; } + public function getTemplate(): ?DocGeneratorTemplate + { + return $this->template; + } + public function getTitle(): ?string { return $this->title; @@ -165,6 +182,13 @@ class Document implements HasScopeInterface return $this; } + public function setTemplate(?DocGeneratorTemplate $template): self + { + $this->template = $template; + + return $this; + } + public function setTitle(string $title): self { $this->title = $title; diff --git a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php index 86e8d350a..bcbd4d707 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php @@ -18,10 +18,12 @@ use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillTextareaType; use Chill\MainBundle\Form\Type\ScopePickerType; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\EntityRepository; use Doctrine\Persistence\ObjectManager; use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; @@ -51,14 +53,25 @@ class PersonDocumentType extends AbstractType */ protected $user; + private ParameterBagInterface $parameterBag; + + private ScopeResolverDispatcher $scopeResolverDispatcher; + public function __construct( - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelper $translatableStringHelper, + ScopeResolverDispatcher $scopeResolverDispatcher, + ParameterBagInterface $parameterBag ) { $this->translatableStringHelper = $translatableStringHelper; + $this->scopeResolverDispatcher = $scopeResolverDispatcher; + $this->parameterBag = $parameterBag; } public function buildForm(FormBuilderInterface $builder, array $options) { + $document = $options['data']; + $isScopeConcerned = $this->scopeResolverDispatcher->isConcerned($document); + $builder ->add('title', TextType::class) ->add('description', ChillTextareaType::class, [ @@ -67,10 +80,6 @@ class PersonDocumentType extends AbstractType ->add('object', StoredObjectType::class, [ 'error_bubbling' => true, ]) - ->add('scope', ScopePickerType::class, [ - 'center' => $options['center'], - 'role' => $options['role'], - ]) ->add('date', ChillDateType::class) ->add('category', EntityType::class, [ 'placeholder' => 'Choose a document category', @@ -84,6 +93,13 @@ class PersonDocumentType extends AbstractType return $entity ? $this->translatableStringHelper->localize($entity->getName()) : ''; }, ]); + + if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) { + $builder->add('scope', ScopePickerType::class, [ + 'center' => $options['center'], + 'role' => $options['role'], + ]); + } } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillDocStoreBundle/Repository/AccompanyingCourseDocumentRepository.php b/src/Bundle/ChillDocStoreBundle/Repository/AccompanyingCourseDocumentRepository.php new file mode 100644 index 000000000..57c898b68 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Repository/AccompanyingCourseDocumentRepository.php @@ -0,0 +1,75 @@ +em = $em; + $this->repository = $em->getRepository(AccompanyingCourseDocument::class); + } + + public function buildQueryByCourse(AccompanyingPeriod $course): QueryBuilder + { + $qb = $this->repository->createQueryBuilder('d'); + + $qb + ->where($qb->expr()->eq('d.course', ':course')) + ->setParameter('course', $course); + + return $qb; + } + + public function countByCourse(AccompanyingPeriod $course): int + { + $qb = $this->buildQueryByCourse($course)->select('COUNT(d)'); + + return $qb->getQuery()->getSingleScalarResult(); + } + + public function find($id): ?AccompanyingCourseDocument + { + return $this->repository->find($id); + } + + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?AccompanyingCourseDocument + { + return $this->findOneBy($criteria); + } + + public function getClassName() + { + return AccompanyingCourseDocument::class; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php new file mode 100644 index 000000000..0f85a74b2 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php @@ -0,0 +1,90 @@ +em = $em; + $this->authorizationHelper = $authorizationHelper; + $this->centerResolverDispatcher = $centerResolverDispatcher; + $this->security = $security; + } + + public function buildQueryByPerson(Person $person): QueryBuilder + { + $qb = $this->em->getRepository(PersonDocument::class)->createQueryBuilder('d'); + + $qb + ->where($qb->expr()->eq('d.person', ':person')) + ->setParameter('person', $person); + + return $qb; + } + + public function countByPerson(Person $person): int + { + $qb = $this->buildQueryByPerson($person)->select('COUNT(d)'); + + $this->addACL($qb, $person); + + return $qb->getQuery()->getSingleScalarResult(); + } + + public function findByPerson(Person $person, array $orderBy = [], int $limit = 20, int $offset = 0): array + { + $qb = $this->buildQueryByPerson($person)->select('d'); + + $this->addACL($qb, $person); + + foreach ($orderBy as [$field, $order]) { + $qb->addOrderBy($field, $order); + } + + $qb->setFirstResult($offset)->setMaxResults($limit); + + return $qb->getQuery()->getResult(); + } + + private function addACL(QueryBuilder $qb, Person $person): void + { + $center = $this->centerResolverDispatcher->resolveCenter($person); + + $reachableScopes = $this->authorizationHelper + ->getReachableScopes( + $this->security->getUser(), + PersonDocumentVoter::SEE, + $center + ); + + $qb->andWhere($qb->expr()->in('d.scope', ':scopes')) + ->setParameter('scopes', $reachableScopes); + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepositoryInterface.php b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepositoryInterface.php new file mode 100644 index 000000000..85b0288c0 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepositoryInterface.php @@ -0,0 +1,21 @@ +

{{ document.title }}

- + {{ mm.mimeIcon(document.object.type) }} - + {% if document.description is not empty %}
{{ document.description }}
{% endif %} - +
@@ -34,6 +34,13 @@ {% if display_action is defined and display_action == true %} -{% endif %} \ No newline at end of file +{% endif %} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig index 1a635cd4a..0d4a7d637 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig @@ -2,8 +2,6 @@ {% set activeRouteKey = '' %} -{% import "@ChillDocStore/Macro/macro.html.twig" as m %} - {% block title %} {{ 'Documents' }} {% endblock %} @@ -21,51 +19,22 @@ {% endblock %} {% block content %} +

{{ 'Documents' }}

- - - - - - - - - - + {% if documents|length == 0 %} +

{{ 'No documents'|trans }}

+ {% else %} +
{% for document in documents %} -
- - - - - {% else %} - - - + {% include 'ChillDocStoreBundle:List:list_item.html.twig' %} {% endfor %} - -
{{ 'Title' | trans }}{{ 'Category'|trans }}{{ 'Actions' | trans }}
{{ document.title }}{% if document.category %}{{ document.category.name|localize_translatable_string }}{% endif %} -
    - {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %} -
  • - {{ m.download_button(document.object, document.title) }} -
  • -
  • - -
  • - {% endif %} - {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %} -
  • - -
  • - {% endif %} -
-
- {{ 'Any document found'|trans }} -
+
+ {% endif %} -
+ {{ chill_pagination(pagination) }} + +
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', accompanyingCourse) %} {% endif %} + + {% endblock %} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig new file mode 100644 index 000000000..45ebf2799 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig @@ -0,0 +1,80 @@ +{% import "@ChillDocStore/Macro/macro.html.twig" as m %} + +
+
+
+
+ {{ document.title }} +
+
+

{{ document.category.name|localize_translatable_string }}

+
+ {% if document.template is not null %} +
+

{{ document.template.name.fr }}

+
+ {% endif %} +
+ +
+
+ {% if document.date is not null %} +
+ {{ document.createdAt|format_date('short') }} +
+ {% endif %} +
+
+
+ {% if document.description is not empty %} +
+
+ {{ document.description|chill_markdown_to_html }} +
+
+ {% endif %} +
+
+
+ {{ 'Created by'|trans }}: + {{ document.createdBy|chill_entity_render_string }} + le {{ document.createdAt|format_date('long') }} +
+
+
+
+ {% if document.course is defined %} + + {% else %} + + {% endif %} +
+
diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig index bf3dcd407..7533f1120 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig @@ -30,7 +30,9 @@ {{ form_row(form.title) }} {{ form_row(form.date) }} {{ form_row(form.category) }} - {{ form_row(form.scope) }} + {% if form.scope is defined %} + {{ form_row(form.scope) }} + {% endif %} {{ form_row(form.description) }} {{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/index.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/index.html.twig index 40c85002e..b3d2baab6 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/index.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/index.html.twig @@ -30,54 +30,24 @@ {% endblock %} {% block personcontent %} + +

{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}

- - - - - - - - - - - + {% if documents|length == 0 %} +

{{ 'No documents'|trans }}

+ {% else %} +
{% for document in documents %} -
- - - - - - {% else %} - - - + {% include 'ChillDocStoreBundle:List:list_item.html.twig' %} {% endfor %} - -
{{ 'Title' | trans }}{{ 'Category'|trans }}{{ 'Circle' | trans }}{{ 'Actions' | trans }}
{{ document.title }}{{ document.category.name|localize_translatable_string }}{{ document.scope.name|localize_translatable_string }} -
    - {% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %} -
  • - {{ m.download_button(document.object, document.title) }} -
  • -
  • - -
  • - {% endif %} - {% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %} -
  • - -
  • - {% endif %} -
-
- {{ 'Any document found'|trans }} -
+
+ {% endif %} + + {{ chill_pagination(pagination) }} {% if is_granted('CHILL_PERSON_DOCUMENT_CREATE', person) %} -