Commit 026f6fb0a87e67b99844d47e3f1b6ab5e7afbd2d

Authored by Etienne Pallier
1 parent c1dc0859
Exists in master and in 1 other branch dev

Grosse amélioration et rationalisation de la gestion des notifications :

log et/ou email (étape 3) :
		- généralisaiton des types de notifications : log ou/et email
		- notification envoyée systématiquement pour toute action de toute
entité, via afterFilter(),
		et ensuite invalidée éventuellement si pas autorisée

v4.103.3-3.7.9
CHANGES.txt
... ... @@ -13,12 +13,24 @@ CHANGEMENTS
13 13  
14 14  
15 15 -------
16   -11/09/2020 NEWS#3 (v3.7.9.100) :
  16 +23/09/2020 NEWS#4 (v4.103.3-3.7.9) :
  17 +
  18 +- Remaniement complet du système de notification :
  19 + - desormais, on notifie soit par mail, soit par log, soit par les 2 moyens (mail et log)
  20 + - toute action (création, modification, suppression...) faite sur toute entité (Materiel, Document, Suivi, Emprunt, ...)
  21 + peut désormais générer une notificaiton (email, log, ou les 2) à une liste configurable de destinataires prédéfinis (seulement pour les mails)
  22 + - par défaut, seules quelques actions de quelques entités importantes (matériels et documents) envoient des notifications
  23 + - la définition des actions "notifiantes" est configurable indépendamment pour chaque labo
  24 + (comme pour les acls, au niveau du code source, pas encore via la BD, ca viendre plus tard...)
17 25  
18 26 - La sélection d'un "gestionnaire de référence" est désormais obligatoire lors de la validation d'une fiche matériel.
19 27 Par défaut, si c'est un gestionnaire qui valide (et c'est normalement le cas...), c'est lui qui est mis comme "gestionnaire de référence"
20 28 (sauf s'il y en avait déjà un de déclaré avant)
21 29  
  30 +
  31 +-------
  32 +11/09/2020 NEWS#3 (v3.7.9.100) :
  33 +
22 34 - Nouvelle entité "Projet", à laquelle un matériel peut (ou pas) être associé
23 35  
24 36 - Nouveau filtre de la liste des matériels (index) => par "Projet"
... ... @@ -94,8 +106,22 @@ Outre ces changements, voici d'autres changements importants :
94 106 ======= CHANGES =======
95 107  
96 108 -------
97   -18/09/2020 v4.103.0-3.7.9 (EP)
98   - - (e) Grosse amélioration et rationalisation de la gestion des emails (étape 1 sur 2)
  109 +22/09/2020 v4.103.3-3.7.9 (EP)
  110 + - (i) Grosse amélioration et rationalisation de la gestion des notifications : log et/ou email (étape 3) :
  111 + - (i) généralisaiton des types de notifications : log ou/et email
  112 + - (i) notification envoyée systématiquement pour toute action de toute entité, via afterFilter(),
  113 + et ensuite invalidée éventuellement si pas autorisée
  114 +
  115 +-------
  116 +22/09/2020 v4.103.2-3.7.9 (EP)
  117 + - (e) Grosse amélioration et rationalisation de la gestion des emails (étapes 1 et 2) :
  118 + - une seule fonction sendmail(), suppression de sendEmail()
  119 + - meilleur algo général
  120 + - toute entité peut envoyer un email (Materiel, Document, Suivi, Emprunt, ...)
  121 + - on peut définir au niveau de chaque entité, quelle(s) action(s) envoient un mail
  122 + - cette définition est configurable pour chaque labo
  123 + (comme pour les acls, au niveau du code source, pas encore via la BD, ca va viendre plus tard...)
  124 +
99 125  
100 126 -------
101 127 17/09/2020 v4.102.0-3.7.9 (EP)
... ...
PUSH_MODIFS
1 1 #!/usr/bin/env bash
2 2  
3 3 # 1) Mise à jour du code source actuel
  4 +echo
  5 +echo "Mise à jour du code source actuel :"
4 6 ./UPDATE
  7 +echo
5 8  
6   -exit
7 9 # 2) Envoi de mes modifs (sur la branche en cours, a priori master)
  10 +echo
  11 +echo "Voulez-vous vraiment envoyer ces modifications sur le dépot officiel du logiciel LabInvent (o/n) ? [o]"
  12 +read do_it ; [[ -z $do_it ]] && do_it="o"
  13 +#echo $do_it
  14 +[[ $do_it != "o" ]] && exit 0
8 15 git add .
9 16 git commit -m "Ajout de mes modifications"
10 17 git push
11   -
  18 +echo
... ...
README.md
... ... @@ -42,8 +42,8 @@ Logiciel testé et validé sur les configurations suivantes :
42 42  
43 43 --------------------------------------------------------------------------------------------
44 44  
45   -Date: 18/09/2020
46   -Version: 4.103.0-3.7.9
  45 +Date: 22/09/2020
  46 +Version: 4.103.3-3.7.9
47 47  
48 48  
49 49 HISTORIQUE DES CHANGEMENTS DE VERSION : voir le fichier CHANGES.txt (ou la page web /pages/changes)
... ...
src/Controller/AppController.php
... ... @@ -67,6 +67,9 @@ class AppController extends Controller
67 67  
68 68 // - ATTRIBUTS VARIABLES
69 69  
  70 + // Par défaut, genre masculin
  71 + protected $is_masculin = true;
  72 +
70 73 // (EP) Seulement pour les tests
71 74 // Permet à un test de forcer (si true) le re-chargement d'une entité (car modifiée en BD)
72 75 protected static $RELOAD = FALSE;
... ... @@ -192,15 +195,44 @@ class AppController extends Controller
192 195 ];
193 196 */
194 197  
  198 +
  199 +
  200 + /*
  201 + *
  202 + * Tableau (array) des actions autorisées à envoyer des notifications (log et/ou email)
  203 + *
  204 + * 'log' = logger seulement
  205 + * 'mail' => envoyer un mail seulement
  206 + * 'both' = faire les 2 (logger ET envoyer un mail)
  207 + *
  208 + * Hérité par CHAQUE controleur (qui a donc sa propre instance de ce tableau, indépendante des instances des autres controleurs)
  209 + *
  210 + * On l'initialise déjà avec les actions autorisées par défaut, pour tout controleur
  211 + * On le complètera ensuite pour les autres actions
  212 + *
  213 + * protected $notifier_actions = [
  214 + 'add' => 'both',
  215 + 'edit' => 'log',
  216 + 'delete' => 'both',
  217 + // ...
  218 + ];
  219 + *
  220 + * Par défaut => aucune action autorisée
  221 + *
  222 + */
  223 + protected $notifier_actions = [];
  224 +
  225 +
195 226 /*
196   - * Tableau des autorisations pour les actions du controleur
  227 + * Tableau (array) des autorisations pour les actions du controleur
197 228 *
198 229 * Hérité par CHAQUE controleur (qui a donc sa propre instance de ce tableau, indépendante des instances des autres controleurs)
199 230 *
200   - * On l'initialise déjà avec les actions autorisées par défaut
  231 + * On l'initialise déjà avec les actions autorisées par défaut, pour tout controleur
201 232 * On le complètera ensuite pour les autres actions
202   - //protected $is_authorized_action = [];
203   - // Pour tous les controleurs
  233 + *
  234 + * Par défaut => aucune action autorisée
  235 + *
204 236 */
205 237 protected $is_authorized_action = [];
206 238 /*
... ... @@ -294,6 +326,43 @@ class AppController extends Controller
294 326 )
295 327 );
296 328 // $easyACL
  329 +
  330 + const actionNounAndPastVerbs = [
  331 + // C
  332 + 'add' => ['Ajout','ajouté'],
  333 + // R
  334 + 'view' => ['Visualisation (détail)','visualisé'],
  335 + 'index' => ['Visualisation (liste)','visualisé'],
  336 + // U
  337 + 'edit' => ['Modification','modifié'],
  338 + // D
  339 + 'delete' => ['Suppression','supprimé'],
  340 + ];
  341 +
  342 +
  343 + protected function is_vowel($char) { return in_array($char, ['a','e','i','o','u','y']); }
  344 +
  345 + // $form=1 => 'le', 'la', ou "l'"
  346 + // $form=2 => 'du' ou 'de la' ou "de l'"
  347 + // $form=3 => "d'un" ou "d'une"
  348 + protected function getMyArticle($form=1) {
  349 + $first_char_is_vowel = $this->is_vowel(substr($this->getName(),0,1));
  350 + // $form=1 => 'Le', 'La', ou "L'"
  351 + if ($form==1) {
  352 + // Si commence par voyelle => "L'" (L'emprunt, L'utilisateur, L'entité...)
  353 + if ($first_char_is_vowel) return "l'";
  354 + return $this->is_masculin ? "le" : "la";
  355 + }
  356 + // $form=2 => 'du' ou 'de la' ou "de l'"
  357 + elseif ($form==2) {
  358 + if ($first_char_is_vowel) return "de l'";
  359 + return $this->is_masculin ? "du" : "de la";
  360 + }
  361 + // $form=3 => "d'un" ou "d'une"
  362 + else
  363 + return $this->is_masculin ? "d'un" : "d'une";
  364 + }
  365 +
297 366  
298 367 public function d($msg) {
299 368 if ( $this->DEBUG || $this->isLabinventDebugMode() ) pr($msg);
... ... @@ -309,6 +378,28 @@ class AppController extends Controller
309 378 return 'nom';
310 379 }
311 380  
  381 + /*
  382 + * Retourne ['nom','verbe_au_passé'] correspondants à l'action $action
  383 + *
  384 + * ex:
  385 + * => ['Ajout','ajouté'] pour l'action 'add'
  386 + * => ['Modification','modifié'] pour l'action 'edit'
  387 + * ...
  388 + *
  389 + * Actions générales : add, edit, delete, view...
  390 + *
  391 + */
  392 + protected function getActionNounAndPastVerb($action) {
  393 + //if (in_array($action, array_keys($this->actionNounAndPastVerbs))) return $this->actionNounAndPastVerbs[$action];
  394 + if (in_array($action, array_keys($this->actionNounAndPastVerbs))) return $this->actionNounAndPastVerbs[$action];
  395 + if (in_array($action, array_keys(AppController::actionNounAndPastVerbs))) return AppController::actionNounAndPastVerbs[$action];
  396 + // Pas de définition pour cette action
  397 + //return [null,null];
  398 + // par défaut, par exemple 'edit-ion' et 'edit-é' pour action 'edit'
  399 + return [$action.'ion', $action.'é'];
  400 + }
  401 +
  402 +
