From fad1821c2f34b007a29a45d52722ed69f48b22e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 5 Oct 2018 11:01:00 +0200 Subject: [PATCH 1/6] fix translation in exports / aggregator. The activity type aggregator is shown. --- CHANGELOG.md | 6 +++++ Export/Aggregator/ActivityTypeAggregator.php | 26 -------------------- Export/Export/CountActivity.php | 4 +-- Resources/translations/messages.fr.yml | 5 +++- 4 files changed, 11 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88a7e4351..1da0df3a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,3 +4,9 @@ Version 1.5.1 - [report activity count] fix error: do not show centers which are not selected in results. +Master branch +============= + +- [aggregate by activity type] fix translation in aggregate activity type +- fix some translation in export +- fix error when persons not loaded by other aggregators / filters diff --git a/Export/Aggregator/ActivityTypeAggregator.php b/Export/Aggregator/ActivityTypeAggregator.php index 544ae98ac..3dec544ba 100644 --- a/Export/Aggregator/ActivityTypeAggregator.php +++ b/Export/Aggregator/ActivityTypeAggregator.php @@ -63,32 +63,6 @@ class ActivityTypeAggregator implements AggregatorInterface // add select element $qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY)); - // make a jointure only if needed - /*$join = $qb->getDQLPart('join'); - if ( - (array_key_exists('activity', $join) - && - !$this->checkJoinAlreadyDefined($join['activity'], 'reasons') - ) - OR - (! array_key_exists('activity', $join)) - ) { - $qb->add( - 'join', - array('activity' => - new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') - ), - true); - } - - // join category if necessary - if ($alias === 'activity_categories_id') { - // add join only if needed - if (!$this->checkJoinAlreadyDefined($qb->getDQLPart('join')['activity'], 'category')) { - $qb->join('reasons.category', 'category'); - } - }*/ - // add the "group by" part $groupBy = $qb->addGroupBy(self::KEY); } diff --git a/Export/Export/CountActivity.php b/Export/Export/CountActivity.php index 00f741fce..97a837520 100644 --- a/Export/Export/CountActivity.php +++ b/Export/Export/CountActivity.php @@ -75,9 +75,7 @@ class CountActivity implements ExportInterface ->from('ChillActivityBundle:Activity', 'activity') ; - if (in_array('person', $requiredModifiers)) { - $qb->join('activity.person', 'person'); - } + $qb->join('activity.person', 'person'); $qb->where($qb->expr()->in('person.center', ':centers')) ->setParameter('centers', $centers) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 63620fb49..55e367d32 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -114,6 +114,7 @@ Count activities by various parameters.: Compte le nombre d'activités enregistr Sum activity duration: Total de la durée des activités Sum activities duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres. List activities: Liste les activités +Number of activities: Nombre d'activités #filters Filter by reason: Filtrer par sujet d'activité @@ -137,5 +138,7 @@ Aggregate by activity reason: Aggréger par sujet de l'activité By reason: Par sujet By category of reason: Par catégorie de sujet Reason's level: Niveau du sujet -Aggregate by activity type: Aggréger par date d'activité +Aggregate by activity type: Aggréger par type d'activité +Activity type: Type d'activité +Group by reasons: Sujet d'activité From 5959edb01a4fa406fbda683340bc580d3e867d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 5 Oct 2018 11:21:45 +0200 Subject: [PATCH 2/6] [export] add filter "filter activity by activity type" --- CHANGELOG.md | 2 + Export/Filter/ActivityTypeFilter.php | 148 +++++++++++++++++++++++++ Resources/config/services/export.yml | 8 ++ Resources/translations/messages.fr.yml | 3 +- 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 Export/Filter/ActivityTypeFilter.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da0df3a3..16ac704c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,5 @@ Master branch - [aggregate by activity type] fix translation in aggregate activity type - fix some translation in export - fix error when persons not loaded by other aggregators / filters +- add "filter by activity type" filter + diff --git a/Export/Filter/ActivityTypeFilter.php b/Export/Filter/ActivityTypeFilter.php new file mode 100644 index 000000000..b3616da10 --- /dev/null +++ b/Export/Filter/ActivityTypeFilter.php @@ -0,0 +1,148 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\ActivityBundle\Export\Filter; + +use Chill\MainBundle\Export\FilterInterface; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\Query\Expr; +use Symfony\Component\Security\Core\Role\Role; +use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Query\Expr\Join; +use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Chill\MainBundle\Export\ExportElementValidatedInterface; +use Chill\ActivityBundle\Entity\ActivityType; + +/** + * + * + */ +class ActivityTypeFilter implements FilterInterface, + ExportElementValidatedInterface +{ + /** + * + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** + * The repository for activity reasons + * + * @var EntityRepository + */ + protected $typeRepository; + + public function __construct( + TranslatableStringHelper $helper, + EntityRepository $typeRepository + ) { + $this->translatableStringHelper = $helper; + $this->typeRepository = $typeRepository; + } + + + public function alterQuery(QueryBuilder $qb, $data) + { + $where = $qb->getDQLPart('where'); + $clause = $qb->expr()->in('activity.type', ':selected_activity_types'); + + if ($where instanceof Expr\Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->add('where', $where); + $qb->setParameter('selected_activity_types', $data['types']); + } + + /** + * Check if a join between Activity and Reason is already defined + * + * @param Join[] $joins + * @return boolean + */ + private function checkJoinAlreadyDefined(array $joins, $alias) + { + foreach ($joins as $join) { + if ($join->getAlias() === $alias) { + return true; + } + } + + return false; + } + + public function applyOn() + { + return 'activity'; + } + + public function buildForm(FormBuilderInterface $builder) + { + //create a local copy of translatableStringHelper + $helper = $this->translatableStringHelper; + + $builder->add('types', EntityType::class, array( + 'class' => ActivityType::class, + 'choice_label' => function (ActivityType $type) use ($helper) { + return $helper->localize($type->getName()); + }, + 'multiple' => true, + 'expanded' => false + )); + } + + public function validateForm($data, ExecutionContextInterface $context) + { + if ($data['types'] === null || count($data['types']) === 0) { + $context->buildViolation("At least one type must be choosen") + ->addViolation(); + } + } + + public function getTitle() + { + return 'Filter by activity type'; + } + + public function addRole() + { + return new Role(ActivityStatsVoter::STATS); + } + + public function describeAction($data, $format = 'string') + { + // collect all the reasons'name used in this filter in one array + $reasonsNames = array_map( + function(ActivityType $t) { + return "\"".$this->translatableStringHelper->localize($t->getName())."\""; + }, + $this->typeRepository->findBy(array('id' => $data['types']->toArray())) + ); + + return array("Filtered by activity type: only %list%", + ["%list%" => implode(", ", $reasonsNames)]); + } +} diff --git a/Resources/config/services/export.yml b/Resources/config/services/export.yml index cb6ff5f52..61d5cc18b 100644 --- a/Resources/config/services/export.yml +++ b/Resources/config/services/export.yml @@ -31,6 +31,14 @@ services: tags: - { name: chill.export_filter, alias: 'activity_reason_filter' } + chill.activity.export.type_filter: + class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter + arguments: + - "@chill.main.helper.translatable_string" + - "@chill_activity.repository.activity_type" + tags: + - { name: chill.export_filter, alias: 'activity_type_filter' } + chill.activity.export.date_filter: class: Chill\ActivityBundle\Export\Filter\ActivityDateFilter arguments: diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 55e367d32..edbaa0967 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -119,7 +119,7 @@ Number of activities: Nombre d'activités #filters Filter by reason: Filtrer par sujet d'activité 'Filtered by reasons: only %list%': 'Filtré par sujet: seulement %list%' - +'Filtered by activity type: only %list%': "Filtré par type d'activity: seulement %list%" Filtered by date activity: Filtrer par date d'activité Activities after this date: Activités après cette date Activities before this date: Activités avant cette date @@ -132,6 +132,7 @@ Implied in an activity before this date: Impliqué dans une activité avant cett Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par personnes associées à une activité entre %date_from% et %date_to% avec les sujets %reasons_name% Activity reasons for those activities: Sujets de ces activités +Filter by activity type: Filtrer par type d'activité #aggregators Aggregate by activity reason: Aggréger par sujet de l'activité From 13333ed54a8c4f3665459db2de5e1c1fe17df820 Mon Sep 17 00:00:00 2001 From: Mat Date: Tue, 16 Oct 2018 10:02:26 +0200 Subject: [PATCH 3/6] privacyEvent, add event to activity list and show actions --- Controller/ActivityController.php | 37 +++++++++++++++++-- .../ChillActivityExtension.php | 1 + Resources/config/services/controller.yml | 5 +++ 3 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 Resources/config/services/controller.yml diff --git a/Controller/ActivityController.php b/Controller/ActivityController.php index a312bd480..80007f415 100644 --- a/Controller/ActivityController.php +++ b/Controller/ActivityController.php @@ -22,6 +22,8 @@ namespace Chill\ActivityBundle\Controller; +use Chill\PersonBundle\Privacy\PrivacyEvent; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -37,7 +39,22 @@ use Chill\ActivityBundle\Form\ActivityType; */ class ActivityController extends Controller { - + + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + + /** + * ActivityController constructor. + * + * @param EventDispatcherInterface $eventDispatcher + */ + public function __construct(EventDispatcherInterface $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + } + /** * Lists all Activity entities. * @@ -62,8 +79,13 @@ class ActivityController extends Controller array('person' => $person, 'scope' => $reachableScopes), array('date' => 'DESC') ); - - + + $event = new PrivacyEvent($person, array( + 'element_class' => Activity::class, + 'action' => 'list' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + return $this->render('ChillActivityBundle:Activity:list.html.twig', array( 'activities' => $activities, 'person' => $person @@ -201,7 +223,14 @@ class ActivityController extends Controller $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); $deleteForm = $this->createDeleteForm($id, $person); - + + $event = new PrivacyEvent($person, array( + 'element_class' => Activity::class, + 'element_id' => intval($id), + 'action' => 'show' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + return $this->render('ChillActivityBundle:Activity:show.html.twig', array( 'person' => $person, 'entity' => $entity, diff --git a/DependencyInjection/ChillActivityExtension.php b/DependencyInjection/ChillActivityExtension.php index ab0059155..0a5144a17 100644 --- a/DependencyInjection/ChillActivityExtension.php +++ b/DependencyInjection/ChillActivityExtension.php @@ -53,6 +53,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf $loader->load('services/repositories.yml'); $loader->load('services/fixtures.yml'); $loader->load('services/menu.yml'); + $loader->load('services/controller.yml'); } public function prepend(ContainerBuilder $container) diff --git a/Resources/config/services/controller.yml b/Resources/config/services/controller.yml new file mode 100644 index 000000000..075c52679 --- /dev/null +++ b/Resources/config/services/controller.yml @@ -0,0 +1,5 @@ +services: + Chill\ActivityBundle\Controller\ActivityController: + arguments: + $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' + tags: ['controller.service_arguments'] From b6ab04f3e31fa6a2e09fd4639507f8c22f0c5dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 19 Oct 2018 12:36:59 +0200 Subject: [PATCH 4/6] add privacy event to edit, update actions --- Controller/ActivityController.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Controller/ActivityController.php b/Controller/ActivityController.php index 80007f415..54f50c4af 100644 --- a/Controller/ActivityController.php +++ b/Controller/ActivityController.php @@ -28,7 +28,6 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Security\Core\Role\Role; - use Chill\ActivityBundle\Entity\Activity; use Chill\PersonBundle\Entity\Person; use Chill\ActivityBundle\Form\ActivityType; @@ -226,7 +225,7 @@ class ActivityController extends Controller $event = new PrivacyEvent($person, array( 'element_class' => Activity::class, - 'element_id' => intval($id), + 'element_id' => $entity->getId(), 'action' => 'show' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); @@ -263,6 +262,13 @@ class ActivityController extends Controller $editForm = $this->createEditForm($entity); $deleteForm = $this->createDeleteForm($id, $person); + + $event = new PrivacyEvent($person, array( + 'element_class' => Activity::class, + 'element_id' => $entity->getId(), + 'action' => 'show' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); return $this->render('ChillActivityBundle:Activity:edit.html.twig', array( 'entity' => $entity, @@ -314,6 +320,13 @@ class ActivityController extends Controller $deleteForm = $this->createDeleteForm($id, $person); $editForm = $this->createEditForm($entity); $editForm->handleRequest($request); + + $event = new PrivacyEvent($person, array( + 'element_class' => Activity::class, + 'element_id' => $entity->getId(), + 'action' => 'update' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); if ($editForm->isValid()) { $em->flush(); From 5eff3f33d8c7efce731430b2d164e5475c44fb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 19 Oct 2018 12:40:12 +0200 Subject: [PATCH 5/6] fix action description in privacy events logs --- Controller/ActivityController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Controller/ActivityController.php b/Controller/ActivityController.php index 54f50c4af..8e6c25e76 100644 --- a/Controller/ActivityController.php +++ b/Controller/ActivityController.php @@ -266,7 +266,7 @@ class ActivityController extends Controller $event = new PrivacyEvent($person, array( 'element_class' => Activity::class, 'element_id' => $entity->getId(), - 'action' => 'show' + 'action' => 'edit' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); From adee1b67a2e471af25074ec86c3413fc831424d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 19 Oct 2018 12:42:28 +0200 Subject: [PATCH 6/6] add changelog for privacy events --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88a7e4351..a556edeba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,3 +4,8 @@ Version 1.5.1 - [report activity count] fix error: do not show centers which are not selected in results. +Branch privacyEvent +================== + +- add privacy events to activity list / show / edit +