diff --git a/config/services.yaml b/config/services.yaml index cb29c3f3321b83667f45e8b12e4198c7c9b8ebf1..0cd60a8dc476b06fb12ec6e6ef62321389d9da00 100755 --- a/config/services.yaml +++ b/config/services.yaml @@ -59,6 +59,10 @@ services: arguments: $rootDB: '%root_db%' + App\Services\UserNotificationService: + arguments: + $baseUrl: '%base_url%' + # Commands App\Command\UpdateProjectsInfoCommand: arguments: @@ -68,6 +72,7 @@ services: arguments: $baseUrl: '%base_url%' + # Overide FOS Registration Controller App\Controller\RegistrationController: tags: ['controller.service_arguments'] @@ -272,7 +277,9 @@ services: arguments: [~, App\Document\Configuration, 'App\Controller\Admin\ConfigurationAdminController'] tags: - { name: sonata.admin, manager_type: doctrine_mongodb, group: sonata_user, label: Configuration } - + + # -- Other --- + admin.etiquettes_config: class: App\Admin\StampAdmin arguments: [~, App\Document\Stamp, '' ] diff --git a/src/Admin/ImportAdmin.php b/src/Admin/ImportAdmin.php index 15e37beb9a2ad6940c6c63653e72cb4c82954454..05869ebc70104ba613bfebbefff83d01fa5f496d 100755 --- a/src/Admin/ImportAdmin.php +++ b/src/Admin/ImportAdmin.php @@ -60,6 +60,13 @@ class ImportAdmin extends AbstractAdmin ->end() ->with('Paramètres', ['class' => 'col-md-12']) ->add('refreshFrequencyInDays', null, ['required' => false, 'label' => 'Fréquence de mise à jours des données en jours (laisser vide pour ne jamais mettre à jour automatiquement']) + ->add('usersToNotify', ModelType::class, [ + 'class' => 'App\Document\User', + 'required' => false, + 'multiple' => true, + 'btn_add' => false, + 'label' => "Utilisateurs à notifier en cas d'erreur, ou lorsque de nouveaux champs/catégories sont à faire correspondre", ], ['admin_code' => 'admin.option_hidden']) + ->add('moderateElements', null, [ 'required' => false, 'label' => 'Modérer les éléments importés', diff --git a/src/Admin/UserAdmin.php b/src/Admin/UserAdmin.php index 2d09fbbae2fee7418e2cd3f6b52646866f2091fa..e62b05815b5757c2a59e777ccf430a23c8ece28c 100755 --- a/src/Admin/UserAdmin.php +++ b/src/Admin/UserAdmin.php @@ -176,7 +176,21 @@ class UserAdmin extends AbstractAdmin ->tab('User') ->with('General', ['class' => 'col-md-6'])->end() ->with('Status', ['class' => 'col-md-6'])->end() - ->with('Groups', ['class' => 'col-md-12'])->end() + ->with('Groups', ['class' => 'col-md-6'])->end() + ->with('Notifications', ['class' => 'col-md-12']) + ->add('watchModeration', null, ['label' => "Etre notifié par email lorsque des éléments sont à modérer", 'required' => false]) + ->add('watchModerationOnlyWithOptions', ModelType::class, [ + 'class' => 'App\Document\Option', + 'required' => false, + 'multiple' => true, + 'btn_add' => false, + 'label' => 'Seulement pour les éléments ayant une des catégories suivante', ], ['admin_code' => 'admin.option_hidden']) + ->add('watchModerationOnlyWithPostCodes', null, [ + 'label' => "Seulement pour les éléments avec code postal", + 'label_attr' => ['title' => "Séparés par des virgules. On peut utiliser le symbole * pour choisir tout un département, par example : 40*, 47*, 48500"], + 'required' => false, + 'attr' => ['placeholder' => '40*, 47*, 48500']]) + ->end() ->end() ->tab('Security') ->with('Roles', ['class' => 'col-md-12'])->end() diff --git a/src/Command/CheckVoteCommand.php b/src/Command/CheckVoteCommand.php index 4a3869ac4944ae64252cee09dd18d9633821ce87..19138e97590d24311bb6c242bfdacf2862c34690 100755 --- a/src/Command/CheckVoteCommand.php +++ b/src/Command/CheckVoteCommand.php @@ -3,6 +3,7 @@ namespace App\Command; use App\Services\ElementVoteService; +use App\Services\UserNotificationService; use Doctrine\ODM\MongoDB\DocumentManager; use App\Services\DocumentManagerFactory; use Psr\Log\LoggerInterface; @@ -14,9 +15,11 @@ class CheckVoteCommand extends GoGoAbstractCommand { public function __construct(DocumentManagerFactory $dm, LoggerInterface $commandsLogger, TokenStorageInterface $security, - ElementVoteService $voteService) + ElementVoteService $voteService, + UserNotificationService $notifService) { $this->voteService = $voteService; + $this->notifService = $notifService; parent::__construct($dm, $commandsLogger, $security); } @@ -33,7 +36,7 @@ class CheckVoteCommand extends GoGoAbstractCommand $elementRepo = $dm->getRepository('App\Document\Element'); $elements = $elementRepo->findPendings(); - foreach ($elements as $key => $element) { + foreach ($elements as $element) { $this->voteService->checkVotes($element); $dm->persist($element); } @@ -41,5 +44,8 @@ class CheckVoteCommand extends GoGoAbstractCommand $dm->flush(); $output->writeln('Nombre elements checkés : '.count($elements)); + + // send notif here so we don't need to create another command + $this->notifService->sendModerationNotifications(); } } diff --git a/src/Command/ImportSourceCommand.php b/src/Command/ImportSourceCommand.php index 8830e4ef0f911b32846843ae7d74310e87532e3b..ffe9ce6b41c6a197db19d0d8234812f6c7ae9cbf 100644 --- a/src/Command/ImportSourceCommand.php +++ b/src/Command/ImportSourceCommand.php @@ -6,6 +6,7 @@ use App\Document\ImportState; use App\Services\ElementImportService; use Doctrine\ODM\MongoDB\DocumentManager; use App\Services\DocumentManagerFactory; +use App\Services\UserNotificationService; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -16,9 +17,11 @@ class ImportSourceCommand extends GoGoAbstractCommand { public function __construct(DocumentManagerFactory $dm, LoggerInterface $commandsLogger, TokenStorageInterface $security, - ElementImportService $importService) + ElementImportService $importService, + UserNotificationService $notifService) { $this->importService = $importService; + $this->notifService = $notifService; parent::__construct($dm, $commandsLogger, $security); } @@ -47,7 +50,8 @@ class ImportSourceCommand extends GoGoAbstractCommand } $this->log('Updating source '.$import->getSourceName().' for project '.$input->getArgument('dbname').' begins...'); - $result = $this->importService->startImport($import); + // $this->importService->setDm($dm); + $result = $this->importService->startImport($import, $manuallyStarted = false); $this->log($result); } catch (\Exception $e) { $this->dm->persist($import); @@ -55,6 +59,7 @@ class ImportSourceCommand extends GoGoAbstractCommand $message = $e->getMessage().'</br>'.$e->getFile().' LINE '.$e->getLine(); $import->setCurrMessage($message); $this->error('Source: '.$import->getSourceName().' - '.$message); + $this->notifService->notifyImportError($import); } } } diff --git a/src/Command/RemoveAbandonnedProjectsCommand.php b/src/Command/RemoveAbandonnedProjectsCommand.php index 3515ef7fde01a62b7aa203265ee91f05a9dddeb2..408c096fbd9266fbf72dfeee1d6795f76a20b553 100755 --- a/src/Command/RemoveAbandonnedProjectsCommand.php +++ b/src/Command/RemoveAbandonnedProjectsCommand.php @@ -2,7 +2,6 @@ namespace App\Command; -use App\Document\User; use App\Services\MailService; use Doctrine\ODM\MongoDB\DocumentManager; use App\Services\DocumentManagerFactory; diff --git a/src/Document/ImportDynamic.php b/src/Document/ImportDynamic.php index 9535af3636e690c90bf87dae3d82aec37ee1fa25..edb8cfdb9401763c09022227ac9999f0c07a0824 100644 --- a/src/Document/ImportDynamic.php +++ b/src/Document/ImportDynamic.php @@ -31,6 +31,12 @@ class ImportDynamic extends Import */ private $nextRefresh = null; + /** + * Users to be tonified when error during import, or where new ontology/taxonomy mapping + * @MongoDB\ReferenceMany(targetDocument="App\Document\User") + */ + private $usersToNotify; + public function isDynamicImport() { return true; @@ -112,4 +118,24 @@ class ImportDynamic extends Import $this->osmQueriesJson = $json; return $this; } + + /** + * Get users to be tonified when error during import, or where new ontology/taxonomy mapping + */ + public function getUsersToNotify() + { + return $this->usersToNotify; + } + + /** + * Set users to be tonified when error during import, or where new ontology/taxonomy mapping + * + * @return self + */ + public function setUsersToNotify($usersToNotify) + { + $this->usersToNotify = $usersToNotify; + + return $this; + } } diff --git a/src/Document/User.php b/src/Document/User.php index 72e8985ce8c3805d12f2ca9e220176e6ddfee666..0d475b2b91084a1a25909fa9c46aadc4f82a6787 100644 --- a/src/Document/User.php +++ b/src/Document/User.php @@ -77,6 +77,22 @@ class User extends BaseUser */ protected $nextNewsletterDate; + /** + * Be notified by email when an Element need moderation + * @MongoDB\Field(type="bool") + */ + protected $watchModeration; + + /** + * @MongoDB\ReferenceMany(targetDocument="App\Document\Option", cascade={"persist"}) + */ + protected $watchModerationOnlyWithOptions; + + /** + * @MongoDB\Field(type="string") + */ + protected $watchModerationOnlyWithPostCodes; + /** * @MongoDB\Field(type="int") */ @@ -895,4 +911,64 @@ class User extends BaseUser { return $this->communsData; } + + /** + * Get be notified by email when an Element need moderation + */ + public function getWatchModeration() + { + return $this->watchModeration; + } + + /** + * Set be notified by email when an Element need moderation + * + * @return self + */ + public function setWatchModeration($watchModeration) + { + $this->watchModeration = $watchModeration; + + return $this; + } + + /** + * Get the value of watchModerationOnlyWithOptions + */ + public function getWatchModerationOnlyWithOptions() + { + return $this->watchModerationOnlyWithOptions; + } + + /** + * Set the value of watchModerationOnlyWithOptions + * + * @return self + */ + public function setWatchModerationOnlyWithOptions($watchModerationOnlyWithOptions) + { + $this->watchModerationOnlyWithOptions = $watchModerationOnlyWithOptions; + + return $this; + } + + /** + * Get the value of watchModerationOnlyWithPostCodes + */ + public function getWatchModerationOnlyWithPostCodes() + { + return $this->watchModerationOnlyWithPostCodes; + } + + /** + * Set the value of watchModerationOnlyWithPostCodes + * + * @return self + */ + public function setWatchModerationOnlyWithPostCodes($watchModerationOnlyWithPostCodes) + { + $this->watchModerationOnlyWithPostCodes = $watchModerationOnlyWithPostCodes; + + return $this; + } } diff --git a/src/Repository/ElementRepository.php b/src/Repository/ElementRepository.php index b7dc966c8f79de00f40a556b6d216fec98d6488f..638821dc9d777590f52c0b82811c377536537884 100755 --- a/src/Repository/ElementRepository.php +++ b/src/Repository/ElementRepository.php @@ -220,6 +220,25 @@ class ElementRepository extends DocumentRepository return $qb->getQuery()->execute(); } + public function findModerationElementToNotifyToUser($user) + { + $qb = $this->createQueryBuilder('App\Document\Element'); + $qb->field('moderationState')->notEqual(ModerationState::NotNeeded); + $qb->field('status')->gt(ElementStatus::AdminRefused); + $optionsIds = []; + foreach($user->getWatchModerationOnlyWithOptions() as $option) + $optionsIds[] = $option->getId(); + if (count($optionsIds)> 0) + $qb->field('optionValues.optionId')->in($optionsIds); + if ($user->getWatchModerationOnlyWithPostCodes()) { + $regexp = str_replace(',', '|', $user->getWatchModerationOnlyWithPostCodes()); + $regexp = "/" . str_replace(' ', '', $regexp) . "/"; + $qb->field('address.postalCode')->equals(new \MongoRegex($regexp)); + } + + return $qb->count()->getQuery()->execute(); + } + private function queryToArray($qb) { return $qb->hydrate(false)->getQuery()->execute()->toArray(); diff --git a/src/Services/ElementImportService.php b/src/Services/ElementImportService.php index 7660b6c6b24875564bcc375dfaeebdf3aaabcf80..ff3b0fefe627f0a9a018d33a1d58a69ceb7fa763 100755 --- a/src/Services/ElementImportService.php +++ b/src/Services/ElementImportService.php @@ -24,22 +24,28 @@ class ElementImportService protected $elementIdsErrors = []; protected $errorsMessages = []; protected $errorsCount = []; + protected $manuallyStarted = true; /** * Constructor. */ public function __construct(DocumentManager $dm, ElementImportOneService $importOneService, ElementImportMappingService $mappingService, - TaxonomyJsonGenerator $taxonomyJsonGenerator) + TaxonomyJsonGenerator $taxonomyJsonGenerator, + UserNotificationService $notifService) { $this->dm = $dm; $this->importOneService = $importOneService; $this->mappingService = $mappingService; $this->taxonomyJsonGenerator = $taxonomyJsonGenerator; + $this->notifService = $notifService; } - public function startImport($import) + public function setDm($dm) { $this->dm = $dm; } + + public function startImport($import, $manuallyStarted = true) { + $this->manuallyStarted = $manuallyStarted; $this->countElementCreated = 0; $this->countElementUpdated = 0; $this->countElementNothingToDo = 0; @@ -326,6 +332,14 @@ class ElementImportService $import->setCurrState($totalErrors > 0 ? ($totalErrors == $size ? ImportState::Failed : ImportState::Errors) : ImportState::Completed); $import->setCurrMessage($log->displayMessage()); + if ($import->isDynamicImport() && !$this->manuallyStarted) { + if ($totalErrors > 0) { + $this->notifService->notifyImportError($import); + } + if ($import->getNewOntologyToMap() || $import->getNewTaxonomyToMap()) { + $this->notifService->notifyImportMapping($import); + } + } $this->dm->flush(); } catch (\Error $e) { diff --git a/src/Services/UserNotificationService.php b/src/Services/UserNotificationService.php new file mode 100644 index 0000000000000000000000000000000000000000..21232906498d7c5a6395eaf73bbad76138a3c8e3 --- /dev/null +++ b/src/Services/UserNotificationService.php @@ -0,0 +1,70 @@ +<?php + +namespace App\Services; + +use Doctrine\ODM\MongoDB\DocumentManager; +use Symfony\Component\Routing\RouterInterface; + +class UserNotificationService +{ + public function __construct(DocumentManager $dm, MailService $mailService, + RouterInterface $router, $baseUrl) + { + $this->dm = $dm; + $this->mailService = $mailService; + $this->baseUrl = $baseUrl; + $this->router = $router; + } + + function sendModerationNotifications() + { + $users = $this->dm->getRepository('App\Document\User') + ->findByWatchModeration(true); + foreach ($users as $user) { + $elementsCount = $this->dm->getRepository('App\Document\Element') + ->findModerationElementToNotifyToUser($user); + if ($elementsCount > 0) { + $config = $this->dm->getRepository('App\Document\Configuration')->findConfiguration(); + + $subject = "Des éléments sont à modérer sur {$config->getAppName()}"; + $url = $this->generateRoute($config, 'gogo_directory'); + $editPreferenceUrl = $this->generateRoute($config, 'admin_app_user_edit', ['id' => $user->getId()]); + $elementsCountText = $elementsCount == 1 ? "{$config->getElementDisplayName()} est" : "{$config->getElementDisplayNamePlural()} sont"; + $content = "Bonjour !</br></br>$elementsCount $elementsCountText à modérer sur la carte \"{$config->getAppName()}\"</br></br> + <a href='{$url}'>Accéder à la carte</a></br></br> + Pour changer vos préférences de notification, <a href='$editPreferenceUrl'>cliquez ici</a>"; + $this->mailService->sendMail($user->getEmail(), $subject, $content); + } + } + } + + private function generateRoute($config, $route, $params = []) + { + return 'http://'.$config->getDbName().'.'.$this->baseUrl . $this->router->generate($route, $params); + } + + function notifyImportError($import) + { + if (!$import->isDynamicImport()) return; + $import->getUsersToNotify()->count(); + foreach($import->getUsersToNotify() as $user) { + $config = $this->dm->getRepository('App\Document\Configuration')->findConfiguration(); + $importUrl = $this->generateRoute($config, 'admin_app_import_edit', ['id' => $import->getId()]); + $subject = "Des erreurs ont eu lieu lors d'un import sur {$config->getAppName()}"; + $content = "Bonjour !</br></br>L'import {$import->getSourceName()} semble avoir quelques soucis.. <a href='$importUrl'>Cliquez ici</a> pour essayer d'y remédier"; + $this->mailService->sendMail($user->getEmail(), $subject, $content); + } + } + + function notifyImportMapping($import) + { + if (!$import->isDynamicImport()) return; + foreach($import->getUsersToNotify() as $user) { + $config = $this->dm->getRepository('App\Document\Configuration')->findConfiguration(); + $importUrl = $this->generateRoute($config, 'admin_app_import_edit', ['id' => $import->getId()]); + $subject = "Action requise pour un import sur {$config->getAppName()}"; + $content = "Bonjour !</br></br>L'import {$import->getSourceName()} a de nouveaux champs ou de nouvelles catégories qui auraient peut être besoin de votre attention.. <a href='$importUrl'>Cliquez ici</a> pour accéder aux tables de correspondances"; + $this->mailService->sendMail($user->getEmail(), $subject, $content); + } + } +} \ No newline at end of file