312 403  
313 404 /*
314 405 * Retourne le matériel courant, c'est à dire :
... ... @@ -326,6 +417,27 @@ class AppController extends Controller
326 417 */
327 418  
328 419 /**
  420 + *
  421 + * (EP 20200922) NEW NOTIFICATIONS MANAGEMENT
  422 + *
  423 + */
  424 + protected function setNotificationAllowedOnActions(array $actions) {
  425 + $this->notifier_actions = $actions;
  426 + }
  427 + protected function isNotifierAction($action) {
  428 + //debug($action);
  429 + //debug($this->notifier_actions);
  430 + return in_array( $action, array_keys($this->notifier_actions) );
  431 + }
  432 + protected function isNotifierActionSendingLog($action) {
  433 + return $this->isNotifierAction($action) && in_array( $this->notifier_actions[$action], ['log','both'] );
  434 + }
  435 + protected function isNotifierActionSendingEmail($action) {
  436 + return $this->isNotifierAction($action) && in_array( $this->notifier_actions[$action], ['mail','both'] );
  437 + }
  438 +
  439 +
  440 + /**
329 441 * (EP 20200525) NEW ACL
330 442 *
331 443 * @param string $action
... ... @@ -753,7 +865,10 @@ class AppController extends Controller
753 865 $condition_result = $condition_on_status_result && $condition_on_belonging_result;
754 866 $this->d("2) Condition globale (a && b) evaluée à :"); $this->d2($condition_result);
755 867 return $condition_result;
756   - }
  868 +
  869 + } // isAuthorizedActionForCurrentUser()
  870 +
  871 +
757 872  
758 873 /*
759 874 * Fonction récursive qui évalue une condition de statut matériel.
... ... @@ -1092,6 +1207,18 @@ class AppController extends Controller
1092 1207 return (int) $this->request->getParam('pass.0');
1093 1208 }
1094 1209  
  1210 +
  1211 + /*
  1212 + * Liste minimum d'entités associées à charger lorsqu'on récupère une entité
  1213 + *
  1214 + * Par défaut => vide
  1215 + *
  1216 + * Peut être surchargé par chaque controleur
  1217 + */
  1218 + protected function getMinimumListOfRelatedEntitiesToLoad() {
  1219 + return [];
  1220 + }
  1221 +
1095 1222 /* (EP 20200428)
1096 1223 *
1097 1224 * Méthode pour optimiser les accès à la BD.
... ... @@ -1108,7 +1235,7 @@ class AppController extends Controller
1108 1235 // PHP7 only
1109 1236 //protected function getEntity($id=null) : Entity {
1110 1237 // PHP>=5
1111   - public function getEntity($id=null, $WITH_RELATED_MATERIEL=false) {
  1238 + public function getEntity($id=null, $WITH_RELATED_MATERIEL=false, $WITH_ASSOCIATED_ENTITIES=true) {
1112 1239 // Si pas d'id => exception (stop)
1113 1240 //assert($this->e_id>0);
1114 1241 if (!$this->e_id && !$id) throw new \Exception(__("cette methode doit etre appelée avec un id déjà positionné !!!"));
... ... @@ -1143,7 +1270,10 @@ class AppController extends Controller
1143 1270 */
1144 1271 //ex: if (! $this->e) $this->e = $this->Materiels->get($this->e_id);
1145 1272 //$this->e = $this->$model->get($this->e_id);
1146   - $related_entities = $WITH_RELATED_MATERIEL ? ['Materiels']:[];
  1273 + //$related_entities = $WITH_RELATED_MATERIEL ? ['Materiels']:[];
  1274 + $related_entities = [];
  1275 + if ($WITH_ASSOCIATED_ENTITIES) $related_entities = $this->getMinimumListOfRelatedEntitiesToLoad();
  1276 + if ($WITH_RELATED_MATERIEL) $related_entities[] = 'Materiels';
1147 1277 $this->e = $this->$model->get($id, ['contain'=>$related_entities]);
1148 1278 $this->e_id = $this->e->id;
1149 1279 }
... ... @@ -1834,6 +1964,7 @@ class AppController extends Controller
1834 1964 */
1835 1965  
1836 1966 } // beforeFilter()
  1967 +
1837 1968  
1838 1969 /**
1839 1970 * Add or Edit method (do either add() or edit())
... ... @@ -2037,6 +2168,9 @@ class AppController extends Controller
2037 2168  
2038 2169 public function afterFilter(Event $event)
2039 2170 {
  2171 +
  2172 + parent::afterFilter($event);
  2173 +
2040 2174 $this->myDebug("step ?? (general): AppController.afterFilter()");
2041 2175 // Tout le temps 'index', why ??N
2042 2176 //debug($this->request->getAttribute('params')['action']);
... ... @@ -2048,6 +2182,34 @@ class AppController extends Controller
2048 2182 else if ($this->request->getAttribute('params')['action'] != 'creer')
2049 2183 $this->request->getSession()->write("retourForm1", false);
2050 2184 //exit;
  2185 +
  2186 + /*
  2187 + * A la fin de l'action, envoi d'une notification
  2188 + * - ssi entité définie
  2189 + * ET
  2190 + * - ssi autorisée
  2191 + * ET
  2192 + * - pour 'add' et 'edit' : seulement si il y eu un POST de data
  2193 + */
  2194 + //debug($this->e);
  2195 + //if ($this->e) $emails = $this->sendNotificationForEntityAction($this->e);
  2196 + //$action = $this->request->getAttribute('params')['action'];
  2197 + if (
  2198 + // Pour toutes les actions autres que 'add' ou 'edit'
  2199 + ! in_array($this->a,['add','edit'])
  2200 + ||
  2201 + // Ou bien pour les actions 'add' ou 'edit' après un POST (pas avant)
  2202 + $this->request->is(['post','patch','put'])
  2203 + //( in_array($this->a,['add','edit']) && $this->request->is(['post','patch','put']) )
  2204 + ) {
  2205 + //debug("hi"); exit;
  2206 + //debug($this->e); exit;
  2207 + //$emails = $this->sendNotificationForEntityAction($this->e);
  2208 + $emails = $this->sendNotificationForEntityAction();
  2209 + }
  2210 + //debug($emails);
  2211 + //exit;
  2212 +
