Loading CHANGELOG.md +2 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ Idem pour les attestations et le privilège "Modification des attestations conce - Correction d'un bug dans la recherche de thèses par nom du doctorant. - Possibilité d'attribuer un "identifiant permanent" à un fichier (ex: 'RAPPORT_ANNUEL_MODELE') facilitant l'intégration de lien de téléchargement de ce fichier dans une page. - Listes de diffusion dynamique Sympa alimentées par SyGAL : pages de consultation des listes de diffusion déclarées dans la config ; une URL pour fournir les abonnés, une autre pour fournir les propriétaires. 1.4.6 (29/05/2020) ------------------ Loading doc/release-notes/v1.4.7.md +15 −0 Original line number Diff line number Diff line Loading @@ -116,4 +116,19 @@ from these t left join acteurs a on a.these_id = t.id left join individu ia on ia.id = a.INDIVIDU_ID ; insert into CATEGORIE_PRIVILEGE(ID, CODE, LIBELLE, ORDRE) select categorie_privilege_id_seq.nextval, 'liste-diffusion', 'Liste de diffusion', 50 from dual ; -- si échoue, retenter jusqu'au succès insert into PRIVILEGE(ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) select privilege_id_seq.nextval, cp.id, 'consulter', 'Consulter une liste de diffusion', 250 from CATEGORIE_PRIVILEGE cp where cp.CODE = 'liste-diffusion'; insert into PRIVILEGE(ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) select privilege_id_seq.nextval, cp.id, 'lister', 'Lister les listes de diffusion', 300 from CATEGORIE_PRIVILEGE cp where cp.CODE = 'liste-diffusion'; -- -- ATTENTION >>> Dans l'interface graphique, accorder ces nouveaux privilèges aux profils voulus (a minima Doctorant et AdminTech). -- ``` module/Application/config/others/liste-diffusion.config.php 0 → 100755 +114 −0 Original line number Diff line number Diff line <?php namespace Application; use Application\Controller\Factory\ListeDiffusionControllerFactory; use Application\Controller\ListeDiffusionController; use Application\Provider\Privilege\ListeDiffusionPrivileges; use Application\Service\ListeDiffusion\ListeDiffusionService; use Application\Service\ListeDiffusion\ListeDiffusionServiceFactory; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionRolePlugin; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionRolePluginFactory; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionStructurePlugin; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionStructurePluginFactory; use UnicaenAuth\Guard\PrivilegeController; use Zend\Mvc\Router\Http\Literal; use Zend\Mvc\Router\Http\Segment; return [ 'bjyauthorize' => [ 'guards' => [ PrivilegeController::class => [ [ 'controller' => ListeDiffusionController::class, 'action' => [ 'index', ], 'privileges' => ListeDiffusionPrivileges::LISTE_DIFFUSION_LISTER, ], [ 'controller' => ListeDiffusionController::class, 'action' => [ 'consulter', ], 'privileges' => ListeDiffusionPrivileges::LISTE_DIFFUSION_CONSULTER, ], [ 'controller' => ListeDiffusionController::class, 'action' => [ 'generate-member-include', 'generate-owner-include', ], 'roles' => [], // doit être accessible librement ], ], ], ], 'router' => [ 'routes' => [ 'liste-diffusion' => [ 'type' => Literal::class, 'options' => [ 'route' => '/liste-diffusion', 'defaults' => [ 'controller' => ListeDiffusionController::class, 'action' => 'index', ], ], 'may_terminate' => true, 'child_routes' => [ 'liste' => [ 'type' => Segment::class, 'options' => [ 'route' => '/:liste', // exemple: /consulter/ed591.doctorants.ucn@normandie-univ.fr // exemple: /consulter/ed591.doctorants@normandie-univ.fr 'constraints' => [ 'liste' => '[a-zA-Z0-9-_.@]+', ], 'defaults' => [ /** @see ListeDiffusionController::consulterAction() */ 'action' => 'consulter', ], ], 'may_terminate' => true, 'child_routes' => [ 'generate-member-include' => [ 'type' => Literal::class, 'options' => [ 'route' => '/95c66625fe1e45a41e4a51d3f786210ab0a47479/generate-member-include/', 'defaults' => [ /** @see ListeDiffusionController::generateMemberIncludeAction() */ 'action' => 'generate-member-include', ], ], ], 'generate-owner-include' => [ 'type' => Literal::class, 'options' => [ 'route' => '/ef35998526851f484a027478ef9b7e936a0366e5/generate-owner-include', 'defaults' => [ /** @see ListeDiffusionController::generateOwnerIncludeAction() */ 'action' => 'generate-owner-include', ], ], ], ], ], ], ], ], ], 'service_manager' => [ 'factories' => [ ListeDiffusionService::class => ListeDiffusionServiceFactory::class, ListeDiffusionStructurePlugin::class => ListeDiffusionStructurePluginFactory::class, ListeDiffusionRolePlugin::class => ListeDiffusionRolePluginFactory::class, ], ], 'controllers' => [ 'factories' => [ ListeDiffusionController::class => ListeDiffusionControllerFactory::class, ], ], ]; module/Application/src/Application/Controller/Factory/ListeDiffusionControllerFactory.php 0 → 100644 +46 −0 Original line number Diff line number Diff line <?php namespace Application\Controller\Factory; use Application\Controller\ListeDiffusionController; use Application\Service\File\FileService; use Application\Service\Individu\IndividuService; use Application\Service\ListeDiffusion\ListeDiffusionService; use Application\Service\Notification\NotifierService; use Zend\ServiceManager\ServiceLocatorInterface as ContainerInterface; class ListeDiffusionControllerFactory { public function __invoke(ContainerInterface $container) { $container = $container->getServiceLocator(); $controller = new ListeDiffusionController(); /** * @var ListeDiffusionService $individuService */ $individuService = $container->get(ListeDiffusionService::class); $controller->setListeDiffusionService($individuService); /** * @var IndividuService $individuService */ $individuService = $container->get('IndividuService'); $controller->setIndividuService($individuService); /** * @var FileService $fileService */ $fileService = $container->get(FileService::class); $controller->setFileService($fileService); /** * @var NotifierService $notifierService */ $notifierService = $container->get(NotifierService::class); $controller->setNotifierService($notifierService); return $controller; } } No newline at end of file module/Application/src/Application/Controller/ListeDiffusionController.php 0 → 100644 +175 −0 Original line number Diff line number Diff line <?php namespace Application\Controller; use Application\Entity\Db\Individu; use Application\Entity\Db\Role; use Application\Service\File\FileServiceAwareTrait; use Application\Service\Individu\IndividuServiceAwareTrait; use Application\Service\ListeDiffusion\ListeDiffusionServiceAwareTrait; use Application\Service\Notification\NotifierServiceAwareTrait; use Webmozart\Assert\Assert; use Zend\View\Model\ViewModel; class ListeDiffusionController extends AbstractController { use ListeDiffusionServiceAwareTrait; use IndividuServiceAwareTrait; use FileServiceAwareTrait; use NotifierServiceAwareTrait; /** * Adresse complète de la liste de diffusion, ex : * - ed591.doctorants.insa@normandie-univ.fr * - ed591.doctorants@normandie-univ.fr * - ed591.dirtheses@normandie-univ.fr * * Où : * - '591' est le numéro national de l'école doctorale ; * - 'doctorants' (ou 'dirtheses') est la "cible" ; * - 'insa' est le source_code unique de l'établissement en minuscules. * * @var string */ protected $liste; /** * @return array|ViewModel */ public function indexAction() { $listes = $this->listeDiffusionService->fetchListesDiffusion(); return new ViewModel([ 'listes' => $listes, ]); } /** * @return ViewModel */ public function consulterAction() { $this->loadRequestParams(); $listesDeclarees = $this->listeDiffusionService->fetchListesDiffusion(); Assert::inArray($this->liste, $listesDeclarees, "Liste spécifiée non déclarée."); $this->listeDiffusionService->setListe($this->liste); $this->listeDiffusionService->init(); $this->listeDiffusionService->createMemberIncludeFileContent(); $memberIndividusAvecAdresse = $this->listeDiffusionService->getIndividusAvecAdresse(); $memberIndividusSansAdresse = $this->listeDiffusionService->getIndividusSansAdresse(); $this->listeDiffusionService->createOwnerIncludeFileContent(); $ownerIndividusAvecAdresse = $this->listeDiffusionService->getIndividusAvecAdresse(); $ownerIndividusSansAdresse = $this->listeDiffusionService->getIndividusSansAdresse(); return new ViewModel([ 'liste' => $this->liste, 'memberIndividusAvecAdresse' => $memberIndividusAvecAdresse, 'memberIndividusSansAdresse' => $memberIndividusSansAdresse, 'ownerIndividusAvecAdresse' => $ownerIndividusAvecAdresse, 'ownerIndividusSansAdresse' => $ownerIndividusSansAdresse, ]); } /** * Dépouillage des paramètres de la requête. * * Les paramètres de routage acceptés sont les suivants : * - `liste` (OBLIGATOIRE) : cf. {@see $liste}. */ private function loadRequestParams() { $this->liste = $this->getRequestedListe(); // ex: 'ed591.doctorants.insa@normandie-univ.fr' } /** * Génération du fichier attendu par Sympa pour obtenir les ABONNÉS d'une liste de diffusion. * * Le fichier retourné contient une adresse électronique par ligne. */ public function generateMemberIncludeAction() { $this->loadRequestParams(); $this->listeDiffusionService->setListe($this->liste); $this->listeDiffusionService->init(); $content = $this->listeDiffusionService->createMemberIncludeFileContent(); //$this->handleMemberIncludeNotFoundEmails(); // PAS POSSIBLE : Sympa interroge toutes les heures ! $filename = $this->listeDiffusionService->generateResultFileName('member'); $this->fileService->downloadFileFromContent($content, $filename); } /** * Génération du fichier attendu par Sympa pour obtenir les PROPRIÉTAIRES d'une liste de diffusion. * * Le fichier retourné contient une adresse électronique par ligne. */ public function generateOwnerIncludeAction() { $this->loadRequestParams(); $this->listeDiffusionService->setListe($this->liste); $this->listeDiffusionService->init(); $content = $this->listeDiffusionService->createOwnerIncludeFileContent(); $filename = $this->listeDiffusionService->generateResultFileName('owner'); $this->fileService->downloadFileFromContent($content, $filename); } /** * Gestion des ABONNÉS sans adresse mail. */ private function handleMemberIncludeNotFoundEmails() { $individusSansAdresse = $this->listeDiffusionService->getIndividusSansAdresse(); if (empty($individusSansAdresse)) { return; } $individusAvecAdresse = $this->listeDiffusionService->getIndividusAvecAdresse(); // Envoi d'une notif aux admin tech $to = $this->fetchAdminTechEmails(); $this->notifierService->triggerAbonnesListeDiffusionSansAdresse( $to, $this->liste, $individusAvecAdresse, $individusSansAdresse); } /** * Gestion des PROPRÉTAIRES sans adresse mail. */ private function handleOwnerIncludeNotFoundEmails() { } /** * @return string */ private function getRequestedListe() { $liste = $this->params()->fromRoute('liste'); Assert::notNull($liste, "Aucune liste spécifiée."); return $liste; } /** * @return string[] */ private function fetchAdminTechEmails() { $individus = $this->individuService->getRepository()->findByRole(Role::CODE_ADMIN_TECH); return array_map(function(Individu $i) { return $i->getEmailUtilisateur(); }, $individus); } } No newline at end of file Loading
CHANGELOG.md +2 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ Idem pour les attestations et le privilège "Modification des attestations conce - Correction d'un bug dans la recherche de thèses par nom du doctorant. - Possibilité d'attribuer un "identifiant permanent" à un fichier (ex: 'RAPPORT_ANNUEL_MODELE') facilitant l'intégration de lien de téléchargement de ce fichier dans une page. - Listes de diffusion dynamique Sympa alimentées par SyGAL : pages de consultation des listes de diffusion déclarées dans la config ; une URL pour fournir les abonnés, une autre pour fournir les propriétaires. 1.4.6 (29/05/2020) ------------------ Loading
doc/release-notes/v1.4.7.md +15 −0 Original line number Diff line number Diff line Loading @@ -116,4 +116,19 @@ from these t left join acteurs a on a.these_id = t.id left join individu ia on ia.id = a.INDIVIDU_ID ; insert into CATEGORIE_PRIVILEGE(ID, CODE, LIBELLE, ORDRE) select categorie_privilege_id_seq.nextval, 'liste-diffusion', 'Liste de diffusion', 50 from dual ; -- si échoue, retenter jusqu'au succès insert into PRIVILEGE(ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) select privilege_id_seq.nextval, cp.id, 'consulter', 'Consulter une liste de diffusion', 250 from CATEGORIE_PRIVILEGE cp where cp.CODE = 'liste-diffusion'; insert into PRIVILEGE(ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) select privilege_id_seq.nextval, cp.id, 'lister', 'Lister les listes de diffusion', 300 from CATEGORIE_PRIVILEGE cp where cp.CODE = 'liste-diffusion'; -- -- ATTENTION >>> Dans l'interface graphique, accorder ces nouveaux privilèges aux profils voulus (a minima Doctorant et AdminTech). -- ```
module/Application/config/others/liste-diffusion.config.php 0 → 100755 +114 −0 Original line number Diff line number Diff line <?php namespace Application; use Application\Controller\Factory\ListeDiffusionControllerFactory; use Application\Controller\ListeDiffusionController; use Application\Provider\Privilege\ListeDiffusionPrivileges; use Application\Service\ListeDiffusion\ListeDiffusionService; use Application\Service\ListeDiffusion\ListeDiffusionServiceFactory; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionRolePlugin; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionRolePluginFactory; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionStructurePlugin; use Application\Service\ListeDiffusion\Plugin\ListeDiffusionStructurePluginFactory; use UnicaenAuth\Guard\PrivilegeController; use Zend\Mvc\Router\Http\Literal; use Zend\Mvc\Router\Http\Segment; return [ 'bjyauthorize' => [ 'guards' => [ PrivilegeController::class => [ [ 'controller' => ListeDiffusionController::class, 'action' => [ 'index', ], 'privileges' => ListeDiffusionPrivileges::LISTE_DIFFUSION_LISTER, ], [ 'controller' => ListeDiffusionController::class, 'action' => [ 'consulter', ], 'privileges' => ListeDiffusionPrivileges::LISTE_DIFFUSION_CONSULTER, ], [ 'controller' => ListeDiffusionController::class, 'action' => [ 'generate-member-include', 'generate-owner-include', ], 'roles' => [], // doit être accessible librement ], ], ], ], 'router' => [ 'routes' => [ 'liste-diffusion' => [ 'type' => Literal::class, 'options' => [ 'route' => '/liste-diffusion', 'defaults' => [ 'controller' => ListeDiffusionController::class, 'action' => 'index', ], ], 'may_terminate' => true, 'child_routes' => [ 'liste' => [ 'type' => Segment::class, 'options' => [ 'route' => '/:liste', // exemple: /consulter/ed591.doctorants.ucn@normandie-univ.fr // exemple: /consulter/ed591.doctorants@normandie-univ.fr 'constraints' => [ 'liste' => '[a-zA-Z0-9-_.@]+', ], 'defaults' => [ /** @see ListeDiffusionController::consulterAction() */ 'action' => 'consulter', ], ], 'may_terminate' => true, 'child_routes' => [ 'generate-member-include' => [ 'type' => Literal::class, 'options' => [ 'route' => '/95c66625fe1e45a41e4a51d3f786210ab0a47479/generate-member-include/', 'defaults' => [ /** @see ListeDiffusionController::generateMemberIncludeAction() */ 'action' => 'generate-member-include', ], ], ], 'generate-owner-include' => [ 'type' => Literal::class, 'options' => [ 'route' => '/ef35998526851f484a027478ef9b7e936a0366e5/generate-owner-include', 'defaults' => [ /** @see ListeDiffusionController::generateOwnerIncludeAction() */ 'action' => 'generate-owner-include', ], ], ], ], ], ], ], ], ], 'service_manager' => [ 'factories' => [ ListeDiffusionService::class => ListeDiffusionServiceFactory::class, ListeDiffusionStructurePlugin::class => ListeDiffusionStructurePluginFactory::class, ListeDiffusionRolePlugin::class => ListeDiffusionRolePluginFactory::class, ], ], 'controllers' => [ 'factories' => [ ListeDiffusionController::class => ListeDiffusionControllerFactory::class, ], ], ];
module/Application/src/Application/Controller/Factory/ListeDiffusionControllerFactory.php 0 → 100644 +46 −0 Original line number Diff line number Diff line <?php namespace Application\Controller\Factory; use Application\Controller\ListeDiffusionController; use Application\Service\File\FileService; use Application\Service\Individu\IndividuService; use Application\Service\ListeDiffusion\ListeDiffusionService; use Application\Service\Notification\NotifierService; use Zend\ServiceManager\ServiceLocatorInterface as ContainerInterface; class ListeDiffusionControllerFactory { public function __invoke(ContainerInterface $container) { $container = $container->getServiceLocator(); $controller = new ListeDiffusionController(); /** * @var ListeDiffusionService $individuService */ $individuService = $container->get(ListeDiffusionService::class); $controller->setListeDiffusionService($individuService); /** * @var IndividuService $individuService */ $individuService = $container->get('IndividuService'); $controller->setIndividuService($individuService); /** * @var FileService $fileService */ $fileService = $container->get(FileService::class); $controller->setFileService($fileService); /** * @var NotifierService $notifierService */ $notifierService = $container->get(NotifierService::class); $controller->setNotifierService($notifierService); return $controller; } } No newline at end of file
module/Application/src/Application/Controller/ListeDiffusionController.php 0 → 100644 +175 −0 Original line number Diff line number Diff line <?php namespace Application\Controller; use Application\Entity\Db\Individu; use Application\Entity\Db\Role; use Application\Service\File\FileServiceAwareTrait; use Application\Service\Individu\IndividuServiceAwareTrait; use Application\Service\ListeDiffusion\ListeDiffusionServiceAwareTrait; use Application\Service\Notification\NotifierServiceAwareTrait; use Webmozart\Assert\Assert; use Zend\View\Model\ViewModel; class ListeDiffusionController extends AbstractController { use ListeDiffusionServiceAwareTrait; use IndividuServiceAwareTrait; use FileServiceAwareTrait; use NotifierServiceAwareTrait; /** * Adresse complète de la liste de diffusion, ex : * - ed591.doctorants.insa@normandie-univ.fr * - ed591.doctorants@normandie-univ.fr * - ed591.dirtheses@normandie-univ.fr * * Où : * - '591' est le numéro national de l'école doctorale ; * - 'doctorants' (ou 'dirtheses') est la "cible" ; * - 'insa' est le source_code unique de l'établissement en minuscules. * * @var string */ protected $liste; /** * @return array|ViewModel */ public function indexAction() { $listes = $this->listeDiffusionService->fetchListesDiffusion(); return new ViewModel([ 'listes' => $listes, ]); } /** * @return ViewModel */ public function consulterAction() { $this->loadRequestParams(); $listesDeclarees = $this->listeDiffusionService->fetchListesDiffusion(); Assert::inArray($this->liste, $listesDeclarees, "Liste spécifiée non déclarée."); $this->listeDiffusionService->setListe($this->liste); $this->listeDiffusionService->init(); $this->listeDiffusionService->createMemberIncludeFileContent(); $memberIndividusAvecAdresse = $this->listeDiffusionService->getIndividusAvecAdresse(); $memberIndividusSansAdresse = $this->listeDiffusionService->getIndividusSansAdresse(); $this->listeDiffusionService->createOwnerIncludeFileContent(); $ownerIndividusAvecAdresse = $this->listeDiffusionService->getIndividusAvecAdresse(); $ownerIndividusSansAdresse = $this->listeDiffusionService->getIndividusSansAdresse(); return new ViewModel([ 'liste' => $this->liste, 'memberIndividusAvecAdresse' => $memberIndividusAvecAdresse, 'memberIndividusSansAdresse' => $memberIndividusSansAdresse, 'ownerIndividusAvecAdresse' => $ownerIndividusAvecAdresse, 'ownerIndividusSansAdresse' => $ownerIndividusSansAdresse, ]); } /** * Dépouillage des paramètres de la requête. * * Les paramètres de routage acceptés sont les suivants : * - `liste` (OBLIGATOIRE) : cf. {@see $liste}. */ private function loadRequestParams() { $this->liste = $this->getRequestedListe(); // ex: 'ed591.doctorants.insa@normandie-univ.fr' } /** * Génération du fichier attendu par Sympa pour obtenir les ABONNÉS d'une liste de diffusion. * * Le fichier retourné contient une adresse électronique par ligne. */ public function generateMemberIncludeAction() { $this->loadRequestParams(); $this->listeDiffusionService->setListe($this->liste); $this->listeDiffusionService->init(); $content = $this->listeDiffusionService->createMemberIncludeFileContent(); //$this->handleMemberIncludeNotFoundEmails(); // PAS POSSIBLE : Sympa interroge toutes les heures ! $filename = $this->listeDiffusionService->generateResultFileName('member'); $this->fileService->downloadFileFromContent($content, $filename); } /** * Génération du fichier attendu par Sympa pour obtenir les PROPRIÉTAIRES d'une liste de diffusion. * * Le fichier retourné contient une adresse électronique par ligne. */ public function generateOwnerIncludeAction() { $this->loadRequestParams(); $this->listeDiffusionService->setListe($this->liste); $this->listeDiffusionService->init(); $content = $this->listeDiffusionService->createOwnerIncludeFileContent(); $filename = $this->listeDiffusionService->generateResultFileName('owner'); $this->fileService->downloadFileFromContent($content, $filename); } /** * Gestion des ABONNÉS sans adresse mail. */ private function handleMemberIncludeNotFoundEmails() { $individusSansAdresse = $this->listeDiffusionService->getIndividusSansAdresse(); if (empty($individusSansAdresse)) { return; } $individusAvecAdresse = $this->listeDiffusionService->getIndividusAvecAdresse(); // Envoi d'une notif aux admin tech $to = $this->fetchAdminTechEmails(); $this->notifierService->triggerAbonnesListeDiffusionSansAdresse( $to, $this->liste, $individusAvecAdresse, $individusSansAdresse); } /** * Gestion des PROPRÉTAIRES sans adresse mail. */ private function handleOwnerIncludeNotFoundEmails() { } /** * @return string */ private function getRequestedListe() { $liste = $this->params()->fromRoute('liste'); Assert::notNull($liste, "Aucune liste spécifiée."); return $liste; } /** * @return string[] */ private function fetchAdminTechEmails() { $individus = $this->individuService->getRepository()->findByRole(Role::CODE_ADMIN_TECH); return array_map(function(Individu $i) { return $i->getEmailUtilisateur(); }, $individus); } } No newline at end of file