2051 2213 }
2052 2214  
2053 2215 /**
... ... @@ -2330,8 +2492,9 @@ class AppController extends Controller
2330 2492  
2331 2493  
2332 2494 // "le materiel", "le suivi", "l'emprunt", "la catégorie"...
  2495 + // Par défaut
2333 2496 public function getArticle() { return "Le "; }
2334   -
  2497 +
2335 2498 static function isLabinventDebugMode()
2336 2499 {
2337 2500 return TableRegistry::getTableLocator()->get('Configurations')->find()->first()->mode_debug;
... ... @@ -2351,6 +2514,10 @@ class AppController extends Controller
2351 2514 *
2352 2515 */
2353 2516 function ilog($msg=null) {
  2517 +
  2518 + // true => n'envoie pas de log
  2519 + $DEBUG = true;
  2520 +
2354 2521 //$controller = $this->request->getParam('controller');
2355 2522 //$action = $this->getActionPassed();
2356 2523 $role = $this->getUserRole();
... ... @@ -2364,7 +2531,9 @@ class AppController extends Controller
2364 2531 //debug("$url fait par $user ($role) ($msg)");
2365 2532 //$this->log("$url fait par $user ($role). $msg", 'debug');
2366 2533 //Log::write('info', "$url fait par $user ($role). $msg");
2367   - $this->log("$url fait par $user ($role). $msg\n", 'info');
  2534 + $msg = "$url fait par $user ($role) - $msg\n";
  2535 + $DEBUG && debug($msg);
  2536 + (!$DEBUG) && $this->log($msg, 'info');
2368 2537  
2369 2538 /* Autres formes possibles
2370 2539  
... ... @@ -2731,21 +2900,31 @@ class AppController extends Controller
2731 2900 //public function sendmail(\App\Model\Entity $entity, $mode=3, $subject = null, $msg = null)
2732 2901 //public function sendmail(\App\Model\Entity\Materiel $entity, $mode=3, $subject = null, $msg = null)
2733 2902 // PHP5 :
2734   - public function sendmail($entity, $mode=3, $subject = null, $msg = null)
2735   - {
2736   -
2737   - $DEBUG = false;
  2903 + // @obsolete
  2904 + public function sendmail($entity, $mode=3, $subject = null, $msg = null) {
  2905 + $this->sendNotificationForEntityAction($mode,$subject,$msg);
  2906 + }
  2907 + public function sendNotificationForEntityAction($mode=3, $subject = null, $msg = null) {
  2908 + //return null;
2738 2909  
2739   - // Si les deux cases "Activer l'envoi des mails.." sont décochées, on se fatigue pas à exécuter la fonction
2740   - $configuration = $this->confLabinvent;
2741   - if (!$configuration->envoi_mail && !$configuration->envoi_mail_guests) return null;
  2910 + // true => n'envoie pas de notif
  2911 + $DEBUG = true;
  2912 +
  2913 + // Entité (Entity)
  2914 + // Si pas d'entité définie => return
  2915 + $entity = $this->e;
  2916 + if ( !$entity ) return null;
  2917 +
  2918 + // Action
  2919 + //$action = $this->request->getAttribute('params')['action']; // add or edit or delete or ...
  2920 + $action = $this->a;
2742 2921  
2743   - // Si l'action n'est pas autorisée à déclencher un mail, on quitte
2744   - $action = $this->request->getAttribute('params')['action']; // add or edit or delete or ...
  2922 + // Si l'action n'est pas autorisée à déclencher une notification => on quitte
2745 2923 // $this pointe sur le controleur en cours qui a appelé sendmail, par exemple MaterielsController ou DocuentsController...
2746 2924 // Donc c'est la methode is_action_with_email() de ce controleur spécifique qui est appelée
2747   - if (! in_array($action, $this->get_actions_with_email()) ) return null;
2748   -
  2925 + //if (! in_array($action, $this->get_actions_with_email()) ) return null;
  2926 + if ( !$this->isNotifierAction($action) ) return null;
  2927 + //debug("notify"); exit;
2749 2928 /*
2750 2929 $all_actions_autorisees = [
2751 2930 'Materiel' => ['add', 'delete'],
... ... @@ -2785,17 +2964,112 @@ class AppController extends Controller
2785 2964  
2786 2965 // ex: 'Etienne Pallier'
2787 2966 $acteur = $_SESSION['Auth']['User']['givenname'][0] . ' ' . $_SESSION['Auth']['User']['sn'][0];
2788   -
2789   - $materiel = null;
  2967 + $user = $this->getCurrentUserName();
  2968 +
  2969 + $action_noun_and_verb = $this->getActionNounAndPastVerb($action);
  2970 + $action_noun = $action_noun_and_verb[0];
  2971 + $action_verb = $action_noun_and_verb[1];
  2972 + //$entity_type = $this->getEntityTypeName();
  2973 + $entity_type = strtolower( substr($this->getName(),0,-1) );
  2974 + $article_le = $this->getMyArticle(1);
  2975 + $article_dun = $this->getMyArticle(3);
  2976 + $id = $entity->id;
  2977 +
  2978 + $materiel = null;
  2979 +
  2980 +
  2981 +
  2982 + /*
  2983 + * 2) LOG
  2984 + */
  2985 +
  2986 + // ex: "Matériel ajouté = 'toto' (id=15)"
  2987 + // ex: "Document modifié = 'doc-toto' (id=112)"
  2988 + // ex: "Utilisateur connecté = 'Pierre Durand' (id=112)"
  2989 + // ex: "Utilisateur déconnecté = 'Pierre Durand' (id=112)"
  2990 + $msglog = "$entity_type $action_verb = '$entity' (id=$id)";
  2991 + //debug($msglog);
  2992 + //(!$DEBUG) &&
  2993 + //$this->isNotifierActionSendingLog($action) && $this->ilog("$entity_name $action_verb = '$entity' (id=$id)");
  2994 + $this->isNotifierActionSendingLog($action) && $this->ilog($msglog);
  2995 +
2790 2996  
2791 2997  
2792 2998 /*
2793   - * 2) CRÉATION DU MAIL (sujet et body)
  2999 + * 3) CRÉATION DU MAIL (sujet et body)
2794 3000 *
2795 3001 * On détermine le message et le sujet du mail en fonction de l'action effectuee
2796 3002 *
2797 3003 */
2798 3004  
  3005 + // MESSAGE GÉNÉRIQUE
  3006 +
  3007 + // Sujet :
  3008 +
  3009 + $subject = $subject ? $subject : "$action_noun $article_dun $entity_type";
  3010 + debug($subject);
  3011 +
  3012 + // Message (body) :
  3013 +
  3014 + // - (1) TOUS : User a fait telle action (+url)
  3015 + $msg_mail = $msg;
  3016 + $msg_mail .= "$user a $action_verb $article_le $entity_type '$entity'";
  3017 + // (EP) Ajout de l'url (ou id) du materiel
  3018 + $msg_mail .= $action=='delete' ? " (id=$id)" : " ($host/materiels/view/$id)";
  3019 + //$msg .= "\n\nURL de la fiche : $host/materiels/view/{$materiel->id}";
  3020 + // $msg .= "\n\n";
  3021 +
  3022 + // - (2) Matos (direct ou associé) only : On ajoute quelques informations sur le matériel : domaine, catégorie, description
  3023 + // Entités (Entity) associées à une entité Materiel (1-N)
  3024 + $materiel = $entity;
  3025 + $ENTITY_TYPE_LINKED = false;
  3026 + $entity_types_linked_to_materiel = ['Suivi', 'Emprunt', 'Document'];
  3027 + foreach ($entity_types_linked_to_materiel as $Entity_type_linked)
  3028 + // Si c'est une entité liée et qu'elle a bien un Materiel associé
  3029 + // (par exemple pour Document, ce n'est pas forcément le cas car il peut être associé à un Suivi et non un Materiel)
  3030 + if ( is_a($entity, $Entity_type_linked) && $entity->materiel_id ) {
  3031 + $materiel = $entity->Materiel;
  3032 + $ENTITY_TYPE_LINKED = true;
  3033 + break;
  3034 + }
  3035 + if ($entity instanceof Materiel || $ENTITY_TYPE_LINKED) {
  3036 + //$materiel = $entity;
  3037 + $msg_more = '';
  3038 + $fields = [
  3039 + 'sur_categorie_id' => ['sur_category', 'Domaine'],
  3040 + 'categorie_id' => ['category', 'Catégorie'],
  3041 + 'sous_categorie_id' => ['sous_category', 'Sous-catégorie'],
  3042 + 'description' => ['hasnot!', 'Description']
  3043 + ];
  3044 + foreach ($fields as $fname=>$attrs) if ($materiel->$fname) {
  3045 + $val = $materiel->has($attrs[0]) ? $materiel->{$attrs[0]}->nom : $materiel->$fname;
  3046 + $msg_more .= "\n\n- $attrs[1] : " . $val;
  3047 + }
  3048 + if ($msg_more) $msg_mail .= "\n\nAttributs du matériel : $msg_more";
  3049 + }
  3050 +
  3051 + // - (3) Matos only (sauf delete, TBA et archive) : Veuillez vérifier...
  3052 + $actions_no_need_to_be_checked = ['delete', 'statusTobearchived', 'statusArchived'];
  3053 + if ( $entity instanceof Materiel && !in_array($action,$actions_no_need_to_be_checked) )
  3054 + $msg_mail .= "\n\nVeuillez vérifier et compléter si besoin la fiche correspondante.";
  3055 +
  3056 + // - (4) TOUS : Vous recevez ce message car... (raison)
  3057 + //if ($entity != null) {
  3058 + $msg_mail .= "\n\nVous recevez ce message car";
  3059 + $raison = " vous êtes concerné(e) par cette action effectuée sur l'inventaire des matériels du laboratoire";
  3060 + $raison .= "\n\n(vous êtes l'utilisateur du matériel, ou bien le gestionnaire, ou encore le responsable thématique, métier ou projet).";
  3061 + $msg_mail .= $raison;
  3062 + //}
  3063 + debug($msg_mail);
  3064 +
  3065 + // Par défaut
  3066 + /*
  3067 + $subject = "Action \"$action\" sur un matériel";
  3068 + $msg = "$acteur a effectué l'action \"$action\" sur le matériel \"$nom_materiel\"";
  3069 + */
  3070 +
  3071 + exit;
  3072 +
2799 3073 /*
2800 3074 * - mail pour un MATERIEL
2801 3075 */
... ... @@ -2989,18 +3263,26 @@ class AppController extends Controller
2989 3263 * ... etc ... (il faut qu'on soit plus précis)
2990 3264 */
2991 3265  
2992   - // Pas de matériel défini => pas de mail (pas de bras, pas de chocolat) !
2993   - if ($materiel == null) return null;
2994   -
  3266 +
2995 3267  
2996 3268 /*
2997   - * 3) DESTINATAIRES : on construit la liste des destinataires
  3269 + * 4) DESTINATAIRES du mail : on construit la liste des destinataires
2998 3270 */
2999   -
  3271 +
  3272 + // Si l'action n'est pas autorisée à envoyer un mai => on quitte
  3273 + if (! $this->isNotifierActionSendingEmail($action) ) return null;
  3274 +
  3275 + // Si les deux cases "Activer l'envoi des mails.." sont décochées, on se fatigue pas à exécuter la fonction
  3276 + $configuration = $this->confLabinvent;
  3277 + if (!$configuration->envoi_mail && !$configuration->envoi_mail_guests) return null;
  3278 +
  3279 + // Pas de matériel défini => pas de mail (pas de bras, pas de chocolat) !
  3280 + if ($materiel == null) return null;
  3281 +
3000 3282 $mailList = [];
3001 3283  
3002 3284 /*
3003   - * 3a) Envoi général
  3285 + * 4a) Envoi général
3004 3286 *
3005 3287 * Si l'envoi général est activé, on ajoute les mails des personnes concernées :
3006 3288 * - le proprio (l'utilisateur) du matériel (sauf s'il est l'acteur de l'action)
... ... @@ -3046,17 +3328,19 @@ class AppController extends Controller
3046 3328 */
3047 3329 $resp_mails = [];
3048 3330 $groups_fk = [ 'groupes_metier_id', 'groupes_thematique_id' ];
3049   - foreach ($groups_fk as $group_fk) if ($materiel->$group_fk) {
3050   - //$mailsRespMetier = TableRegistry::getTableLocator()->get('Users')->find()
3051   - $resp_mails[$group_fk] = TableRegistry::getTableLocator()->get('Users')->find()
3052   - ->select('email')
3053   - ->where([
3054   - 'role =' => 'Responsable',
3055   - "$group_fk =" => $materiel->$group_fk
3056   - ])
3057   - ->toArray();
  3331 + foreach ($groups_fk as $group_fk) {
  3332 + $resp_mails[$group_fk] = [];
  3333 + if ($materiel->$group_fk)
  3334 + //$mailsRespMetier = TableRegistry::getTableLocator()->get('Users')->find()
  3335 + $resp_mails[$group_fk] = TableRegistry::getTableLocator()->get('Users')->find()
  3336 + ->select('email')
  3337 + ->where([
  3338 + 'role =' => 'Responsable',
  3339 + "$group_fk =" => $materiel->$group_fk
  3340 + ])
  3341 + ->toArray();
3058 3342 }
3059   - $DEBUG && debug($resp_mails);
  3343 + //$DEBUG && debug($resp_mails);
3060 3344 //exit;
3061 3345 /*
3062 3346 if ($materiel->groupes_metier_id) {
... ... @@ -3084,7 +3368,7 @@ class AppController extends Controller
3084 3368 //$resp_mails = array_values($resp_mails);
3085 3369 //$resp_mails['groupes_metier_id']=[]; $resp_mails['groupes_thematique_id']=[];
3086 3370 $resp_mails = array_merge($resp_mails['groupes_metier_id'], $resp_mails['groupes_thematique_id']);
3087   - $DEBUG && debug($resp_mails);
  3371 + //$DEBUG && debug($resp_mails);
3088 3372 foreach ($resp_mails as $resp_mail) $mailList[] = $resp_mail['email'];
3089 3373 //exit;
3090 3374 /*
... ... @@ -3116,7 +3400,7 @@ class AppController extends Controller
3116 3400 } // si envoi général activé
3117 3401  
3118 3402 /*
3119   - * 3b) Envoi à la liste spécifique
  3403 + * 4b) Envoi à la liste spécifique
3120 3404 *
3121 3405 * Si l'envoi à la liste spécifique est activé,
3122 3406 * on ajoute simplement TOUS les mails de cette liste,
... ... @@ -3142,7 +3426,7 @@ class AppController extends Controller
3142 3426 }
3143 3427  
3144 3428 /*
3145   - * 3c) On supprime
  3429 + * 4c) On supprime
3146 3430 * - les doublons éventuels
3147 3431 * ainsi que
3148 3432 * - l'auteur de l'action (puisqu'il est déjà au courant)
... ... @@ -3158,12 +3442,12 @@ class AppController extends Controller
3158 3442 $mailList = array_map('strtolower', $mailList);
3159 3443 // - on supprime les doublons
3160 3444 $mailList = array_unique($mailList);
3161   - $DEBUG && debug($mailList);
  3445 + //$DEBUG && debug($mailList);
3162 3446 // - on supprime l'auteur de l'action le cas échéant
3163 3447 //if ($DEBUG) debug($this->u->email);
3164 3448 $found = array_search(strtolower($this->u->email), $mailList);
3165 3449 //$found = array_search('nathalie.baby@irap.omp.eu', $mailList);
3166   - $DEBUG && debug($found);
  3450 + //$DEBUG && debug($found);
3167 3451 if ($found !== false) unset($mailList[$found]);
3168 3452 // Eventuellement, pour renuméroter (supprime les indices manquants)
3169 3453 sort($mailList);
... ... @@ -3207,7 +3491,7 @@ class AppController extends Controller
3207 3491  
3208 3492  
3209 3493 /*
3210   - * 5) ENVOI : enfin, on envoie le mail à toute la liste des destinataires
  3494 + * 5) ENVOI DU MAIL : enfin, on envoie le mail à toute la liste des destinataires
3211 3495 */
3212 3496  
3213 3497 // On dédoublonne la liste des mails pour éviter de spammer les gens, non mais !
... ... @@ -3229,7 +3513,7 @@ class AppController extends Controller
3229 3513 $role = "car vous etes dans la liste spécifique des emails de LabInvent.";
3230 3514 $role .= "\n\nPour faire retirer votre mail de cette liste, veuillez contacter un super-administrateur.";
3231 3515 */
3232   - $role = "car vous êtes concerné(e) par cette action effectuée sur l'inventaire des matériels du laboratoire.";
  3516 + $role = "car vous êtes concerné(e) par cette action effectuée sur l'inventaire des matériels du laboratoire";
3233 3517 $role .= "\n\n(vous êtes l'utilisateur du matériel, ou bien le gestionnaire, ou encore le responsable thématique, métier ou projet).";
3234 3518 /* (EP 13/319) : à quoi sert toute cette suite du texte du mail ???
3235 3519 * Ca sent le bon vieux copier-coller sans réfléchir...
... ... @@ -3258,7 +3542,7 @@ class AppController extends Controller
3258 3542 //debug($message); exit;
3259 3543 //debug($mode);
3260 3544  
3261   - switch($mode) {
  3545 + if (! $DEBUG) switch($mode) {
3262 3546  
3263 3547 //si le mode 1 est sélectionné c'est un envoi de mail avec ajout d'une photo
3264 3548 //explique le document qui a été ajouté, et le met en pièce jointe
... ...
src/Controller/DocumentsController.php
... ... @@ -20,6 +20,11 @@ class DocumentsController extends AppController
20 20 // Formats autorisés pour photo
21 21 var $photo_formats = ['png','jpg','jpeg'];
22 22  
  23 + // @override parent
  24 + protected $actionNounAndPastVerbs = [
  25 + 'mailDevis' => ['Partage','partagé'],
  26 + ];
  27 +
23 28 // private pour qu'elle ne puisse pas être appelée via url comme une action
24 29 private function is_photo_type_from_extension($doc) {
25 30 return in_array($doc->type_doc, $this->photo_formats);
... ... @@ -31,6 +36,31 @@ class DocumentsController extends AppController
31 36 //@Override parent
32 37 protected function setAuthorizations() {
33 38  
  39 +
  40 + /*
  41 + * a) Actions de ce controleur qui enverront des notifications (log et/ou email)
  42 + *
  43 + * 'log' = logger seulement
  44 + * 'mail' => envoyer un mail seulement
  45 + * 'both' = faire les 2 (logger ET envoyer un mail)
  46 + *
  47 + */
  48 + $this->setNotificationAllowedOnActions([
  49 + 'add' => 'both',
  50 + 'edit' => 'log',
  51 + 'delete' => 'both',
  52 + // ...
  53 + ]);
  54 + /*
  55 + $this->setNotificationAllowedOnActions([
  56 + 'add', 'edit', 'delete',
  57 + 'view',
  58 + // ...
  59 + ]);
  60 + */
  61 +
  62 + // b) Règles d'accès (ACLs)
  63 +
34 64 // Action 'add' (ajout d'une nouvelle entité) : statut quelconque mais doit appartenir au user
35 65 // Proprio only
36 66 $this->setAuthorizationsForAction('add', [0,1], [
... ... @@ -928,15 +958,6 @@ class DocumentsController extends AppController
928 958  
929 959 }
930 960  
931   - // Actions autorisées à envoyer un email
932   - //@Override parent
933   - protected function get_actions_with_email() {
934   - return [
935   - 'add', 'edit', 'delete',
936   - // ...
937   - ];
938   - }
939   -
940 961  
941 962 public function ficheMetrologique($id)
942 963 {
... ...
src/Controller/FournisseursController.php
... ... @@ -143,11 +143,7 @@ class FournisseursController extends AppController
143 143 public function edit($id = null)
144 144 {
145 145 $fournisseur = $this->Fournisseurs->get($id);
146   - if ($this->request->is([
147   - 'patch',
148   - 'post',
149   - 'put'
150   - ])) {
  146 + if ($this->request->is(['patch','post','put'])) {
151 147 $fournisseur = $this->Fournisseurs->patchEntity($fournisseur, $this->request->getData());
152 148 if ($this->Fournisseurs->save($fournisseur)) {
153 149 $this->Flash->success(__('Le fournisseur a bien été édité.'));
... ...
src/Controller/MaterielsController.php
... ... @@ -53,6 +53,18 @@ class MaterielsController extends AppController {
53 53 );
54 54  
55 55  
  56 + // @override parent
  57 + protected $actionNounAndPastVerbs = [
  58 + 'statusCreated' => ['Dé-validation','dé-validé'],
  59 + 'statusValidated' => ['Validation','validé'],
  60 + //TODO: spécial
  61 + 'statusTobearchived' => ["Demande d'archivage","demandé l'archivage", '', "d'un"],
  62 + 'statusValidated' => ['Archivage','archivé'],
  63 + 'setLabelIsPlaced' => ["Positionnement d'étiquette","posé l'étiquette", 'sur'],
  64 + 'printLabelRuban' => ["Impression de l'étiquette", "imprimé l'étiquette", "d'un", 'sur'],
  65 + ];
  66 +
  67 +
56 68 // EP 08/2017
57 69 // protected $easyACL = array(
58 70 const OLD_easyACL = array(
... ... @@ -173,6 +185,15 @@ class MaterielsController extends AppController {
173 185 }
174 186  
175 187  
  188 + // @override parent
  189 + // Default 'contain'
  190 + protected function getMinimumListOfRelatedEntitiesToLoad() {
  191 + return [
  192 + 'SurCategories', 'Categories', 'SousCategories'
  193 + ];
  194 + }
  195 +
  196 +
176 197 /*
177 198 * Cette méthode est appelée pendant l’event Controller.initialize qui se produit avant chaque action du controller.
178 199 * C’est un endroit pratique pour vérifier le statut d’une session ou les permissions d’un utilisateur.
... ... @@ -261,6 +282,167 @@ class MaterielsController extends AppController {
261 282 return 'designation';
262 283 }
263 284  
  285 +
  286 + /*
  287 + * @Override
  288 + *
  289 + * Initialisation des autorisations PAR DÉFAUT (générales à tous les labos) pour les actions de ce controleur
  290 + *
  291 + */
  292 + protected function setAuthorizations() {
  293 + //debug("GENERIC!");
  294 +
  295 + /*
  296 + * a) Actions de ce controleur qui enverront des notifications (log et/ou email)
  297 + *
  298 + * 'log' = logger seulement
  299 + * 'mail' => envoyer un mail seulement
  300 + * 'both' = faire les 2 (logger ET envoyer un mail)
  301 + *
  302 + */
  303 + $this->setNotificationAllowedOnActions([
  304 + 'add' => 'both',
  305 + 'edit' => 'log',
  306 + 'delete' => 'both',
  307 + //'view',
  308 + 'statusCreated' => 'log',
  309 + 'statusTobearchived' => 'both',
  310 + 'statusValidated' => 'both',
  311 + 'statusArchived' => 'both',
  312 + // ...
  313 + ]);
  314 + /*
  315 + $this->setNotificationAllowedOnActions([
  316 + 'add', 'edit', 'delete',
  317 + //'view',
  318 + 'statusCreated', 'statusTobearchived', 'statusValidated', 'statusArchived',
  319 + // ...
  320 + ]);
  321 + */
  322 +
  323 + // b) Règles d'accès (ACLs)
  324 +
  325 + // - Action 'add' (ajout d'un nouveau matériel) => autorisé pour tous
  326 + //$this->setAuthorizationsForAction('add', 0);
  327 + $this->setAuthorizationsForAction('add (créer)', 0);
  328 + //$this->setAuthorizationsForAction('view', 0);
  329 +
  330 + // - Action 'add' (ajout d'un nouveau matériel par copie d'un autre)
  331 + $this->setAuthorizationsForAction('add_by_copy (ajout par copie)', ['CREATED',0], [
  332 + 'user' => ['CREATED',1],
  333 + //'resp' => ['CREATED',0],
  334 + //'resp' => 'default',
  335 + //$admin = 'default',
  336 + //$super = 'default'
  337 + ]);
  338 +
  339 + /* Actions autorisées par défaut par AppController : index et view
  340 + // - Action 'index' (affichage de la liste des matériels)
  341 + $this->setAuthorizationsForAction('index',
  342 + $default = [0,0] // = + vue spécialisée PAR statut
  343 + //$user = 'default', // vue simplifiée tout statut confondu (sauf ARCHIVED)
  344 + //$resp = 'default',
  345 + //$admin = 'default',
  346 + //$super = 'default'
  347 + );
  348 + // - Action 'view' (vue détaillée d'un matériel)
  349 + $this->setAuthorizationsForAction('view',
  350 + $default = [0,0]
  351 + //$user = 'default',
  352 + //$resp = 'default',
  353 + //$admin = 'default',
  354 + //$super = 'default' // + champs techniques
  355 + );
  356 + */
  357 +
  358 + // - Action 'edit' (modif d'un matériel)
  359 + $this->setAuthorizationsForAction('edit (modifier)', ['CREATED',0], [
  360 + 'user' => ['CREATED',1],
  361 + 'resp' => 'user',
  362 + //'resp' => -1,
  363 + //'resp' => 0,
  364 + //'resp' => ['CREATED',1],
  365 + //$admin = 'default',
  366 + //$super = 'default' // + champs techniques
  367 + ]);
  368 +
  369 + // Action 'delete' (suppression d'un matériel)
  370 + $this->setAuthorizationsForAction('delete (supprimer)', ['CREATED',1]);
  371 +
  372 + // Action 'devalidate' ou 'invalidate' (repasser le matériel au statut 'CREATED', c'est à dire le dé-valider ou l'invalider)
  373 + // (VALIDATED ou TBA ou ARCHIVED) => CREATED
  374 + //$this->setAuthorizationsForAction('devalidate',
  375 + $this->setAuthorizationsForAction('statusCreated (dévalider)', ['NOT CREATED',0], [
  376 + 'user' => -1, // PAS AUTORISÉ
  377 + 'resp' => ['NOT CREATED',1]
  378 + ]);
  379 +
  380 + // Action 'updgrade' (avancement du statut d'un matériel)
  381 + // CREATED => VALIDATED => TBA => ARCHIVED
  382 + /*
  383 + $this->setAuthorizationsForAction('upgrade', ['NOT ARCHIVED',0], [ // En fait, l'action fait juste passer au statut "suivant"
  384 + //$default = ['PREVIOUS',0], // le matériel doit avoir le statut "précédent" du statut actuel
  385 + 'user' => ['VALIDATED',1], // SEULEMENT l'action "demande d'archivage"
  386 + //$resp = ['VALIDATED',1] // SEULEMENT l'action "demande d'archivage"
  387 + //'resp' => 'Utilisateur'
  388 + 'resp' => 'user'
  389 + ]);
  390 + */
  391 + // Action 'updgrade' (avancement du statut d'un matériel)
  392 + // - Validation d'un materiel (passe à VALIDATED) : CREATED => VALIDATED
  393 + $this->setAuthorizationsForAction('statusValidated (valider)', ['CREATED',0], [
  394 + 'user' => -1, // interdit
  395 + 'resp' => -1 // interdit
  396 + ]);
  397 + // - Demande d'archivage : VALIDATED => TBA
  398 + $this->setAuthorizationsForAction("statusTobearchived (demander l'archivage)", ['VALIDATED',0], [
  399 + //$user = ['default',1],
  400 + 'user' => ['VALIDATED',1],
  401 + //$resp = ['default',1]
  402 + //$resp = ['VALIDATED',1]
  403 + 'resp' => 'user'
  404 + ]);
  405 + // - Archivage : TBA => ARCHIVED
  406 + $this->setAuthorizationsForAction('statusArchived (archiver)', ['TOBEARCHIVED',0], [
  407 + 'user' => -1, // interdit
  408 + 'resp' => -1 // interdit
  409 + ]);
  410 +
  411 + // Action 'printLabelRuban' (impression d'une étiquette)
  412 + $this->setAuthorizationsForAction('printLabelRuban (imprimer étiquette)', ['VALIDATED && conf.hasPrinter',0] );
  413 + $this->setAuthorizationsForAction('setLabelIsPlaced (déclarer étiquette collée)', ['VALIDATED && conf.hasPrinter',0] );
  414 + $this->setAuthorizationsForAction('setLabelIsNotPlaced', ['VALIDATED && conf.hasPrinter',0] );
  415 + /*
  416 + $this->setAuthorizationsForAction('setLabelIsPlaced', 0); // autorisé sans condition
  417 + $this->setAuthorizationsForAction('setLabelIsNotPlaced', 0); // autorisé sans condition
  418 + */
  419 +
  420 + // Action 'execActions'
  421 + $this->setAuthorizationsForAction('execActions', 0, [ // par défaut autorisé sans condition
  422 + // sauf pour user et resp
  423 + 'user' => -1, // PAS AUTORISÉ
  424 + 'resp' => -1 // PAS AUTORISÉ
  425 + ]);
  426 + // Action 'export'
  427 + $this->setAuthorizationsForAction('export', 0, [// autorisé sans condition
  428 + 'user' => -1 // interdit
  429 + ]);
  430 + $this->setAuthorizationsForAction('getDateGarantie', 0); // autorisé sans condition
  431 +
  432 + /*
  433 + // Action 'ficheMateriel'
  434 + $this->setAuthorizationsForAction('createDocFicheMateriel', 0);
  435 + // Action 'ficheMaterielPdf'
  436 + // DOMPDF
  437 + $this->setAuthorizationsForAction('createDocFicheMaterielPdf', 0);
  438 + */
  439 +
  440 + //debug($this->is_authorized_action);exit;
  441 +
  442 + } // _setAuthorizations()
  443 +
  444 +
  445 +
264 446 /*
265 447 * Méthode de définition des autorisations SPÉCIFIQUES au laboratoire IRAP
266 448 *
... ... @@ -282,8 +464,18 @@ class MaterielsController extends AppController {
282 464 // 1) On appelle d'abord la méthode générale
283 465 $this->setAuthorizations();
284 466  
285   - // 2) Puis on fait nos petites règles locales pour notre labo à nous tout seul
  467 + // 2) Puis on fait nos petites règles locales pour notre petit labo à nous tout seul
  468 +
286 469 /*
  470 + // a) Adaptation des règles de notification
  471 + // Actions de ce controleur qui enverront des notifications (emails)
  472 + $this->setNotificationAllowedOnActions([
  473 + 'add', 'edit', 'delete',
  474 + 'statusCreated', 'statusTobearchived', 'statusValidated', 'statusArchived',
  475 + // ...
  476 + ]);
  477 +
  478 + // b) Adaptation des règles d'accès (ACLs)
287 479 // - Adaptation de la règle pour "ajout par copie"
288 480 $this->setAuthorizationsForAction('add_by_copy', '', ['CREATED',0], [
289 481 'user' => ['CREATED',1],
... ... @@ -374,136 +566,6 @@ class MaterielsController extends AppController {
374 566 return in_array($status, array_keys(self::statuses));
375 567 }
376 568  
377   - /*
378   - * @Override
379   - *
380   - * Initialisation des autorisations PAR DÉFAUT (générales à tous les labos) pour les actions de ce controleur
381   - *
382   - */
383   - protected function setAuthorizations() {
384   - //debug("GENERIC!");
385   -
386   - // Action 'add' (ajout d'un nouveau matériel) => autorisé pour tous
387   - //$this->setAuthorizationsForAction('add', 0);
388   - $this->setAuthorizationsForAction('add (créer)', 0);
389   - //$this->setAuthorizationsForAction('view', 0);
390   -
391   - // Action 'add' (ajout d'un nouveau matériel par copie d'un autre)
392   - $this->setAuthorizationsForAction('add_by_copy (ajout par copie)', ['CREATED',0], [
393   - 'user' => ['CREATED',1],
394   - //'resp' => ['CREATED',0],
395   - //'resp' => 'default',
396   - //$admin = 'default',
397   - //$super = 'default'
398   - ]);
399   -
400   - /* Actions autorisées par défaut par AppController : index et view
401   - // - Action 'index' (affichage de la liste des matériels)
402   - $this->setAuthorizationsForAction('index',
403   - $default = [0,0] // = + vue spécialisée PAR statut
404   - //$user = 'default', // vue simplifiée tout statut confondu (sauf ARCHIVED)
405   - //$resp = 'default',
406   - //$admin = 'default',
407   - //$super = 'default'
408   - );
409   - // - Action 'view' (vue détaillée d'un matériel)
410   - $this->setAuthorizationsForAction('view',
411   - $default = [0,0]
412   - //$user = 'default',
413   - //$resp = 'default',
414   - //$admin = 'default',
415   - //$super = 'default' // + champs techniques
416   - );
417   - */
418   -
419   - // Action 'edit' (modif d'un matériel)
420   - $this->setAuthorizationsForAction('edit (modifier)', ['CREATED',0], [
421   - 'user' => ['CREATED',1],
422   - 'resp' => 'user',
423   - //'resp' => -1,
424   - //'resp' => 0,
425   - //'resp' => ['CREATED',1],
426   - //$admin = 'default',
427   - //$super = 'default' // + champs techniques
428   - ]);
429   -
430   - // Action 'delete' (suppression d'un matériel)
431   - $this->setAuthorizationsForAction('delete (supprimer)', ['CREATED',1]);
432   -
433   - // Action 'devalidate' ou 'invalidate' (repasser le matériel au statut 'CREATED', c'est à dire le dé-valider ou l'invalider)
434   - // (VALIDATED ou TBA ou ARCHIVED) => CREATED
435   - //$this->setAuthorizationsForAction('devalidate',
436   - $this->setAuthorizationsForAction('statusCreated (dévalider)', ['NOT CREATED',0], [
437   - 'user' => -1, // PAS AUTORISÉ
438   - 'resp' => ['NOT CREATED',1]
439   - ]);
440   -
441   - // Action 'updgrade' (avancement du statut d'un matériel)
442   - // CREATED => VALIDATED => TBA => ARCHIVED
443   - /*
444   - $this->setAuthorizationsForAction('upgrade', ['NOT ARCHIVED',0], [ // En fait, l'action fait juste passer au statut "suivant"
445   - //$default = ['PREVIOUS',0], // le matériel doit avoir le statut "précédent" du statut actuel
446   - 'user' => ['VALIDATED',1], // SEULEMENT l'action "demande d'archivage"
447   - //$resp = ['VALIDATED',1] // SEULEMENT l'action "demande d'archivage"
448   - //'resp' => 'Utilisateur'
449   - 'resp' => 'user'
450   - ]);
451   - */
452   - // Action 'updgrade' (avancement du statut d'un matériel)
453   - // - Validation d'un materiel (passe à VALIDATED) : CREATED => VALIDATED
454   - $this->setAuthorizationsForAction('statusValidated (valider)', ['CREATED',0], [
455   - 'user' => -1, // interdit
456   - 'resp' => -1 // interdit
457   - ]);
458   - // - Demande d'archivage : VALIDATED => TBA
459   - $this->setAuthorizationsForAction("statusTobearchived (demander l'archivage)", ['VALIDATED',0], [
460   - //$user = ['default',1],
461   - 'user' => ['VALIDATED',1],
462   - //$resp = ['default',1]
463   - //$resp = ['VALIDATED',1]
464   - 'resp' => 'user'
465   - ]);
466   - // - Archivage : TBA => ARCHIVED
467   - $this->setAuthorizationsForAction('statusArchived (archiver)', ['TOBEARCHIVED',0], [
468   - 'user' => -1, // interdit
469   - 'resp' => -1 // interdit
470   - ]);
471   -
472   - // Action 'printLabelRuban' (impression d'une étiquette)
473   - $this->setAuthorizationsForAction('printLabelRuban (imprimer étiquette)', ['VALIDATED && conf.hasPrinter',0] );
474   - $this->setAuthorizationsForAction('setLabelIsPlaced (déclarer étiquette collée)', ['VALIDATED && conf.hasPrinter',0] );
475   - $this->setAuthorizationsForAction('setLabelIsNotPlaced', ['VALIDATED && conf.hasPrinter',0] );
476   - /*
477   - $this->setAuthorizationsForAction('setLabelIsPlaced', 0); // autorisé sans condition
478   - $this->setAuthorizationsForAction('setLabelIsNotPlaced', 0); // autorisé sans condition
479   - */
480   -
481   - // Action 'execActions'
482   - $this->setAuthorizationsForAction('execActions', 0, [ // par défaut autorisé sans condition
483   - // sauf pour user et resp
484   - 'user' => -1, // PAS AUTORISÉ
485   - 'resp' => -1 // PAS AUTORISÉ
486   - ]);
487   - // Action 'export'
488   - $this->setAuthorizationsForAction('export', 0, [// autorisé sans condition
489   - 'user' => -1 // interdit
490   - ]);
491   - $this->setAuthorizationsForAction('getDateGarantie', 0); // autorisé sans condition
492   -
493   - /*
494   - // Action 'ficheMateriel'
495   - $this->setAuthorizationsForAction('createDocFicheMateriel', 0);
496   - // Action 'ficheMaterielPdf'
497   - // DOMPDF
498   - $this->setAuthorizationsForAction('createDocFicheMaterielPdf', 0);
499   - */
500   -
501   - //debug($this->is_authorized_action);exit;
502   -
503   -
504   -
505   - } // _setAuthorizations()
506   -
507 569  
508 570 /**
509 571 *
... ... @@ -568,7 +630,9 @@ class MaterielsController extends AppController {
568 630 //$this->myDebug("isAuthorizedAction ? " . $this->OLD_isAuthorizedAction2($this, $this->userRole, $this->a, $id, $user));
569 631 $this->myDebug("isAuthorizedAction ? " . $this->OLD_isAuthorizedAction2($this, $this->user_role, $this->a, $id, $user));
570 632 //return $this->isAuthorizedActionForRole($role, $action, $id); // $user, $userCname
571   - if ($action=='add' && $id>0) $action = 'add_by_copy';
  633 + if ($action=='add' && $id>0) {
  634 + $action = 'add_by_copy';
  635 + }
572 636 return $this->isAuthorizedActionForCurrentUser($action, $id); // $user, $userCname
573 637  
574 638 } // isAuthorized()
... ... @@ -1195,7 +1259,6 @@ class MaterielsController extends AppController {
1195 1259 debug($this->getEntity($id)->is_created);
1196 1260 debug($this->getEntity($id)->is_validated);
1197 1261 */
1198   -
1199 1262 $materiel = $this->Materiels->get($id, [
1200 1263 'contain' => [
1201 1264 'SurCategories',
... ... @@ -1215,6 +1278,7 @@ class MaterielsController extends AppController {
1215 1278 'Fournisseurs'
1216 1279 ]
1217 1280 ]);
  1281 + $this->e = $materiel;
1218 1282 $e = $materiel;
1219 1283  
1220 1284 // current user
... ... @@ -1483,6 +1547,10 @@ class MaterielsController extends AppController {
1483 1547 */
1484 1548 //debug("1"); debug($_SESSION);
1485 1549  
  1550 + // (EP202009) moved to parent.afterFilter()
  1551 + //$emails = $this->sendNotificationForEntityAction($materiel);
  1552 + //debug($emails);
  1553 +
1486 1554 } // view
1487 1555  
1488 1556  
... ... @@ -1497,19 +1565,44 @@ class MaterielsController extends AppController {
1497 1565 //protected function add_or_edit($IS_ADD, $id=null, $valeurs=null, $erreurs=null,
1498 1566 protected function add_or_edit($IS_ADD, $id=null, $erreurs=null,
1499 1567 // uniquement à cause de parent::add_or_edit() :
1500   -
1501 1568 $entity_name=null, array $associated_entities=[], $with_parent=false) {
  1569 +
1502 1570 //debug("ici"); exit;
1503   -
1504 1571 $this->myDebug("step 3: MaterielsController.add_or_edit()");
1505   -
1506 1572 $IS_EDIT = !$IS_ADD;
1507   -
1508 1573 $usersTable = TableRegistry::getTableLocator()->get('Users');
1509   -
1510   - // Set $materiel
1511   - $materiel = NULL;
1512   -
  1574 + // Set $materiel : soit un matériel vide (ADD new), soit un matériel de la BD à modifier (EDIT et ADD par copie)
  1575 + //$materiel = ($IS_ADD && !$id) ? $this->Materiels->newEntity() : $this->Materiels->get($id, ['contain' => []]);
  1576 + //debug($this->e); debug($this->getEntity($id)); exit;
  1577 + //$materiel = ($IS_ADD && !$id) ? $this->Materiels->newEntity() : $this->e;
  1578 + //$materiel = ($IS_ADD && !$id) ? $this->Materiels->newEntity() : $this->getEntity($id);
  1579 + $materiel = $IS_ADD ? $this->Materiels->newEntity() : $this->getEntity($id);
  1580 + // ADD par copie : mettre id et numero labo à null
  1581 + if ($IS_ADD && $id) {
  1582 + // IMPORTANT: validate=False car sinon, les données sont validées avant la copie,
  1583 + // et le numero_laboratoire est vu comme invalide car déjà utilisé et doit etre unique !!!
  1584 + // et on a pour résultat : "le matériel n'a pas pu être ajouté" (sans savoir pourquoi !!!)
  1585 + //$materiel = $this->Materiels->newEntity($this->getEntity($id)->toArray(), ['validate' => false]);
  1586 + //$materiel = $this->Materiels->patchEntity($materiel, $this->getEntity($id, false, false)->toArray(), [
  1587 + $materiel = $this->Materiels->patchEntity($materiel, $this->Materiels->get($id, ['contain' => []])->toArray(), [
  1588 + 'validate' => false,
  1589 + // Ne pas valider non plus les entités associées
  1590 + /*
  1591 + 'associated' => [
  1592 + 'SurCategories' => ['validate' => false],
  1593 + 'Categories' => ['validate' => false],
  1594 + 'SousCategories' => ['validate' => false],
  1595 + ]
  1596 + */
  1597 + ]);
  1598 + // IMPORTANT: on ne doit pas laisser l'id égal à celui du matériel copié !!! il en faut un nouveau
  1599 + $materiel->id = null;
  1600 + // on supprime le champ numero_laboratoire car il va être généré automatiquement
  1601 + //unset($materiel->numero_laboratoire);
  1602 + $materiel->numero_laboratoire = null;
  1603 + }
  1604 + //debug($materiel); exit;
  1605 + /*
1513 1606 // ADD
1514 1607 if ($IS_ADD) {
1515 1608 // 1) on crée un materiel vide
... ... @@ -1517,8 +1610,11 @@ class MaterielsController extends AppController {
1517 1610 // - add_by_copy : COPIE de materiel (on a cliqué sur "Copier ce materiel") => id passé en argument
1518 1611 if (isset($this->request->getAttribute('params')['pass'][0])) {
1519 1612 // On récupère le materiel à copier et on le copie dans $materiel
  1613 + /S
1520 1614 $materiel_to_copy = $this->Materiels->get($this->request->getAttribute('params')['pass'][0]);
1521 1615 $materiel_to_copy = $materiel_to_copy->toArray();
  1616 + S/
  1617 + $materiel_to_copy = $this->e->toArray();
1522 1618 //var_dump($materiel_to_copy);
1523 1619 ///foreach ($materiel_to_copy as $key=>$value) $materiel->$key = $value;
1524 1620 // IMPORTANT: validate=False car sinon, les données sont validées avant la copie,
... ... @@ -1536,45 +1632,46 @@ class MaterielsController extends AppController {
1536 1632 //$materiel->id = False;
1537 1633 //unset($materiel->id);
1538 1634  
1539   - /*
  1635 + /S
1540 1636 $attribute="[original]";
1541 1637 $materiel->$attribute = [];
1542   - */
  1638 + S/
1543 1639 //$materiel->id = FALSE;
1544 1640 //$materiel->'[new]' => true,
1545 1641 }
1546 1642 // - NOUVEAU materiel (on a cliqué sur "Nouveau materiel")
1547 1643 else {
1548 1644 //$materiel = $this->Materiels->newEntity();
1549   - /* (EP 20200505 plus nécessaire car on utilise désormais NULL)
  1645 + /S (EP 20200505 plus nécessaire car on utilise désormais NULL)
1550 1646 // Set default values : "N/A"
1551 1647 $materiel->groupes_thematique_id = 1;
1552 1648 $materiel->groupes_metier_id = 1;
1553 1649 $materiel->site_id = 9;
1554   - */
  1650 + S/
1555 1651 }
1556 1652 }
1557 1653 // EDIT
1558 1654 else {
1559   - /*
  1655 + /S
1560 1656 $this->log("Edit a doc1 !", 'debug');
1561 1657 Log::write('debug',"Edit a doc2 !");
1562 1658 $this->dlog("Edit a doc1 !");
1563   - */
  1659 + S/
1564 1660 $materiel = $this->Materiels->get($id, [
1565 1661 'contain' => [] // load associated entities
1566 1662 ]);
1567 1663 //$this->myDebug($materiel);
1568 1664 //debug($materiel);
1569 1665 }
  1666 + */
1570 1667  
1571 1668  
1572   - /* SI POST
  1669 + /* SI POST...
1573 1670 * Les données ont été saisies et postées
1574 1671 * On va donc les sauvegarder
1575 1672 */
1576   - $authorized_actions = $IS_ADD ? ['post'] : ['post','patch','put'];
1577 1673 //if ( $this->request->is(['post','patch','put']) ) {
  1674 + $authorized_actions = $IS_ADD ? ['post'] : ['post','patch','put'];
1578 1675 if ( $this->request->is($authorized_actions) ) {
1579 1676  
1580 1677 //debug($this->request->getData());
... ... @@ -1594,7 +1691,6 @@ class MaterielsController extends AppController {
1594 1691  
1595 1692 // (1) On remplit $materiel avec les données de ce materiel
1596 1693 $materiel = $this->Materiels->patchEntity($materiel, $this->request->getData());
1597   - //debug($materiel); exit;
1598 1694  
1599 1695 /*
1600 1696 // AVIRER
... ... @@ -1655,12 +1751,16 @@ class MaterielsController extends AppController {
1655 1751 $verb = $IS_ADD ? "ajouté" : "modifié";
1656 1752 //$action = $IS_ADD ? "add" : "edit";
1657 1753 //debug($materiel); exit;
1658   -
1659 1754 if (! $this->Materiels->save($materiel)) {
1660 1755 $this->myDebug($materiel->getErrors());
  1756 + debug($materiel->getErrors());
1661 1757 $this->Flash->error(__("Le matériel n'a pas pu être $verb"));
1662 1758 }
1663 1759 else {
  1760 + //debug("iciii"); exit;
  1761 + // (EP202009) $this->e doit refléter le matériel mis à jour
  1762 + $this->e = $materiel;
  1763 +
1664 1764 /*
1665 1765 debug($materiel->getErrors('jkl')); exit;
1666 1766 if ($materiel->getError('numero_laboratoire')) {
... ... @@ -1672,11 +1772,12 @@ class MaterielsController extends AppController {
1672 1772 if ($IS_ADD) {
1673 1773 //(EP202009)
1674 1774 //$this->sendEmail($materiel);
1675   - $this->sendmail($materiel);
  1775 + ///////$this->sendmail($materiel);
1676 1776 $id = $materiel->id;
  1777 + //debug($this->e->id);exit;
1677 1778 }
1678 1779 //$this->dlog("Materiel $verb = '$materiel->designation' (id=$id)");
1679   - $this->ilog("Materiel $verb = '$materiel' (id=$id)");
  1780 + //////$this->ilog("Materiel $verb = '$materiel' (id=$id)");
1680 1781 /*
1681 1782 * EDIT
1682 1783 //En attendant un remaniement complet de la fonction
... ... @@ -1688,8 +1789,7 @@ class MaterielsController extends AppController {
1688 1789 $id
1689 1790 ]);
1690 1791 }
1691   - } // if POST
1692   -
  1792 + } // if POST...
1693 1793  
1694 1794 /* SINON (PAS POST)
1695 1795 * C'est la première fois qu'on vient sur cette vue,
... ... @@ -2156,23 +2256,30 @@ class MaterielsController extends AppController {
2156 2256 */
2157 2257 public function delete($id = null)
2158 2258 {
  2259 +
  2260 + $DEBUG = true;
  2261 +
2159 2262 // $this->request->allowMethod(['post', 'delete']);
2160 2263 $verb = 'supprimé';
  2264 + /*
2161 2265 $materiel = $this->Materiels->get($id,
2162 2266 [
2163 2267 'contain'=>['SurCategories', 'Categories', 'SousCategories']
2164 2268 ]
2165 2269 );
  2270 + */
  2271 + // Optimisation : ne charge l'entité QUE si pas déjà fait
  2272 + $materiel = $this->getEntity($id);
2166 2273  
2167 2274 // DEBUG
2168   - $emails = $this->sendmail($materiel);
2169   - debug($emails);
2170   - exit;
2171   - /*
  2275 + //$emails = $this->sendmail($materiel);
  2276 + //$emails = $this->sendNotificationForEntityAction($materiel);
  2277 + //debug($emails);
  2278 + //exit;
2172 2279  
2173 2280 //if ($materiel->has('sur_category')) debug($materiel->sur_category->nom);
2174 2281 //debug($materiel); exit;
2175   - if ($this->Materiels->delete($materiel)) {
  2282 + if ( !$DEBUG && $this->Materiels->delete($materiel) ) {
2176 2283 $this->Flash->success(__("Le matériel a bien été $verb"));
2177 2284 $this->ilog("Materiel $verb = '$materiel' (id=$id)");
2178 2285 //(EP202009)
... ... @@ -2181,11 +2288,12 @@ class MaterielsController extends AppController {
2181 2288 }
2182 2289 else
2183 2290 $this->Flash->error(__("Le matériel n'a pas pu être $verb"));
2184   - */
2185 2291 return $this->redirect([
2186 2292 'action' => 'index'
2187 2293 ]);
2188   - }
  2294 +
  2295 + } // delete()
  2296 +
2189 2297  
2190 2298  
2191 2299 /**
... ...
src/Controller/UsersController.php
... ... @@ -38,11 +38,18 @@ class UsersController extends AppController
38 38 }
39 39  
40 40  
  41 + // @override parent
41 42 // "l'" utilisateur (et non pas "le utilisateur")
42 43 public function getArticle()
43 44 {
44 45 return "L'";
45 46 }
  47 +
  48 + // @override parent
  49 + protected $actionNounAndPastVerbs = [
  50 + 'login' => ['Connexion','connecté'],
  51 + 'logout' => ['Déconnexion','déconnecté'],
  52 + ];
46 53  
47 54 // 1) AVANT connexion
48 55 public function beforeFilter(Event $event)
... ... @@ -60,15 +67,30 @@ class UsersController extends AppController
60 67 */
61 68 protected function setAuthorizations() {
62 69  
  70 + // Actions qui envoient des notifs
  71 + $this->setNotificationAllowedOnActions([
  72 + 'login' => 'log',
  73 + 'logout' => 'log',
  74 + 'add' => 'log',
  75 + 'edit' => 'log',
  76 + 'delete' => 'log',
  77 + // ...
  78 + ]);
  79 +
63 80 // Actions autorisées à tous
64   - foreach (['login', 'logout', 'getLdapLogin', 'getLdapEmail', 'indexRecap'] as $action) $this->setAuthorizationsForAction($action, 0);
  81 + foreach (['login', 'logout', 'getLdapLogin', 'getLdapEmail', 'indexRecap'] as $action)
  82 + $this->setAuthorizationsForAction($action, 0);
65 83  
66 84 // Action autorisées seulement à superadmin
67 85 // TODO: affiner dans le cas d'un LDAP : même superadmin ne doit pas pouvoir supprimer ou modifier (sauf certains attributs) un utilisateur
68   - foreach (['add', 'edit', 'delete'] as $action) $this->setAuthorizationsForAction($action, -1, ['super'=>0]);
  86 + foreach (['add', 'edit', 'delete'] as $action)
  87 + $this->setAuthorizationsForAction($action, -1, ['super'=>0]);
69 88  
70 89 } // setAuthorizations
71 90  
  91 +
  92 +
  93 +
72 94 // 2) APRES connexion
73 95 /**
74 96 * Give authorization for users
... ...