self::PROFILE_USER, 'Responsable' => self::PROFILE_RESPONSABLE, 'Administration' => self::PROFILE_ADMIN, 'Administration Plus' => self::PROFILE_ADMINPLUS, 'Super Administrateur' => self::PROFILE_SUPERADMIN ]; // - ATTRIBUTS VARIABLES // (EP) Seulement pour les tests // Permet à un test de forcer (si true) le re-chargement d'une entité (car modifiée en BD) protected static $RELOAD = FALSE; // (EP 202007) passé dans la table configuration => "mode_nolimit" // Il suffit de passer ceci à true pour TOUT autoriser à superadmin //protected $SUPERADMIN_CAN_DO_EVERYTHING = false; // (prod) Par défaut (false), il se comporte un peu comme ADMIN //protected $SUPERADMIN_CAN_DO_EVERYTHING = true; // (dev only) no limit, peut TOUT faire (attention, pas en prod svp !!!) protected $confLabinvent = null; // Le Controleur courant protected $c = null; // L'Action courante //protected $action = null; protected $a = null; /* La table courante (objet Table) * * $t = TableRegistry::getTableLocator()->get('Materiels'); (ou autre entité telle que 'Suivis' par exemple...) * */ protected $t = null; /* L'entité courante (objet Entity) * * $e = $t->newEntity(); * ou encore * $e = $t->get(12); * ou encore * $e = $t->find(...)->first(); * ou encore * $e = $t->find(...)->last(); * ... */ //protected $entity =null; protected $e = null; // remplace $entity // id de l'entité courante (shortcut pour $this->e->id) //protected $entity_id = null; protected $e_id = null; // remplace $entity_id // L'utilisateur courant (objet User Entity) // Current (priviledged) USER (if so, otherwise = NULL) from DB (Entity class) //private $CURRENT_PRIVILEDGED_USER = null; //protected $current_user_entity = null; protected $u = null; // remplace $current_user_entity protected $userName = null; // Current ROLE (by default = "Utilisateur") //private $CURRENT_ROLE = null; protected $user_role = null; // L'entité Materiel liée à une autre entité (telle qu'un suivi, un emprunt, un doc attaché...) protected static $related_materiel = null; /* * (EP 20200525) NEW ACL * * AUTORISATIONS * * Voir le tableau (feuille de calcul Google Sheet) https://docs.google.com/spreadsheets/d/16uAq_ko6bpKGxRZTL9rWq5XZ6kaVGMqowLURpBBdJJU/edit#gid=0 * */ //private $default_authorizations = [ const default_authorizations = [ /* * Chaque entrée initialise un tableau à 2 conditions : [ conditions d'accès sur le statut du matériel, conditions d'accès sur l'appartenance du matériel] * La 1ère condition, celle sur le statut, peut prendre des valeurs diverses telles que : 0 (pas de condition), 'CREATED', 'NOT ARCHIVED', ... * La 2ème condition ne peut prendre que 2 valeurs : 0 (pas de condition d'accès) ou 1 (le matériel doit "appartenir" à l'utilisateur) * Si une entrée est égale à 'default', ça signifie qu'elle a la même valeur que l'entrée 'default' (ici [0,0]) * * Exemples : * - [0,0] = aucune condition (toute personne connectée peut faire cette action, quelque soit le profil) * - [0,1] = pas de condition d'accès sur le statut du matériel, mais condition sur l'appartenance (le matériel doit "appartenir" à l'utilisateur) * - ['CREATED',0] = condition sur le statut (le matériel doit être CREATED), mais pas sur l'appartenance (il peut appartenir à n'importe qui) * - ['NOT ARCHIVED',0] = condition sur le statut (le matériel ne doit PAS être ARCHIVED), mais pas sur l'appartenance (il peut appartenir à n'importe qui) * ... */ 'alias' => '', 'default' => 0, 'user' => 'default', 'resp' => 'default', 'admin' => 'default', 'adminp' => 'default', 'super' => 'default' /* // Par défaut (Règle Genérale), il n'y a pas de condition d'accès, donc on peut accéder à l'action sans condition 'default' => 0, //'default' => [0,0], // idem 0 // accès interdit //'default' => -1, // chaque profil utilise par défaut les régles générales (celles de l'entrée 'default') /S 'USER' => 'default', 'RESP' => 'default', 'ADMIN' => 'default', 'SUPER' => 'default', S/ 'Utilisateur' => 'default', 'Responsable' => 'default', 'Administration' => 'default', 'Administration Plus' => 'default', 'Super Administrateur' => 'default', //'Super Administrateur' => -1 */ ]; // default_authorizations /* const default_authorizations_adminonly = [ 'default' => 0, 'user' => -1, 'resp' => -1, 'admin' => 'default', 'adminp' => 'default', 'super' => 'default' ]; */ /* * Tableau des autorisations pour les actions du controleur * * Hérité par CHAQUE controleur (qui a donc sa propre instance de ce tableau, indépendante des instances des autres controleurs) * * On l'initialise déjà avec les actions autorisées par défaut * On le complètera ensuite pour les autres actions //protected $is_authorized_action = []; // Pour tous les controleurs */ protected $is_authorized_action = []; /* // autorisé pour tous : 'index' => self::default_authorizations, 'view' => self::default_authorizations, 'find' => self::default_authorizations, // admin(+) only : 'add' => self::default_authorizations_adminonly, 'edit' => self::default_authorizations_adminonly, 'delete' => self::default_authorizations_adminonly, // Uniquement pour le controleur de pages PagesController (1 seule action autorisée : display) //'display' => self::default_authorizations, ]; */ // (OLD AVIRER) EP 08/2017 // protected $easyACL = array( const OLD_easyACL = array( /** * Default ACL for ALL (logged) users * * Les actions non mentionnées sont accessibles à tous (par défaut), * exemple 'find', 'index'... * Ces default ACL peuvent être surchargées pour un profil précis * (par exemple pour 'USER' qui est plus restreint) */ // 'ALL' => array ( 'DEFAULT' => array( // 'action' => 'condition for execution' (= 'Y', 'N', or ''), // with like "'field name' == 'value'" // !!! Used for test, DO NOT REMOVE : !!! 'action_CAS4_Y' => 'Y', 'action_CAS4_N' => 'N' // YOUR RULES : // CRUD actions : // 'edit' => 'N', // update // 'delete' => 'N', ), // Ajoute des ACL plus spécifiques (ci-dessus) pour le profil USER qui est plus restreint // Les actions absentes ne sont pas surchargées (elles sont exécutées selon les conditions définies pour 'ALL') 'USER' => array( // !!! Used for test, DO NOT REMOVE : !!! 'action_CAS3_Y' => 'Y', 'action_CAS3_N' => 'N', // YOUR RULES : // CRUD actions 'add' => 'Y', // C 'index' => 'Y', // R all 'view' => 'Y', // R one // 'edit' => 'N', // U 'edit' => 'is_creator', // is_creator = (nom_createur == CURRENT_USER_NAME) 'delete' => 'N', // D // OTHER actions 'find' => 'Y' // create /* * ceci n'a aucun sens car l'action sur le modèle "Pages" s'appelle toujours "display" (et non pas tools, infos, ou printers...) * 'tools' => 'N', * 'infos' => 'N', * 'printers' => 'N', */ ), // Surcharge des ACL par défaut (ci-dessus) pour le profil RESPONSABLE qui est plus restreint // Les actions absentes ne sont pas surchargées (elles sont exécutées selon les conditions définies pour 'ALL') 'RESPONSABLE' => array(), // Surcharge des ACL par défaut (ci-dessus) pour le profil ADMIN 'ADMIN' => array( // 'add' => 'Y', // create 'edit' => 'Y' // update // 'delete' => 'Y', // update ), // Surcharge des ACL par défaut (ci-dessus) pour le profil ADMINPLUS 'ADMINPLUS' => array( // 'edit' => 'Y', // update ), // Surcharge des ACL par défaut (ci-dessus) pour le profil SUPERADMIN 'SUPERADMIN' => array( // 'add' => 'Y', // create // 'edit' => 'Y', // update 'delete' => 'Y' ) ); // $easyACL public function d($msg) { if ( $this->DEBUG || $this->isLabinventDebugMode() ) pr($msg); } public function d2($msg) { if ( $this->DEBUG || $this->isLabinventDebugMode() ) debug($msg); } // Nom du champ "nom" de l'entité (par défaut => 'nom') // To be overriden public function getNameFieldLabel() { //return 'name'; return 'nom'; } /* * Retourne le matériel courant, c'est à dire : * - soit l'entité courante si on est dans MaterielsController * - soit le materiel associé à l'entité courante si on est dans un autre controleur (lié aux matériels : SuivisController, EmpruntsController, DocumentsController...) protected function getCurrentMateriel($id) { //debug("controleur is ".$this->name); //if ($this->name == 'Materiels') return $this->e; // Si on est dans MaterielsController, retourner l'entité courante (puisque c'est un matériel) // Sinon (on est dans un controleur lié aux matériels tel que SuivisController, EmpruntsController, DocumentsController...) // => on retourne le matériel associé (related) à l'entité courante (Suivi, Emprunt, Document...) $m = $this->name=='Materiels' ? $this->getEntity($id) : $this->getMateriel($id); return $m; } */ /** * (EP 20200525) NEW ACL * * @param string $action * @param array $authorizations = [ * 'default' => 0, * 'user' => 'default', * 'resp' => 'default', * 'admin' => 'default', * 'adminp' => 'default', * 'super' => 'default' * ] * */ //protected function setAuthorizationsForAction($action, $default, $user=null, $resp=null, $admin=null, $adminp=null, $super=null) { // php7: //protected function setAuthorizationsForAction(string $action, $default, array $authorizations=null) { // php5: protected function setAuthorizationsForAction($action, $default, array $authorizations=[]) { /* * Paramètres "nommés" simulés avec le paramètre $authorizations : * (https://phil.tech/2013/named-parameters-in-php) * * Comment ça marche ? * 1) "$authorizations +=" n'ajoute QUE les arguments qui n'ont pas déjà été passés en paramètres * 2) "extract" transforme les arguments de $authorizations en variables directes : $user, $resp, ... */ $authorizations += [ 'user' => null, 'resp' => null, 'admin' => null, 'adminp' => null, 'super' => null, ]; //extract($authorizations); /* // (raccourci) Reference vers le tableau $action_rules = &$this->is_authorized_action[$action]; // initialisation du tableau pour cette action pour le controleur spécifique en cours (des zéros partout = pas d'autorisation, par défaut) $action_rules = self::default_authorizations; */ //$roles_short = ['default', 'user', 'resp', 'admin', 'adminp', 'super']; $roles_short = ['user', 'resp', 'admin', 'adminp', 'super']; $alias = ''; $action_and_alias = explode('(',$action); if (count($action_and_alias)==2) { $action = trim($action_and_alias[0]); $alias = substr($action_and_alias[1],0,-1); } //debug("action=$action, alias=$alias"); // initialisation du tableau pour cette action pour le controleur spécifique en cours $this->is_authorized_action[$action] = self::default_authorizations; // Ajout de l'alias dans le tableau des autorisations pour cette action $this->is_authorized_action[$action]['alias'] = $alias; // (raccourci) Reference vers le tableau $action_rules = &$this->is_authorized_action[$action]; $S = false; //$S = $action == 'edit'; //$S = $action == 'statusTobearchived'; //$S = $action == 'sortiePdf'; //$S = $action == 'admissionPdf'; //$S = $this->name == 'Suivis'; // Initialisation de la règle générale par défaut (pour cette action) // Si la règle par défaut est un alias vers une autre action (ex: 'add'), on remplace l'alias par sa valeur (la règle associée à l'action pointée par l'alias) // Par exemple, si la règle pour 'edit' est la même que pour 'add', on initialise la règle pour 'edit' par la règle pour 'add', logique $roles = array_keys(self::PROFILES); //$default = $authorizations['default']; // 1) Initialisation de la règle générale (par défaut) et de la règle concernant CHAQUE role (pour cette action) $action_rules['default'] = $default; if ($S) { debug("0a) action $action"); debug("action_rules:"); debug($action_rules); } /* $roles_var = ['user', 'resp', 'admin', 'adminp', 'super']; //foreach ($roles_var as $role_var) if ($$role_var) $action_rules[$role] = $$role_var; for ($i=0; $i<=4; $i++) { $role_var = $roles_var[$i]; $role = $roles[$i]; if ($i==0) debug("$role_var, ".$$role_var.", $role"); if ($$role_var !== null) $action_rules[$role] = $$role_var; } */ // 2) Intialisation de la règle pour chaque profil //debug("user value is"); debug($user); //$roles_var = [$user, $resp, $admin, $adminp, $super]; //foreach ($roles_var as $role_var) if ($$role_var) $action_rules[$role] = $$role_var; foreach ($roles_short as $role_short) { $role_cond = &$authorizations[$role_short]; //if ($S) { debug("condition for role $role_short"); debug($role_cond); } if (isset($role_cond) && $role_cond!==null) $action_rules[$role_short] = $role_cond; } if ($S) { debug("0b) action $action"); debug("action_rules:"); debug($action_rules); } // 3) Des-aliasing de chaque règle // - règle générale (par défaut) /* ENORME BUG PHP : in_array(0,['add','edit'])) => renvoie TRUE !!! 0 == 'add' => renvoie TRUE !!! */ $all_actions = array_keys($this->is_authorized_action); //if ($default!==0 && in_array($default,['add','edit','admission','sortie'])) { if ($default!==0 && in_array($default,$all_actions)) { $action_rules['default'] = $this->is_authorized_action[$default]['default']; } // - règle pour chaque role if ($S) { debug("1) action $action"); debug("action_rules:"); debug($action_rules); } //foreach ($roles as $role) //$roles_short = ['user']; foreach ($roles_short as $role) { //debug("- role is $role"); //if ($role == 'Administration Plus') continue; if (! isset($action_rules[$role])) continue; $rule = &$action_rules[$role]; //debug("RULE is"); debug($rule); // règle = 'default' if ($rule === 0) continue; // car sinon, bug php, in_array répond toujours TRUE !!! elseif ($rule === 'default') $rule = $action_rules['default']; // règle = un autre role elseif (in_array($rule,$roles_short)) { //debug("$rule in roles"); $rule = $action_rules[$rule]; } // règle = une autre action (= 'add' ou 'edit') elseif (in_array($rule,['add','edit'])) $rule = $this->is_authorized_action[$rule][$role]; elseif (is_array($rule) && $rule[0]==='default') $rule[0] = $action_rules['default'][0]; //if ($role=='user') debug("RULE is"); debug($rule); //debug("action_rules:"); debug($action_rules); } if ($S) { debug("2) action $action"); debug("action_rules:"); debug($action_rules); } } // setAuthorizationsForAction public function getAuthorizations($action=null, $role=null) { if (!$action) return $this->is_authorized_action; if (!$role) return $this->is_authorized_action[$action]; return $this->is_authorized_action[$action][$role]; } /* * Retourne le materiel associé à l'entité courante * (par exemple, le materiel associé au suivi $id) * * $id : * - si $action=='add' => c'est l'id du materiel * - sinon => c'est l'id de l'entité (suivi, emprunt...) * * Cette méthode est surchargée par MaterielsController * qui ne renvoit que le materiel d'id $id * */ //protected function getRelatedMaterielForId($id, $action=null) { protected function getRelatedMaterielForId($id, $IS_RELATED_ENTITY_ID=false) { if (!$id) throw new \ErrorException("L'id ($id) n'est pas positionné (=0 ou null) !!!"); // Si action 'add', id = celui du materiel //if ($action == 'add') return $this->getMateriel($id); // Si $IS_RELATED_ENTITY_ID => $id est l'id d'une entité associée (a priori Materiels) if ($IS_RELATED_ENTITY_ID) return $this->getMateriel($id); // Sinon, id = celui de l'entité (emprunt) return $this->getEntity($id, $WITH_RELATED_MATERIEL=true)->materiel; } protected function getRelatedMaterielForEntityId($id, $related_matos_id=null) { if (!$id && !$related_matos_id) throw new \ErrorException("L'id ($id) et le related_matos_id ($related_matos_id) ne sont pas positionnés (=0 ou null) !!!"); if ($id) return $this->getEntity($id, $WITH_RELATED_MATERIEL=true)->materiel; return $this->getMateriel($related_matos_id); } protected function getMaterielOrRelatedMaterielForEntityId($id, $related_matos_id=null) { return ($this->name == 'Materiels') ? $this->getEntity($id) : $this->getRelatedMaterielForEntityId($id, $related_matos_id); } /* // Lève une exception si pas implémentée protected function getRelatedMaterielForId($id, $action=null) { throw new \Exception("Pour déterminer si la condition d'accès à l'action est respectée, il faut un matériel défini (or \$m est null) !"); } */ // WRAPPER sur tableau des autorisations is_authorized_action[] public function getAccessConditionForActionAndRole($action, $role) { //debug($this->is_authorized_action[$action]); // Si pas de règle définie pour l'action => accès interdit if (!isset($this->is_authorized_action[$action][$role])) return -1; //throw new \ErrorException("L'action '$action' n'a pas de condition d'accès définie dans le controleur $this->name (role '$role') !!"); $access_condition = $this->is_authorized_action[$action][$role]; if ($access_condition==='default') $access_condition = $this->is_authorized_action[$action]['default']; return $access_condition; } // @deprecated public function isAuthorizedAction($action, $id=null, $related_matos_id=null, $user=null) { return $this->isAuthorizedActionForCurrentUser($action, $id, $related_matos_id, $user); } /** * @param string $action * @param int $id => entity id * @param int $related_matos_id => related materiel id * @param $user => Utilisateur courant (null par défaut car on prend celui de la session en cours ; si pas null on prend ce user (qui est quand meme l'utilisateur courant)) * * @throws \ErrorException * @throws \Exception * * @return boolean */ // php7: //protected function isAuthorizedAction(string $action, int $id=null, bool $IS_RELATED_ENTITY_ID=false, $user=null) { // php5: //protected function isAuthorizedAction($action, $id=null, $IS_RELATED_ENTITY_ID=false, $user=null) { //public function isAuthorizedAction($action, $id=null, $IS_RELATED_ENTITY_ID=false, $user=null) { public function isAuthorizedActionForCurrentUser($action, $id=null, $related_matos_id=null, $user=null) { //return $this->isAuthorizedActionForRole($this->user_role, $action, $id); //return $this->isAuthorizedActionForRole($this->getUserRole($user), $action, $id, $IS_RELATED_ENTITY_ID, $user); $this->d("IN isAuthorizedActionForCurrentUser(): controleur $this->name, action $action"); //return $this->isAuthorizedActionForRole($this->getUserRole($user), $action, $id, $related_matos_id, $user); //return $this->isAuthorizedActionForCurrentUser($action, $id, $related_matos_id, $user); $role_long = $this->getUserRole($user); $this->d("*************************** CONTROLEUR ".$this->name.", ACTION $action, ROLE $role_long, id=$id, related_matos_id=$related_matos_id"); //$this->d("********* USER :"); $this->d2($user); //if ($this->SUPERADMIN_CAN_DO_EVERYTHING) return TRUE; if ($this->confLabinvent->mode_nolimit) return TRUE; //if ($action=='statusTobearchived'); exit; //$m = ($m_id) ? $this->getCurrentMateriel($m_id) : null; //$m = null; /* if ($this->name=='Materiels' && $id!==null) $m = $this->getEntity($id); if ($this->name!='Materiels' && $related_matos_id!==null) $m = $this->getRelatedMaterielForId($id); debug("matos is"); debug($m); */ switch ($role_long) { case 'Utilisateur': $role='user'; break; case 'Responsable': $role='resp'; break; case 'Administration': $role='admin'; break; case 'Administration Plus': $role='adminp'; break; case 'Super Administrateur': $role='super'; } /* * Cas particulier du controleur de pages (PagesController) et de son unique action "display" * => on remplace l'action par le nom de la page */ if ($this->name == 'Pages') { // Si la page n'existe pas => accès rejeté $action = "display/".$this->page; if (! in_array($action, array_keys($this->is_authorized_action))) return false; } // Pour cette action et ce role : //debug("role is $role"); //$access_condition = $this->is_authorized_action[$action][$role]; $access_condition = $this->getAccessConditionForActionAndRole($action,$role); $this->d("0) Condition (complète) (NOT desaliased) :"); $this->d($access_condition); //debug($this->is_authorized_action); //debug($this->is_authorized_action[$action]); //debug("access_condition"); debug($access_condition); //debug($this->is_authorized_action); // Si la condition est un alias vers une autre entrée (style 'default' ou 'admin'...), on remplace cet alias par sa valeur //if ( in_array($access_condition, ['default', 'user', 'resp', 'admin']) ) if ( !is_int($access_condition) && ( $access_condition=='default' || in_array($access_condition, array_keys(self::PROFILES)) ) ) { $this->is_authorized_action[$action][$role] = $this->is_authorized_action[$action][$access_condition]; // 2) Maintenant, on n'a plus d'alias vers une condition, mais une vraie condition qu'on peut appliquer directement $access_condition = $this->is_authorized_action[$action][$role]; } // - si -1 => acccès refusé $this->d("1) Condition (complète) (desaliased) :"); $this->d($access_condition); //debug($access_condition); exit; if ($access_condition === -1) return FALSE; if ($access_condition === 0) return TRUE; // A partir d'ici, on doit avoir un array //if ($action=='sortiePdf') exit; if (! is_array($access_condition)) throw new \ErrorException("La condition ($access_condition) pour autoriser l'action ($action) doit être -1, 0, ou bien un tableau !"); //if ($action=='admissionPdf') exit; // - sinon, cette condition est un tableau à 2 valeurs : [condition de statut , condition d'appartenance] // Les 2 conditions doivent être respectées : return $condition_on_status AND $condition_on_belonging $condition_on_status = $access_condition[0]; $condition_on_belonging = $access_condition[1]; // Il faut maintenant calculer chacune de ces conditions /* * a) Condition de Statut * * Peut prendre diverses formes : * - soit un zéro pour dire OK (pas de condition) : '0' * - soit un simple statut : 'CREATED', 'VALIDATED', ... * - soit un NON statut : 'NOT ARCHIVED' * - peut aussi être composé de 2 conditions séparées par un '&&' (ET) ou un '||' (OU) */ $this->d("- a) condition statut :"); $this->d($condition_on_status); $m = null; // 0 => pas de condition, c'est ok ! //if ($condition === 0) return TRUE; if ($condition_on_status === 0) $condition_on_status_result=TRUE; // -1 => pas ok ! elseif ($condition_on_status === -1) $condition_on_status_result=FALSE; else { //$m = $this->getRelatedMaterielForId($id, $action); // Uniquement pour 'add' d'un controleur autre que Materiels (car sinon c'est inutile) ////if ($action=='add' && $id==0) $id = posted_data.materiel_id (données POSTED contiennent l id du matos à tester, galère !!!) // Si c'est le controleur des materiels, on prend directement le materiel d'id $id // Sinon, on prend le materiel associé à l'entité //$m = ($this->name == 'Materiels') ? $this->getEntity($id) : $this->getRelatedMaterielForEntityId($id, $related_matos_id); $m = $this->getMaterielOrRelatedMaterielForEntityId($id, $related_matos_id); $this->d("AppC: (related) matos id & status is $m->id, $m->status"); //$m = $this->getRelatedMaterielForId($id, $IS_RELATED_ENTITY_ID); //$condition_on_status_result = $this->eval_condition_on_status($condition_on_status, $id, $action, $m); //$condition_on_status_result = $this->eval_condition_on_status($condition_on_status, $id, $action, $m); //$condition_on_status_result = $this->eval_condition_on_status($condition_on_status, $id, $action, $IS_RELATED_ENTITY_ID, $m); //debug("condition");debug($condition_on_status); exit; $condition_on_status_result = $this->eval_condition_on_status($condition_on_status, $id, $action, $related_matos_id, $m); } $this->d("$condition_on_status evalué à "); $this->d2($condition_on_status_result); //if ($action=='printLabelRuban') { debug("coucou2"); exit; } // Si condition statut non respectée => access denied //if ($action=='admission') {debug("here"); exit;} if (! $condition_on_status_result) return FALSE; //if ($this->name=='Suivis') exit; /* // par défaut => faux $condition_on_status_result = FALSE; $statuses = MaterielsController::statuses; //debug("statuts:"); debug($statuses); //$statuses = ['CREATED', 'VALIDATED', 'TOBEARCHIVED', 'ARCHIVED']; // 0 => pas de condition, c'est ok ! if ($condition_on_status == 0) $condition_on_status_result = TRUE; // autre => à évaluer : qqch comme 'CREATED' ou 'NOT ARCHIVED' ou 'CREATED && autre chose'... else { // Est-ce une double condition séparée par un && ou un || ? $tokens = ['&&','||']; $found = false; foreach ($tokens as $token) { $pos = strpos($condition_on_status,$token); if ($pos > 0) { $conditions = explode($token, $condition_on_status); $conditions_result = []; foreach ($conditions as $condition) $conditions_result[] = $this->eval_condition_on_status($condition); $found = true; break; } } // found && ou || => 2 conditions à évaluer if ($found) $condition_on_status_result = eval("return $conditions_result[0] $token $conditions_result[1];"); // not found => 1 seule condition à évaluer : avec ou sans 'NOT' else { // - soit un "NON statut" : commence par 'NOT ' $NOT = FALSE; if (strpos($condition_on_status,'NOT ')===0) { $NOT = TRUE; // on prend le statut après le "NOT " : $condition_on_status = substr($condition_on_status,4); } // - soit un "statut" if (! in_array($condition_on_status, $statuses)) throw new \Exception("La condition de statut doit être soit un 'statut' soit un 'NOT statut' !"); if (!$m) throw new \Exception('Pour déterminer si la condition de statut est respectée, il faut un matériel défini (or $m est null) !'); $condition_on_status_result = $m->hasStatus($condition_on_status); if ($NOT) $condition_on_status_result = !$condition_on_status; } } */ // b) Condition d'Appartenance (belonging) $this->d("- b) condition appartenance :"); $this->d($condition_on_belonging); if (! in_array($condition_on_belonging, [-1,0,1])) throw new \Exception("La condition d'appartenance doit être 0 (pas de condition) ou 1 (doit appartenir) !"); // 0 => pas de condition, c'est ok ! if ($condition_on_belonging === -1) $condition_on_belonging_result = FALSE; elseif ($condition_on_belonging === 0) $condition_on_belonging_result = TRUE; // 1 => le matériel doit "appartenir" à l'utilisateur connecté else { //debug("********* USER1 IS:"); debug($user); $u = $this->getUserEntity($user); //debug("********* USER2 IS:"); debug($u); //exit; //$m = $m?:$this->getRelatedMaterielForId($id, $action); //debug($m); //$m = $m?:$this->getRelatedMaterielForId($id, $IS_RELATED_ENTITY_ID); $m = $m?:$this->getMaterielOrRelatedMaterielForEntityId($id, $related_matos_id); //debug($m); //debug($m); //$m = $m ? $m : $this->getRelatedMaterielForId($id); /* if (!$m) { throw new \Exception('Pour déterminer si la condition d\'appartenance est respectée, il faut un matériel défini (or $m est null) !'); } */ $condition_on_belonging_result = $m->belongsToUser($u->nom); // Si l'utilisateur courant a le profil "Responsable", il peut aussi faire cette action s'il est responsable du matériel $m if ($this->USER_IS_RESP()) $condition_on_belonging_result = $condition_on_belonging_result || $m->isSameGroupAsUser($u->groupes_metier_id, $u->groupes_thematique_id); } $this->d("$condition_on_belonging evalué à "); $this->d2($condition_on_belonging_result); //if ($this->name=='Emprunts') exit; //if ($this->name=='Documents') exit; // 3) return (1) && (2) $condition_result = $condition_on_status_result && $condition_on_belonging_result; $this->d("2) Condition globale (a && b) evaluée à :"); $this->d2($condition_result); return $condition_result; } /* * Fonction récursive qui évalue une condition de statut matériel. * Cette condition peut être simple ('CREATED') ou composée ('NOT CREATED && toto') */ //protected function eval_condition_on_status($condition, $id, $action, $m=null) { //protected function eval_condition_on_status($condition, $id, $action, $IS_RELATED_ENTITY_ID=false, $m=null) { protected function eval_condition_on_status($condition, $id, $action, $related_matos_id=null, $m=null) { // On enlève les espaces inutiles $condition = trim($condition); /* // 1) '0' => pas de condition, c'est ok ! //if ($condition === 0) return TRUE; if ($condition === '0') return TRUE; if ($condition === '-1') return FALSE; //if ($this->name=='Suivis') exit; */ $this->d("La (sous-)condition à évaluer est: $condition"); // 2) '[NOT] statut' => [NOT] eval(statut) $NOT = FALSE; if (strpos($condition,'NOT ') === 0) { $NOT = TRUE; // on prend le statut après le "NOT " : $condition = substr($condition,4); } // 3) un simple statut tel que 'CREATED', ou 'VALIDATED', ... //$m = $m?:$this->getRelatedMaterielForId($id, $action); //$m = $m?:$this->getRelatedMaterielForId($id, $IS_RELATED_ENTITY_ID); $m = $m?:$this->getMaterielOrRelatedMaterielForEntityId($id,$related_matos_id); //debug("m is"); debug($m); //if (! in_array($condition, $statuses)) throw new \Exception("La condition de statut doit être soit un 'statut' soit un 'NOT statut' !"); if (in_array($condition, array_keys(MaterielsController::statuses))) { //if (!$m) throw new \Exception("Pour déterminer si la condition de statut ($condition) est respectée, il faut un matériel défini (Or \$m est null) !"); $condition_result = ($m->status == $condition); if ($NOT) $condition_result = ! $condition_result; return $condition_result; } // 4) une simple valeur de config telle que conf.hasPrinter... $token = 'conf.'; //if ($condition == 'VALIDATED && conf.hasPrinter') { if (strpos($condition,$token) === 0) { $condition = substr($condition, strlen($token)); //debug("conf attr is $condition"); // ex: $this->confLabinvent->hasPrinter pour 'conf.hasPrinter' return $this->confLabinvent->$condition; } // 5) Double condition séparée par un && ou un || telle que 'expr1 && expr2' => eval(expr1) && eval(expr2) $tokens = ['&&','||']; //debug("tokens:"); debug($tokens); foreach ($tokens as $token) { $pos = strpos($condition,$token); if ($pos > 0) { $conditions = explode($token, $condition); $this->d("conditions:"); $this->d($conditions); $conditions_result = []; // Appel récursif //foreach ($conditions as $condition) $conditions_result[] = $this->eval_condition_on_status($condition, $id, $action, $m); //foreach ($conditions as $condition) $conditions_result[] = $this->eval_condition_on_status($condition, $id, $action, $IS_RELATED_ENTITY_ID, $m); foreach ($conditions as $condition) $conditions_result[] = $this->eval_condition_on_status($condition, $id, $action, $related_matos_id, $m); //debug($conditions_result[0]); //debug($conditions_result[1]); // Marche pas avec false !!! (uniquement avec true, dommage) //return eval("return (bool)$conditions_result[0] $token (bool)$conditions_result[1];"); // token AND (&&) if ($token == '&&') return $conditions_result[0] && $conditions_result[1]; // token OR (||) return $conditions_result[0] || $conditions_result[1]; } } // SINON => Exception, il y a qqch qui cloche dans la syntaxe throw new \Exception("La condition de statut ($condition) pour le controleur (".$this->name.") et l'action ($action) doit être soit un 'statut' soit un 'NOT statut' soit une condition double (séparée par '&&' ou '||') !"); } // eval_condition_on_status() // if (isset($this->easyACL['DEFAULT'][$action])) { public function OLD_hasACLRule($easyACL, $role, $action) { // return isset($this->easyACL[$role][$action]); // return (null !== self::easyACL[$role][$action]); // return array_key_exists($role, self::easyACL) && array_key_exists($action, self::easyACL[$role]); return array_key_exists($role, $easyACL) && array_key_exists($action, $easyACL[$role]); } // @todo public function startsWith($haystack, $needle) { return strpos($haystack, $needle) === 0; } /* * //@todo * public function endsWith($haystack, $needle) { * return strpos($haystack, $needle, strlen($haystack)-1) === 0; * } */ public function OLD_evalACL($condition) { return $condition; // Simple case if ($condition == 'Y') return true; if ($condition == 'F') return false; // Complex case // @todo return true; } public function OLD_evalSpecificRule($condition, AppController $controller, $user, $role, $action, $id = null) { // if starts with "&&" eval DEFAULT rule && specific rule if ($this->startsWith($condition, '&&')) { //debug($condition); //if (! isset($controller::easyACL['DEFAULT'][$action])) return new \Exception('bad rule'); if (! array_key_exists($action, $controller::OLD_easyACL['DEFAULT']) ) return new \Exception('bad rule'); //return $this->evalACL($controller->easyACL['DEFAULT'][$action]) && $this->evalACL($condition); return $this->OLD_evalACL($controller::OLD_easyACL['DEFAULT'][$action]).' ' . $this->OLD_evalACL($condition); } // otherwise, eval only specific rule return $this->OLD_evalACL($condition); } public function isAuthorizedByAcl($acl) { debug("role is", $this->user_role); $aclDefault = $acl['ALL']; $aclForCurrentUser = $acl[$this->user_role]; /* if ($aclDefault) if ($this->startsWith($aclForCurrentUser, '&&')) */ } /** * * @param AppController $controller * // a subclass of AppController (MaterielsController or any other) * @param array $user * @param string $role * @param string $action * @param string $id */ // public function isAuthorizedAction(AppController $controller, $roleLong, $action, $id=null, $user=null) { public function OLD_isAuthorizedAction2($controller, $roleLong, $action, $id = null, $user = null) { /* Cette fonction n'est pas encore appelée pour de vrai, juste pour test, donc inutile d'afficher ça : $this->myDebug("step 2B (intermediaire general): AppController.OLD_isAuthorizedAction2(controller, $roleLong, $action, $id, user)"); $this->myDebug("- controller name is {$controller->name}"); */ //$this->myDebug("- user is ", $user); $doDEBUG = true; $doDEBUG = false; switch ($roleLong) { case 'Utilisateur': $role = 'USER'; break; case 'Responsable': $role = 'RESPONSABLE'; break; case 'Administration': $role = 'ADMIN'; break; case 'Administration Plus': $role = 'ADMINPLUS'; break; case 'Super Administrateur': $role = 'SUPERADMIN'; break; } if ($doDEBUG) debug("role is $role"); // 1) SPECIFIC controller SPECIFIC (role) rule for action // if (isset($controller->easyACL[$role][$action])) { if (self::OLD_hasACLRule($controller::OLD_easyACL, $role, $action)) { if ($doDEBUG) debug("CAS1"); return $this->OLD_evalSpecificRule($controller::OLD_easyACL[$role][$action], $controller, $user, $role, $action); } // 2) SPECIFIC controller DEFAULT rule for action // if (null !== $controller::easyACL['DEFAULT'][$action]) { if (self::OLD_hasACLRule($controller::OLD_easyACL, 'DEFAULT', $action)) { if ($doDEBUG) debug("CAS2"); return $this->OLD_evalACL($controller::OLD_easyACL['DEFAULT'][$action]); } // 3) ALL controllers (AppController) SPECIFIC (role) rule for action // if (isset($this->easyACL[$role][$action])) { if (self::OLD_hasACLRule(self::OLD_easyACL, $role, $action)) { if ($doDEBUG) debug("CAS3"); return $this->OLD_evalSpecificRule(self::OLD_easyACL[$role][$action], $this, $user, $role, $action); } // 4) ALL controllers (AppController) DEFAULT rule for action // if (isset($this->easyACL['DEFAULT'][$action])) { // if (self::hasACLRule('DEFAULT',$action)) { if (self::OLD_hasACLRule(self::OLD_easyACL, 'DEFAULT', $action)) { if ($doDEBUG) debug("CAS4"); return $this->OLD_evalACL(self::OLD_easyACL['DEFAULT'][$action]); // return $this->evalACL(parent::getACLRule('DEFAULT',$action)); } /* * (RECURSIVE CALL) * 5) SPECIFIC controller PREVIOUS SPECIFIC (role) rule for action * ex: if role is 'SUPER', use 'ADMIN' rule * ex: if role is 'ADMIN', use 'RESP' rule * ex: if role is 'RESP', use 'USER' rule * ex: if role is 'USER', stop recursive call * Stop recursive call if role is 'USER' => no rule found, so DEFAULT IS AUTHORIZE (Y) !!! => permissive ACL */ // if ($role == 'USER') return true; if ($role == 'USER') { if ($doDEBUG) debug("CAS5"); return 'Y'; } if ($doDEBUG) debug("CAS6"); return $this->OLD_isAuthorizedAction2($controller, $this->getPreviousRole($role), $action, $id, $user); } // @todo public function getMandatoryFieldsForAction($action) { $fields = []; // meme fonctionnement recursif que isAuthorizedAction() ci-dessus return $fields; } // @todo public function getHiddenFieldsForAction($action) { $fields = []; // meme fonctionnement recursif que isAuthorizedAction() ci-dessus return $fields; } // @todo public function getReadOnlyFieldsForAction($action) { $fields = []; // meme fonctionnement recursif que isAuthorizedAction() ci-dessus return $fields; } // @todo public function getDefaultValueFieldsForAction($action) { $fields = []; // meme fonctionnement recursif que isAuthorizedAction() ci-dessus return $fields; } public static function getRoleLevel($role) { // return $this->allProfiles[$role]; // debug("role is" .$role); return self::PROFILES[$role]; } public static function forceReload() { self::$RELOAD = TRUE; } public static function getPreviousRole($role) { switch ($role) { /* * case 'RESPONSABLE': $rolePrev='USER'; break; * case 'ADMIN': $rolePrev='RESPONSABLE'; break; * case 'ADMINPLUS': $rolePrev='ADMIN'; break; * case 'SUPERADMIN': $rolePrev='ADMINPLUS'; break; */ case 'RESPONSABLE': $rolePrev = 'Utilisateur'; break; case 'ADMIN': $rolePrev = 'Responsable'; break; case 'ADMINPLUS': $rolePrev = 'Administration'; break; case 'SUPERADMIN': $rolePrev = 'Administration Plus'; break; } return $rolePrev; } // to be overriden by subclasses //abstract static public function getActions(); static public function getActions() { //throw new NotImplementedException(); $actions = [ // - CRUD /* */ 'add', 'view', 'index', 'edit', 'delete', /* // - Autres */ //'find', ]; // Retourne toutes les méthodes publiques, mêmes celles qui ne sont pas des actions, donc pas bon //$actions = get_class_methods('App\Controller\MaterielsController'); return $actions; } public function getActionPassed() { // BETTER: // return $this->request->getAttribute('params')['action']; return $this->request->getParam('action'); } // Retourne l'id passé en paramètre de l'url, sinon 0 (si null) public function getIdPassed() { // return (int) $this->request->getAttribute('params')['pass'][0]; return (int) $this->request->getParam('pass.0'); } /* (EP 20200428) * * Méthode pour optimiser les accès à la BD. * Retourne l'entité dont l'id est $id (en la mettant en cache pour éviter de la rechercher 2 fois) * Si $id = null => retourne l'entité courante ($this->e) (entité concernée par l'action en cours) * * Cette méthode ne doit être appelée que lorsque c'est approprié * (actions 'edit', 'view', ..., mais pas 'add', 'find', 'index', ...) * sinon ça provoque une exception... * * Optimisation : l'entité n'est récupérée dans la BD qu'une seule fois pour toutes * */ // PHP7 only //protected function getEntity($id=null) : Entity { // PHP>=5 public function getEntity($id=null, $WITH_RELATED_MATERIEL=false) { // Si pas d'id => exception (stop) //assert($this->e_id>0); if (!$this->e_id && !$id) throw new \Exception(__("cette methode doit etre appelée avec un id déjà positionné !!!")); // Par défaut id = id de l'entité courante if (is_null($id)) $id = $this->e_id; //pr($this->e); // Si l'entité courante n'est pas la bonne, la mettre à null pour obliger à la recharger //if ($id && $this->e && $this->e->id!=$id) $this->e = null; //if ($id && $this->e && $this->e_id!=$id) $this->e = null; if ($this->e && $this->e_id!=$id) $this->e = null; //if (self::$RELOAD) $this->e=null; //pr("reload is ".(int)self::$RELOAD); // Forcer la relecture de l'entité ? (seulement pour les tests) if (self::$RELOAD) $this->e=null; //debug("e is :"); debug($this->e); $control = "Controleur ".$this->name." avec id $id => "; if ($this->e) $this->d($control."OPTIMISATION: Utilisation du cache"); if (!$this->e) { $this->d($control."(RE)LOAD !!!"); // Les 3 sont possibles //$model = $this->request->getParam('controller'); // ex: Materiels //$model = $this->name; // ex: Materiels $model = $this->modelClass; // ex: Materiels /* debug("model2"); $model = $this->$model; debug($model); */ //ex: if (! $this->e) $this->e = $this->Materiels->get($this->e_id); //$this->e = $this->$model->get($this->e_id); $related_entities = $WITH_RELATED_MATERIEL ? ['Materiels']:[]; $this->e = $this->$model->get($id, ['contain'=>$related_entities]); $this->e_id = $this->e->id; } //pr($this->e); /* * Avec les entités associées : if (! $this->e) $this->e = $this->$model->get($this->e_id, [ 'contain' => ['Comments'] ]); */ //debug($this->e); return $this->e; } public function getUsersTable() { return TableRegistry::getTableLocator()->get('Users'); } // Retourne l'entity User qui a le login $userlogin ("epallier") public function getUserByLogin($userlogin) { if ($this->u && $this->u->username == $userlogin) return $this->u; //return $users->find()->where(['username' => $userlogin])->first(); return $this->getUsersTable()->findByUsername($userlogin); } // Retourne l'entity User qui a le nom complet $fullname ("Pallier Etienne") public function getUserByFullname($fullname) { if ($this->u && $this->u->nom == $fullname) return $this->u; //return $users->find()->where(['username' => $userlogin])->first(); return $this->getUsersTable()->findByNom($fullname); } /** * (EP) * Autorisations PAR DÉFAUT * Appelé à la fin de isAuthorized() de chaque controller si cette fonction n'a pas return true */ /* (EP) migré directement dans isAuthorized() public function isAuthorizedCommons($user) { $this->myDebug("step 2B (intermediaire general): AppController.isAuthorizedCommons(user)"); $action = $this->getActionPassed(); //$this->myDebug("action iss: $action", null, true); $this->myDebug("- action is: $action"); // $role = $this->getUserRole($user); // Seul Administration (et +) peut ajouter, supprimer ou modifier (pour la plupart des controleurs) if (in_array($action, ['add', 'edit', 'delete'])) return ($this->USER_IS_ADMIN_AT_LEAST()); /S if ($this->USER_IS_ADMIN_AT_LEAST()) return true; // Les autres n'y ont pas accès return false; S/ // Sinon, on applique les règles générales par défaut // Ne pas faire ça car $this sera interprété comme le controleur SPECIFIQUE et non AppController : //return $this->isAuthorized($user); // Donc, il faut être explicite : return AppController::isAuthorized($user); } */ /** * * @param $user * @return boolean isAuthorized is located in the Auth component * Check whether a LOGGED in user has a set of permissions to perform a given action * Give authorization in general * * Autorisations APRES connexion, donc à partir d'ici le user est obligatoirement identifié * (AVANT connexion, c'est initialize() et beforeFilter() qui gèrent) * * On tente d’autoriser ici les actions qui n’ont pas été autorisées * par la méthode isAuthorized du controleur spécifique * * ref: https://book.cakephp.org/4/fr/controllers/components/authentication.html#autorisation * * $user est l'equivalent de $this->LdapAuth->user() * */ //public function isAuthorized(Array $user) { return $this->isAuthorizedAction($user=$user); } //public function isAuthorized(Array $user) { return AppController::isAuthorizedAction($user=$user); } //protected function isAuthorizedAction($action = null, $id=null, $role=null, $user=null, $userCname=null) { //public function isAuthorized(Array $user, $action=null) { public function isAuthorized($user, $action=null, $id=null, $role=null) { //$action=null, $id=null, $role=null, $userCname=null) { $this->myDebug("step 2C (general): AppController.isAuthorized()"); // $user est l'equivalent de $this->LdapAuth->user() $this->myDebug("- user is:", $user); //$action = $this->getActionPassed(); if (!$action) $action = $this->a; $this->myDebug("- action is: $action"); //if (!$id) $id = $this->getIdPassed(); if (!$id) $id = $this->e_id; /* $IS_RELATED_ENTITY_ID = false; return $this->isAuthorizedAction($action, $id, $IS_RELATED_ENTITY_ID); // $user, $userCname */ return $this->isAuthorizedActionForCurrentUser($action, $id); // $user, $userCname // LA SUITE EST A VIRER // $role = $this->getUserRole($user); /* * // ATTENTION, normalement, on devrait tester si role est défini..., mais c'est sans doute pas utile * // cf https://book.cakephp.org/3.0/fr/tutorials-and-examples/blog-auth-example/auth.html * if (isset($user['role']) && $user['role'] === 'admin') { * return true; * } */ //$configuration = $this->confLabinvent; //$role = $this->getUserRole($user); /* * $role = TableRegistry::getTableLocator()->get('Users')->find() * ->where(['username' => $user[$configuration->authentificationType_ldap][0]]) * ->first()['role']; */ ///$this->myDebug("- role is " . $this->user_role); /* $prefix = $this->request->getParam('prefix'); $this->myDebug("- prefix is $prefix"); */ // BETTER: // $action = $this->request->getAttribute('params')['action']; // $action = $this->request->getParam('action'); //$action = $this->getActionPassed(); // error_log($action); /* // Seul Administration (et +) peut ajouter, supprimer ou modifier (pour la plupart des controleurs) if (in_array($action, ['add', 'edit', 'delete'])) return ($this->USER_IS_ADMIN_AT_LEAST()); */ // On autorise ou pas l’action demandée : // - Super-Admin peut accéder à toutes les actions //if ($role == 'Super Administrateur') return true; //if ($this->USER_IS_SUPERADMIN) return true; if ($this->USER_IS_SUPERADMIN()) return true; // - Actions générales accessibles à TOUS les roles (profils), pour TOUT controleur if (in_array($action, [ 'add', 'index', 'view', 'find', /* (EP 202004) sale ! => migré dans chaque controleur spécifique concerné // QrCode 'creer', // Suivis 'getNextDate', // Materiels 'getDateGarantie' */ ])) return true; // - Pour toutes les autres actions, par défaut => accès refusé (denied) return false; } // isAuthorized() // (EP) Used by Materiels and Users Controllers protected function setUsersLists() { // On recup tous les users du LDAP (ou fakeLDAP si on n'est pas en mode LDAP) //$users = TableRegistry::get('LdapConnections')->getListUsers(); //sort($users); $users_login_and_email = TableRegistry::getTableLocator()->get('LdapConnections')->getUsersLoginAndEmail(); $users_name = array_keys($users_login_and_email); // Formatage en $users_option_list["Etienne Pallier"] = "Etienne Pallier" ... $users_option_list = []; for ($i = 0; $i < sizeof($users_name); $i ++) $users_option_list[$users_name[$i]] = $users_name[$i]; $this->set(compact( 'users_option_list', 'users_login_and_email' )); return $users_name; } // @deprecated public function getTablePriviledgedUserFromCurrentSessionUserIfExists($user = null) { return $this->getUserEntity($user); } public function getCurrentUserEntity() { return $this->getUserEntity(); } public function getUserEntity($user = null) { //if (! $this->CURRENT_PRIVILEDGED_USER) { //debug("user is"); debug($user); //debug("1)"); debug($_SESSION); if (! $this->u) { $configuration = $this->confLabinvent; $ldapAuthType = $configuration->ldap_authenticationType; // Dans les tests, $username est égal à qqch comme : 0 => 'user4_RESP' // par défaut, user est DEJA une Entity User => rien à faire // Si $user non défini ou bien array, il faut rechercher ce user dans la BD pour créer un User entity if (!$user || is_array($user)) { //debug("2)"); debug($_SESSION['Auth']['User'][$ldapAuthType]); // (EP 202006) Marche pas avec les TESTS : ça flingue carrément la variable $_SESSION !!! //$username = $user ? $user[$ldapAuthType] : $this->LdapAuth->user($ldapAuthType); // Donc je remplace par : $username = $user ? $user[$ldapAuthType] : $_SESSION['Auth']['User'][$ldapAuthType]; //debug("ldapAuthType is '$ldapAuthType'"); /* CAKEPHP 3 way : $req = $this->getRequest(); //debug($req); $session = $req->getSession(); debug($session->read()); //debug($session->read('Auth.User')); */ //debug("username is"); debug($username); //debug("3)"); debug($_SESSION); //debug($this->LdapAuth); //exit; if (!$username) throw new \ErrorException("L'utilisateur courant n'a pas été trouvé !!!"); //debug("user name is:"); debug($username); $username = $username[0]; $user = TableRegistry::getTableLocator()->get('Users') ->find() ->where(['username' => $username]) ->first(); // ->where(['username' => $this->LdapAuth->user('cn')[0]]) } // if (! $priviledgedUser) $priviledgedUser = "Unpriviledged User (not in table utilisateurs)"; $this->u = $user; } return $this->u; } public function getUserRole($user = null) { //if (! $this->CURRENT_ROLE) { if (! $this->user_role) { $priviledgedUser = $this->getTablePriviledgedUserFromCurrentSessionUserIfExists($user); // default role is "Utilisateur" (for people who are not in the table utilisateurs) //$this->CURRENT_ROLE = ($priviledgedUser) ? $priviledgedUser['role'] : 'Utilisateur'; $this->user_role = ($priviledgedUser) ? $priviledgedUser['role'] : 'Utilisateur'; } //return $this->CURRENT_ROLE; return $this->user_role; } private function userHasRole($expectedRole, $ORMORE = false) { $role = $this->getUserRole(); if (!$ORMORE) return ($role == $expectedRole); return ($this->getRoleLevel($role) >= $this->getRoleLevel($expectedRole)); /* * //$hasRole = false; * switch ($expectedRole) { * case 'Super Administrateur' : * return (in_array($role, ['Super Administrateur'])); * break; * case 'Administration Plus' : * return (in_array($role, ['Administration Plus', 'Super Administrateur'])); * break; * case 'Administration' : * return (in_array($role, ['Administration', 'Administration Plus', 'Super Administrateur' ])); * break; * case 'Responsable' : * return (in_array($role, ['Responsable', 'Administration', 'Administration Plus', 'Super Administrateur'])); * break; * case 'Utilisateur' : * return (in_array($role, ['Utilisateur', 'Responsable', 'Administration', 'Administration Plus', 'Super Administrateur'])); * break; * } * return $false; */ } public function userHasRoleAtLeast($expectedRole) { return $this->userHasRole($expectedRole, true); } public function USER_IS_ADMIN_AT_LEAST() { return $this->userHasRoleAtLeast('Administration'); } public function USER_IS_RESP_AT_LEAST() { return $this->userHasRoleAtLeast('Responsable'); } public function USER_IS_SUPERADMIN() { return $this->userHasRole('Super Administrateur'); } public function USER_IS_ADMIN() { return $this->userHasRole('Administration'); } public function USER_IS_RESP() { return $this->userHasRole('Responsable'); } public function USER_IS_USER() { return $this->userHasRole('Utilisateur'); } /** * Initialization hook method. * Use this method to add common initialization code like loading components. * e.g. `$this->loadComponent('Security');` * * ref: https://book.cakephp.org/4/fr/controllers/components/authentication.html#id1 * ref: https://book.cakephp.org/4/fr/controllers/components/authentication.html#configuration-des-gestionnaires-d-authentification * * @return void */ public function initialize() { $this->myDebug("step 0B (general): AppController.initialize()"); parent::initialize(); $this->loadComponent('RequestHandler'); $this->loadComponent('Flash'); // Composant en charge de l'authentification // - sans LDAP : /* $this->loadComponent('Auth', [ 'authenticate' => [ 'Form' => [ 'fields' => [ 'username' => 'email', 'password' => 'password' ] ] // avec finder redéfini 'Form' => [ 'finder' => 'auth' // va utiliser une méthode findAuth() dans UsersTable ] ], 'loginAction' => [ 'controller' => 'Users', 'action' => 'login' ], // If unauthorized, return them to page they were just on 'unauthorizedRedirect' => $this->referer() ]); // Allow the display action so our PagesController // continues to work. Also enable the read only actions. $this->Auth->allow(['display', 'view', 'index']); // Les autres actions sont redirigées sur /users/login */ // - avec LDAP : /* * If none of your users have hashed passwords, comment this block and $this->Auth->allow() calls. * (par exemple dans beforeFilter()) * Then go and edit the user, saving a new password for them. * After saving a new password for the user, * make sure to uncomment the lines we just temporarily commented! */ $this->loadComponent('LdapAuth', [ // Les AUTHORIZATIONS sont faites par Controleur // (et non pas par un Component ou plugin) // TODO: utiliser Authorization component plugin (cakephp v4) //'authorize'=> 'Controller', 'authorize' => ['Controller'], /* pour Auth (au lieu de LdapAuth) on aurait aussi mis ceci : 'authenticate' => [ 'Form' => [ 'fields' => [ 'userna100000000000000000000000000000000me' => 'email', 'password' => 'password' ] ] ], */ // Redirection après login : 'loginRedirect' => [ 'controller' => 'Pages', //'action' => 'home' 'action' => 'display', 'home' ], // Redirection après logout : 'logoutRedirect' => [ 'controller' => 'Pages', 'action' => 'home' ] ]); // On peut aussi configurer après : // Message d'erreur en cas de refus de connexion $this->LdapAuth->setConfig('authError', "Désolé, vous n'êtes pas autorisé à accéder à cette zone."); /* Autres possibilités de config : * $this->Auth->config('authenticate', [ * 'Form' => ['userModel' => 'Members'] * //'Basic' => ['userModel' => 'Members'], * ]); * $this->Auth->config('authorize', ['Controller']); */ // Actions autorisées SANS authentification // Allow the display action so our PagesController continues to work. // Also enable the read only actions. // Déplacé dans beforeFilter() //$this->LdapAuth->allow(['display', 'view', 'index']); // Autoriser TOUTES les actions SANS authentification : //$this->LdapAuth->allow(); // On charge la configuration /* $this->confLabinvent = TableRegistry::getTableLocator()->get('Configurations')->find() ->where([ 'id =' => 1 ]) ->first(); */ $this->confLabinvent = TableRegistry::getTableLocator()->get('Configurations')->find()->first(); // (EP 23/5/19) Exception si la config est vide, inutile d'aller plus loin ! if (is_null($this->confLabinvent)) throw new \Exception("EXCEPTION: La table 'configurations' de la base de données est vide"); // Initialisation des autorisations pour les actions du controleur // 1) Initialisation des autorisations par défaut du parent (AppController) $this->setDefaultAuthorizations(); // 2) Ajout des autorisations spécifiques par le controleur courant $SPECIFIC_METHOD_EXISTS = false; if ($this->confLabinvent->labNameShort) { $labshortname = $this->confLabinvent->labNameShort; $this->d("lab name is set to $labshortname"); $setAuthorizationsSpecific = "setAuthorizations_$labshortname"; // Si une méthode spécifique (dans le controleur courant) existe pour CE labo, on l'appelle à la place de la méthode générale // Par exemple pour l'IRAP, ça sera $this=>setAuthorizations_IRAP() : // if (method_exists($this, 'setAuthorizations_IRAP')) $this->setAuthorizations_IRAP(); if (method_exists($this, $setAuthorizationsSpecific)) { $SPECIFIC_METHOD_EXISTS = true; $this->$setAuthorizationsSpecific(); } } // Sinon, on appelle la méthode générale if (! $SPECIFIC_METHOD_EXISTS) $this->setAuthorizations(); } // initialize() // Méthode à spécialiser dans chaque controleur // Sinon, par défaut c'est celle-ci qui est utilisée et elle ne fait rien ! protected function setAuthorizations() {} // Actions autorisées par défaut pour TOUS les controleurs protected function setDefaultAuthorizations() { // autorisé pour tous $this->setAuthorizationsForAction('index (liste générale)', 0); $this->setAuthorizationsForAction('view (vue détaillée)', 0); $this->setAuthorizationsForAction('find (rechercher)', 0); /* $this->setAuthorizationsForAction('index', 0); $this->setAuthorizationsForAction('view', 0); $this->setAuthorizationsForAction('find', 0); */ // admin(+) only : $this->setAuthorizationsForAction('add(créer)', 0, [ //$this->setAuthorizationsForAction('add', 0, [ 'user' => -1, 'resp' => -1, ]); $this->setAuthorizationsForAction('edit (modifier)', 0, [ //$this->setAuthorizationsForAction('edit', 0, [ 'user' => -1, 'resp' => -1, ]); $this->setAuthorizationsForAction('delete (supprimer)', 0, [ //$this->setAuthorizationsForAction('delete', 0, [ 'user' => -1, 'resp' => -1, ]); //debug($this->is_authorized_action);exit; } protected function getCurrentUserName() { //debug($this->LdapAuth->user('id')); exit; if ($this->LdapAuth->user()) { if (! $this->userName) { $this->userName = $this->LdapAuth->user('sn')[0] . ' ' . $this->LdapAuth->user('givenname')[0]; } } // par défaut, null return $this->userName; } /** * * {@inheritdoc} * * @see \Cake\Controller\Controller::beforeFilter() * 1) Autorisations SANS (ou AVANT) connexion * 2) Ensuite, c'est isAuthorized qui gère * * Cette méthode est appelée pendant l’event Controller.initialize qui se produit * AVANT chaque action du controller. * C’est un endroit pratique pour vérifier le statut d’une session ou les permissions d’un utilisateur. * ATTENTION: cette méthode sera appelée pour les actions manquantes. * */ public function beforeFilter(Event $event) { // Affichages pour debug //pr($event); $this->myDebug("step 1B (general): AppController.beforeFilter()"); $controllerName = $this->request->getParam('controller'); $this->myDebug("- controller passed : $controllerName"); $passedArgs = $this->request->getParam('pass'); $this->myDebug("- args passed : ", $passedArgs); $query = $this->request->getQueryParams(); $this->myDebug("- query passed : ", $query); // Initialisations pour la suite // - L'entité concernée par l'action // Par défaut null car certaines actions n'ont pas d'entité (ex : 'add', 'find', 'index', ...) $this->e = null; // - L'action demandée et son id le cas échéant (nul par défaut, égal 0) $this->a = $this->getActionPassed(); $this->myDebug("- action passed : ".$this->a); //debug("- action passed : ".$this->a); $this->e_id = $this->getIdPassed(); $this->myDebug("- id passed : ".$this->a); parent::beforeFilter($event); // !!! Ne jamais autoriser l'action 'login', sinon cela va créer des problèmes sur le fonctionnement normal de AuthComponent (cf doc) !!! /* * EXEMPLES d'utilisation: * // to allow all access to all actions: * if (isset($this->Auth)) { * $this->Auth->allow('*'); * } * // Allow access to index & view actions: * if (isset($this->Auth)) { * $this->Auth->allowedActions = array('index', 'view'); * } */ // (EP 21/5/19) NEW $configuration = $this->confLabinvent; $D = $configuration->mode_debug; //$this->myDebug($configuration); // TODO: (EP) A quoi ça sert ??? $this->request->getSession()->write("authType", $configuration->ldap_authenticationType); // Groupes métier et technique // id du Groupe métier N/A /* $this->idGmNa = TableRegistry::getTableLocator()->get('GroupesMetiers') ->find()->where(['nom =' => 'N/A'])->first()['id']; // id du Groupe technique N/A $this->idGtNa = TableRegistry::getTableLocator()->get('GroupesThematiques') ->find()->where(['nom =' => 'N/A'])->first()['id']; */ $this->idGmNa = null; $this->idGtNa = null; // Utilisateur connecté (identifié) ? $this->myDebug("- Utilisateur connecté ? : ", $this->LdapAuth->user() ? "oui" : "non"); $this->myDebug($this->LdapAuth->user()); // Si le user est connecté (identifié), on positionne quelques variables utiles // - pour le controleur spécifique, // - et pour la vue //if ($configuration->ldap_used && !$this->); if ($this->LdapAuth->user()) { // ATTENTION, $priviledgedUser = NULL si l'utilisateur courant n'est pas un utilisateur privilégié // (c'est à dire s'il n'est pas dans la table "utilisateurs") //$this->priviledgedUser = $this->getTablePriviledgedUserFromCurrentSessionUserIfExists(); $this->u = $this->getTablePriviledgedUserFromCurrentSessionUserIfExists(); //$role = $this->getUserRole(); //$this->user_role = $this->getUserRole(); $this->user_role = $this->getUserRole(); $profile = self::PROFILES["$this->user_role"]; $this->myDebug("- priviledgedUser is {$this->u}"); $this->myDebug("- user_role is {$this->getUserRole()}", "- profile is: $profile"); // L'utilisateur connecté (return null si pas connecté) // $this->Auth->user('id'); //$this->userName = $this->getCurrentUserName(); //$this->set('username', $this->LdapAuth->user('sn')[0] . ' ' . $this->LdapAuth->user('givenname')[0]); $this->USER_IS_UTILISATEUR = ($profile == self::PROFILE_USER); $this->USER_IS_RESPONSABLE = ($profile == self::PROFILE_RESPONSABLE); $this->USER_IS_ADMIN = ($profile == self::PROFILE_ADMIN); $this->USER_IS_ADMINPLUS = ($profile == self::PROFILE_ADMINPLUS); $this->USER_IS_SUPERADMIN = ($profile == self::PROFILE_SUPERADMIN); $this->USER_IS_RESPONSABLE_OR_MORE = ($profile >= self::PROFILE_RESPONSABLE); $this->USER_IS_ADMIN_OR_MORE = ($profile >= self::PROFILE_ADMIN); $this->USER_IS_ADMINPLUS_OR_MORE = ($profile >= self::PROFILE_ADMINPLUS); // Positionne ces variables pour TOUTES les vues $this->set('role', $this->user_role); $this->set('profile', $profile); $this->set('username', $this->getCurrentUserName()); $this->set('priviledgedUser', $this->u); $this->set('USER_IS_UTILISATEUR', $this->USER_IS_UTILISATEUR); $this->set('USER_IS_ADMIN', $this->USER_IS_ADMIN); $this->set('USER_IS_ADMINPLUS', $this->USER_IS_ADMINPLUS); $this->set('USER_IS_SUPERADMIN', $this->USER_IS_SUPERADMIN); $this->set('USER_IS_RESPONSABLE_OR_MORE', $this->USER_IS_RESPONSABLE_OR_MORE); $this->set('USER_IS_RESPONSABLE', $this->USER_IS_RESPONSABLE); //$this->set(compact('USER_IS_ADMIN_OR_MORE')); $this->set('USER_IS_ADMIN_OR_MORE', $this->USER_IS_ADMIN_OR_MORE); $this->set('USER_IS_ADMINPLUS_OR_MORE', $this->USER_IS_ADMINPLUS_OR_MORE); // (EP) TODO: vraiment utile ??? A virer, non ? $this->set('PROFILE_USER', self::PROFILE_USER); $this->set('PROFILE_ADMIN', self::PROFILE_ADMIN); $this->set('PROFILE_RESPONSABLE', self::PROFILE_RESPONSABLE); $this->set('PROFILE_ADMINPLUS', self::PROFILE_ADMINPLUS); $this->set('PROFILE_SUPERADMIN', self::PROFILE_SUPERADMIN); // $this->set('allProfiles', $this->allProfiles); $this->set('allProfiles', self::PROFILES); } // Now, set these constants for all VIEWS $this->set(compact('configuration')); $this->set(compact('D')); $this->set('idGmNa', $this->idGmNa); $this->set('idGtNa', $this->idGtNa); // On autorise certaines actions SANS connexion (ces actions sont donc publiques) // - pour le mode spécial “installation” => on autorise pleins d’actions sans login // - pour le mode normal habituel => on autorise seulement l’action “display” pour quelques pages publiques (comme la page “about”) //$configuration = $this->confLabinvent; if ($configuration->mode_install) $this->LdapAuth->allow([ 'display', 'add', 'edit', 'installOff' ]); /* // Seule l'action display() est autorisée SANS authentification // (mais PagesController.display() va restreindre ça seulement à la page about) else $this->LdapAuth->allow(['display']); */ // Autoriser TOUTES les actions SANS authentification //$this->LdapAuth->allow(); $this->myDebug("- Actions allowed are: ", $this->LdapAuth->allowedActions); /* (EP 20200427 migré dans initialize()) // Message d'erreur en cas de refus de connexion $this->LdapAuth->setConfig('authError', "Désolé, vous n'êtes pas autorisé à accéder à cette zone."); */ } // beforeFilter() /** * Add or Edit method (do either add() or edit()) * => Factorisation de add() et edit() * (voir aussi https://book.cakephp.org/3.0/en/orm.html) * * @param $IS_ADD: True = add ; False = edit * @return \Cake\Network\Response|void Redirects on successful add/edit, renders view otherwise. */ //protected function add_or_edit($IS_ADD, $id=null, $values=null, $errors=null, $entity_name=null, array $associated_entities=[], $with_parent=false) { protected function add_or_edit($IS_ADD, $id=null, $errors=null, $entity_name=null, array $associated_entities=[], $with_parent=false) { // On refuse de creer une entité sans préciser l'id de l'entité parente associée (en général materiel id) if ($with_parent && $id===null) return; $controller = $this->request->getParam('controller'); $this->myDebug("step 3: $controller .add_or_edit()"); $IS_EDIT = !$IS_ADD; /* $this->entityBuilt = null; $this->parent = null; $this->parents = null; */ /* (EP 20200326) * Pour être plus générique, * On utilise désormais $entity au lieu d'un terme plus spécifique comme $emprunt * (ou $suivi ou $materiel pour les controleurs de Suivis et Materiels, ...) * On utilisera aussi $this->$controller au lieu de $this->Emprunts (ou $this->Suivis ou $this->Materiels, ...) */ $entity = ( $IS_ADD ? $this->$controller->newEntity() : // cf https://book.cakephp.org/3/fr/orm/retrieving-data-and-resultsets.html#eager-loading-associations // Ceci permettra des accès du type $suivi->type_suivi->nom depuis la vue //$this->Emprunts->get($id, ['contain' => ['TypeSuivis']]); $this->$controller->get($id, ['contain' => $associated_entities ]) ); //debug($suivi); // POST (on arrive ici après un SUBMIT) // add //if ($this->request->is('post')) { // edit if ($this->request->is(['patch','post','put'])) { //$entity = $this->Emprunts->patchEntity($suivi, $this->request->getData()); $entity = $this->$controller->patchEntity($entity, $this->request->getData()); // TODO : à virer, trouver comment faire ça autrement, c'est sale !!! if ($controller == 'Suivis') { if ($IS_ADD) { if ($this->request->getData('typemesure') !== null && $this->request->getData('typemesure') == "1") $entity->typemesure = "Indirect"; $entity->panne_resolu = false; } } $verb = $IS_ADD ? 'ajouté' : 'modifié'; // SAVE KO if (! $this->$controller->save($entity)) $this->Flash->error(__("$entity_name n'a pas pu être $verb")); // SAVED OK else { $this->Flash->success(__("$entity_name a bien été $verb")); if ($with_parent) { //$parent_id = $IS_ADD ? $this->request->getParam('pass.0') : $entity->materiel_id; $parent_id = $IS_ADD ? $id : $entity->materiel_id; // (EP) Redirection vers la vue parente (materiel emprunté) (depuis add ou edit) return $this->redirect([ 'controller' => 'Materiels', 'action' => 'view', $parent_id ]); } else { if ($IS_ADD) return $this->redirect([ 'action' => 'index', ]); else return $this->redirect([ 'action' => 'view', $id ]); } /* // ADD if ($IS_ADD) return $this->redirect([ 'controller' => 'Materiels', 'action' => 'view', $this->request->getAttribute('params')['pass'][0] ]); // EDIT else $this->setAction('view', $id); /S equivalent à else return $this->redirect([ 'action' => 'view', $id ]); S/ */ } } // POST // START (on arrive ici la première fois qu'on ouvre la vue) if ($with_parent) { $parents = $this->$controller->Materiels->find('list'); //$materiel_id = $IS_EDIT ? $entity->materiel_id : $this->request->getAttribute('params')['pass'][0]; //$parent_id = $IS_EDIT ? $entity->materiel_id : $this->request->getParam('pass.0'); $parent_id = $IS_EDIT ? $entity->materiel_id : $id; // parent = materiel $parent = $this->$controller->Materiels->get($parent_id); //$matos_id = $IS_ADD ? $parent->id : $entity->materiel_id; } //$materiel = $this->$controller->Materiels->get($materiel_id); /* (EP) inutile $numMateriel = $this->$controller->Materiels->find() ->select('numero_laboratoire') ->where([ 'id =' => $materiel_id ]) ->first()['numero_laboratoire']; */ $this->set(compact('IS_ADD','entity')); $with_parent && $this->set(compact('parent','parents')); /* (EP) inutile $this->set('_serialize', [ 'entity' ]); */ // On délare ces variables pour la méthode add_or_edit() du controleur spécifique // (car on ne peut pas faire un return !!!) $this->entityBuilt = $entity; $this->parent = $with_parent ? $parent : null; $this->parents = $with_parent ? $parents : null; } //add_or_edit() // Méthode utilisée (ou utilisable) par tous les controleurs liés à l'entité Materiel : Suivis, Emprunts, Documents (...) // Optimisée pour ne charger le "matériel lié" qu'une seule fois pour TOUS les controleurs intéressés protected function getMateriel($matos_id=null) { $control = $this->name; // ex: Suivis // Par défaut, on prend le matos id passé via la requete url //$parent_id = $IS_EDIT ? $entity->materiel_id : $this->request->getParam('pass.0'); //if (!$matos_id) $matos_id = $this->request->getParam('pass.0'); if (!$matos_id) $matos_id = $this->getIdPassed(); //debug($control); //$model = $this->modelClass; // ex: Suivis $m = AppController::$related_materiel; /* (EP) Si le materiel en mémoire n'est pas celui demandé, on le met à null pour qu'il soit rechargé * * => En utilisation normale, hors test, pas besoin de faire ça. * => C'est uniquement pour les TESTS car sinon ils ne passent pas... * car les tests utilisent la MEME instance du controleur pour faire plusieurs posts avec des id différents * (alors qu'en utilisation hors test, l'instance est recréée à chaque appel du style materiels/view/11995 puis materiels/view/11963... * et donc AppController::$related_materiel est remis à null à chaque fois) * Exemple : * - $this->post("/emprunts/add/1", $data); * - $this->post("/emprunts/add/3", $data); * - ... * (idem pour suivis) */ ////if ($matos_id && $m && $matos_id!=$m->id) $m = null; if ($m && $matos_id!=$m->id) $m = null; // Forcer la relecture du materiel ? (pour les tests) if (self::$RELOAD) $m=null; // Si le matériel n'est pas encore en mémoire, on va le chercher en BD // Moins optimisé : Un exemplaire PAR controleur appelant (car attribut d'instance) : //if (!$this->related_materiel) { // Très optimisé : Un seul exemplaire (singleton car attribut de classe) quelquesoit le controleur qui appelle cette méthode : if (! $m) { //debug("load, matos_id=$matos_id"); // UNE FOIS SEULEMENT !!! (pour tous les controleurs) /* // Par défaut, on prend le matos id passé via la requete url //$parent_id = $IS_EDIT ? $entity->materiel_id : $this->request->getParam('pass.0'); if (!$matos_id) $matos_id = $this->request->getParam('pass.0'); */ //$this->related_materiel = $this->Suivis->Materiels->get($matos_id); //$this->related_materiel = $this->$control->Materiels->get($matos_id); $m = AppController::$related_materiel = $this->$control->Materiels->get($matos_id); assert($m->id == AppController::$related_materiel->id); //debug($this->related_materiel); exit; } //return $this->related_materiel; return $m; } public function afterFilter(Event $event) { $this->myDebug("step ?? (general): AppController.afterFilter()"); // Tout le temps 'index', why ??N //debug($this->request->getAttribute('params')['action']); if (in_array($this->request->getAttribute('params')['action'], [ 'edit', 'add' ])) $this->request->getSession()->write("retourForm1", true); else if ($this->request->getAttribute('params')['action'] != 'creer') $this->request->getSession()->write("retourForm1", false); //exit; } /** * Before render callback. * * @param \Cake\Event\Event $event * The beforeRender event * @return void */ public function beforeRender(Event $event) { // TODO: ? // cf https://book.cakephp.org/4/en/views/themes.html //$this->viewBuilder()->setTheme('Modern'); // this theme would be found in plugins/Modern/templates $this->myDebug("step 4B (general) : AppController.beforeRender() - [step 3 = action() si existe]"); // (EP 23/5/19) moved to beforeFilter() /* $this->set('PROFILE_USER', self::PROFILE_USER); $this->set('PROFILE_ADMIN', self::PROFILE_ADMIN); $this->set('PROFILE_RESPONSABLE', self::PROFILE_RESPONSABLE); $this->set('PROFILE_ADMINPLUS', self::PROFILE_ADMINPLUS); $this->set('PROFILE_SUPERADMIN', self::PROFILE_SUPERADMIN); // $this->set('allProfiles', $this->allProfiles); $this->set('allProfiles', self::PROFILES); */ // Ca sert à quoi ??? if (! array_key_exists('_serialize', $this->viewVars) && in_array($this->response->type(), [ 'application/json', 'application/xml' ])) $this->set('_serialize', true); // (EP 21/5/19) moved to beforeFilter() //$this->set('username', $this->LdapAuth->user('sn')[0] . ' ' . $this->LdapAuth->user('givenname')[0]); // moved to beforeFilter() // TODO: (EP) A quoi ça sert ??? /* $configuration = $this->confLabinvent; $this->set('configuration', $configuration); $this->request->getSession()->write("authType", $configuration->ldap_authenticationType); */ // moved to beforeFilter() //$priviledgedUser = $this->getTablePriviledgedUserFromCurrentSessionUserIfExists(); /* * $user = TableRegistry::getTableLocator()->get('Users')->find() * ->where(['username' => $this->LdapAuth->user($configuration->authentificationType_ldap)[0]]) * ->first(); * $role = $user['role']; * if ($role == null) * $role = 'Utilisateur'; */ // Role = 'Utilisateur', 'Responsable", ... // (EP 21/5/19) moved to beforeFilter() /* $role = $this->getUserRole(); $this->set('role', $role); */ // Profile = PROFILE_USER (=1), PROFILE_RESPONSABLE (=2), ... // $profile = $this->allProfiles["$role"]; // (EP 21/5/19) moved to beforeFilter() /* $profile = self::PROFILES["$role"]; $this->set('profile', $profile); */ // (EP 21/5/19) moved to beforeFilter() /* $USER_IS_UTILISATEUR = ($profile == self::PROFILE_USER); $USER_IS_ADMIN = ($profile == self::PROFILE_ADMIN); $USER_IS_ADMINPLUS = ($profile == self::PROFILE_ADMINPLUS); $USER_IS_SUPERADMIN = ($profile == self::PROFILE_SUPERADMIN); $USER_IS_RESPONSABLE_OR_MORE = ($profile >= self::PROFILE_RESPONSABLE); $USER_IS_RESPONSABLE = ($profile == self::PROFILE_RESPONSABLE); $USER_IS_ADMIN_OR_MORE = ($profile >= self::PROFILE_ADMIN); $USER_IS_ADMINPLUS_OR_MORE = ($profile >= self::PROFILE_ADMINPLUS); $this->set('USER_IS_UTILISATEUR', $USER_IS_UTILISATEUR); $this->set('USER_IS_ADMIN', $USER_IS_ADMIN); $this->set('USER_IS_ADMINPLUS', $USER_IS_ADMINPLUS); $this->set('USER_IS_SUPERADMIN', $USER_IS_SUPERADMIN); $this->set('USER_IS_RESPONSABLE_OR_MORE', $USER_IS_RESPONSABLE_OR_MORE); $this->set('USER_IS_RESPONSABLE', $USER_IS_RESPONSABLE); $this->set(compact('USER_IS_ADMIN_OR_MORE')); $this->set('USER_IS_ADMINPLUS_OR_MORE', $USER_IS_ADMINPLUS_OR_MORE); $this->set('priviledgedUser', $priviledgedUser); */ /* * @todo EP 08/2017 Nouvelle organisation des ACL avec $easyACL */ //$action = $this->getActionPassed(); if (in_array($this->a, array( 'add', 'edit', 'view', 'index' ))) { $hiddenFields = $this->getHiddenFieldsForAction($this->a); $this->set('hiddenFields', $hiddenFields); $this->myDebug(compact("hiddenFields")); if (in_array($this->a, array( 'add', 'edit' ))) { $mandatoryFields = $this->getMandatoryFieldsForAction($this->a); $this->set('mandatoryFields', $mandatoryFields); $readOnlyFields = $this->getReadOnlyFieldsForAction($this->a); $this->set('readOnlyFields', $readOnlyFields); $haveDefaultValueFields = $this->getDefaultValueFieldsForAction($this->a); // only for DEBUG : //$this->myDebug("mandat, ro, default fields=", $mandatoryFields, $readOnlyFields, $haveDefaultValueFields); $this->set(compact('haveDefaultValueFields')); //$mandatoryFields = array("un"=>"mand", "deux"=>"alkjl"); $this->myDebug(compact("mandatoryFields")); $this->myDebug(compact("readOnlyFields")); $this->myDebug(compact("haveDefaultValueFields")); } } // Moved to beforeFilter() /* $this->set('idGmNa', TableRegistry::getTableLocator()->get('GroupesMetiers')->find() ->where([ 'nom =' => 'N/A' ]) ->first()['id']); $this->set('idGtNa', TableRegistry::getTableLocator()->get('GroupesThematiques')->find() ->where([ 'nom =' => 'N/A' ]) ->first()['id']); */ // Pass this function to all views $mydebug = function($debugmode, $arg, $stop=false) { if ($debugmode) { // Absolument nécessaire sur inventirap (à cause de php 5 ?) // car sinon, aucun vardump() ou debug() ne s'affiche, why ???... //Configure::write('debug', true); debug($arg); if ($stop) exit(); } }; $this->set(compact('mydebug')); // Pass this function to all views $displayElement = function ($nom, $valeur, $params = "") { $TD = ($params=="") ? 'TD' : "TD $params"; //$TD = ($params=="") ? '' : ''; //$tdstyle = $params!="" ? $params : ''; // Ca c'est parce que sinon y'a au moins deux tests qui passent pas, a cause de l'espace dans la balise ... //if ($valeur != "") echo ' '.$nom.' ' . $TD.$valeur.''; //if ($valeur != "") echo '' . $nom . ' ' . $balise . $valeur . ''; if ($valeur!="") echo " $nom <$TD>$valeur "; }; $printTableRow = $displayElement; $this->set(compact('printTableRow')); //@deprecated $this->set('displayElement', $displayElement); // Pass this function to all views // @todo : Si cette fonction ne concerne que SuivisController, il faut la déplacer dans ce controleur $dateProchainControleVerif = function ($t) { $time = Time::now(); // On récupère la date et l'heure actuelles $today = new \DateTime((new date("$time->year-$time->month-$time->day"))->format('Y-m-d')); $time1 = new time($t); $dateTime1 = new \DateTime((new date("$time1->year-$time1->month-$time1->day"))->format('y-m-d')); $interval = ($today->diff($dateTime1)); $strInterval = $interval->format('%a'); return (int) $strInterval; }; $this->set('dateProchainControleVerif', $dateProchainControleVerif); // Pass this function to all views //function echoActionButton($html, $icon_class, $title, $action, $id, $tip='', $controller='materiels', $mat=NULL, $photo=NULL) { //$echoActionButton = function($html, $icon_class, $buttonStyle='', $title, $controller='', $action, $id, $other_args=[], $tip='', $confirmMessage='') { $getActionButton = function($html, $icon_class, $buttonStyle, $title, $controller, $action, $id, $other_args=[], $tip='', $confirmMessage='', $moreButtonStyle='') { if ($controller=='') $controller='materiels'; $controllerArgs = []; $controllerArgs['controller'] = $controller; $controllerArgs['action'] = $action; $controllerArgs[] = $id; foreach ($other_args as $other_arg) $controllerArgs[] = $other_arg; return $html->link( __("$title"), $controllerArgs, /* [ 'controller' => $controller, 'action' => $action, $id, $other_args ], */ [ 'title' => $tip, 'escape' => false, 'onclick' => 'return true;', //'style' => 'margin-right: 10px'.$moreButtonStyle, 'style' => $buttonStyle, 'confirm' => $confirmMessage ] ); }; $echoActionButton = function($html, $icon_class, $buttonStyle, $title, $controller, $action, $id, $other_args=[], $tip='', $confirmMessage='', $moreButtonStyle='') { if ($controller=='') $controller='materiels'; $controllerArgs = []; $controllerArgs['controller'] = $controller; $controllerArgs['action'] = $action; $controllerArgs[] = $id; foreach ($other_args as $other_arg) $controllerArgs[] = $other_arg; echo $html->link( __("$title"), $controllerArgs, /* [ 'controller' => $controller, 'action' => $action, $id, $other_args ], */ [ 'title' => $tip, 'escape' => false, 'onclick' => 'return true;', //'style' => 'margin-right: 10px'.$moreButtonStyle, 'style' => $buttonStyle, 'confirm' => $confirmMessage ] ); }; $this->set(compact('getActionButton', 'echoActionButton')); // Pass this function to all views (en fait, seulement add.ctp et edit.ctp) //function echoSubmitButtons($context, $matos_id) { // $action : 'view' or 'index' //$echoSubmitButtons = function($context, $action, $matos_id=null, $controller=null) { $echoSubmitButtons = function($context, $action, $matos_id=null, $controller=null) { // - Bouton Enregistrer echo '
'; //echo '
'; echo "\n"; echo $context->Form->input('Enregistrer', ['type'=>'submit', 'value'=>'Submit', 'class'=>'btn btn-primary']); //echo $context->Form->button(('Annuler'), ['action' => 'view', $matos_id], ['escape' => false,'onclick' => 'return true;','style' => 'margin-right: 10px']); //echo $context->Html->link(__('Annuler'), ['action' => 'view', $matos_id], ['class' => 'btn btn-info ', 'escape' => false]); echo "\n"; //echo '
'; $action_params = ['action'=>$action, $matos_id]; if ($controller) $action_params['controller'] = $controller; //echo $context->Html->link(__('Annuler'), [$controller, 'action'=>$action, $matos_id], ['class'=>'btn btn-outline-dark btn-sm', 'style'=>"text-decoration:none;", 'escape'=>false]); echo $context->Html->link(__('Annuler'), $action_params, ['class'=>'btn btn-outline-dark btn-sm', 'style'=>"text-decoration:none;", 'escape'=>false]); //echo '
'; echo "\n"; echo '
'; /* //echo $this->Form->submit(__('Enregistrer')); echo $context->Form->button('Enregistrer', ['class'=>'btn btn-outline-success', 'type'=>'submit']); // - Bouton Cancel //echo $this->Html->link(__(' Annuler'), ['action' => 'view', $materiel->id], ['escape' => false,'onclick' => 'return true;','style' => 'margin-right: 10px']); echo $context->Form->button(('Annuler'), ['action' => 'view', $matos_id], ['escape' => false,'onclick' => 'return true;','style' => 'margin-right: 10px']); //echo ''; //echo 'Cancel'; */ //} }; $this->set(compact('echoSubmitButtons')); } // beforeRender() // "le materiel", "le suivi", "l'emprunt", "la catégorie"... public function getArticle() { return "Le "; } static function isLabinventDebugMode() { return TableRegistry::getTableLocator()->get('Configurations')->find()->first()->mode_debug; /* return TableRegistry::getTableLocator()->get('Configurations')->find() ->where([ 'id =' => 1 ]) ->first()->mode_debug; */ } /* Fonction de log * * cf https://book.cakephp.org/3/fr/core-libraries/logging.html * */ function ilog($msg=null) { //$controller = $this->request->getParam('controller'); //$action = $this->getActionPassed(); $role = $this->getUserRole(); // ex: $this->log("/materiels/edit/12009" fait par ()", 'debug'); //debug($this->request); //debug($this->request->getParam('pass.0')); //debug($this->request->getParam('action')); //debug($this->request->url); $url = $this->request->getPath(); $user = $this->getCurrentUserName(); //debug("$url fait par $user ($role) ($msg)"); //$this->log("$url fait par $user ($role). $msg", 'debug'); //Log::write('info', "$url fait par $user ($role). $msg"); $this->log("$url fait par $user ($role). $msg\n", 'info'); /* Autres formes possibles Log::write('debug',$msg); (https://book.cakephp.org/3/fr/core-libraries/logging.html#scopes-de-journalisation) Log::debug('this gets written only to shops.log', ['scope' => ['orders']]); Log::warning('this gets written only to shops.log', ['scope' => ['orders']]); Log::warning('This is a warning', ['orders']); Log::warning('This is a warning', 'payments'); */ } function myDebug($arg1, $arg2=null, $stop=false) { if ($this->isLabinventDebugMode()) { // Absolument nécessaire sur inventirap (à cause de php 5 ?) // car sinon, aucun vardump() ou debug() ne s'affiche, why ???... Configure::write('debug', true); debug($arg1); if ($arg2) debug($arg2); if ($stop) exit(); } } /** * Envoi un mail avec un sujet, contenant un message à destination d'une liste de mails, selon l'action effectuée. * * @param $entity : * L'entité concernée (principalement un Matériel, mais ça peut aussi etre un Document) * @param $subject : * Sujet du message à envoyer. Si $subject n'est pas renseigné, un sujet par défaut sera généré. * @param $msg : * Message à envoyer. Si $msg n'est pas renseigné, un message par défaut sera généré. */ public function sendEmail($entity, $subject=null, $msg=null) { /* * $_SESSION['Auth']['User'] pour retrouver TOUTES les infos de la session courante (tout est du string) : * nom $_SESSION['Auth']['User']['sn'][0] * prenom $_SESSION['Auth']['User']['givenname'][0] * mail $_SESSION['Auth']['User']['mail'][0] * login $_SESSION['Auth']['User']['xxx'][0] /!\ Ce champ est suceptible de changer de nom, dans les tests ce champ est ['cn'][0] * mdp $_SESSION['Auth']['User']['userpassword'][0] */ $configuration = $this->confLabinvent; $action = $this->request->getAttribute('params')['action']; // add or edit or delete or ... // Si les deux cases "Activer l'envoi des mails.." sont décochées, on se fatigue pas à exécuter la fonction if (! $configuration->envoi_mail && ! $configuration->envoi_mail_guests) return null; $mailList = array(); // On détermine le message et le sujet du mail en fonction de l'action effectuee $acteur = $_SESSION['Auth']['User']['givenname'][0] . ' ' . $_SESSION['Auth']['User']['sn'][0]; // if ($entity != null) { if ($entity instanceof Materiel) { $materiel = $entity; $nom_materiel = $materiel->designation; if ($subject==null && $msg==null) { $msgMore = ''; Switch ($action) { case 'add': $subject = "Ajout d'un matériel"; $msg = "$acteur a ajouté le matériel \"$nom_materiel\""; break; // case 'edit': //$subject = "Modification d'un matériel"; //$msg = "$acteur a modifié le matériel \"$nom_materiel\""; // break; case 'delete': $subject = "Suppression d'un matériel"; $msg = "$acteur a supprimé le matériel \"$nom_materiel\""; // @todo: mettre le nom des domaine, categ, et sous-categ, et non pas l'id if ($materiel->sur_categorie_id != "") $msgMore .= "\n\nDomaine : " . $materiel->sur_categorie_id; if ($materiel->categorie_id != "") $msgMore .= "\n\nCatégorie : " . $materiel->categorie_id; if ($materiel->sous_categorie_id != "") $msgMore .= "\n\nSous-catégorie : " . $materiel->sous_categorie_id; if ($materiel->description != "") $msgMore .= "\n\nDescription :\n" . $materiel->description; break; //case 'statusCreated': //$subject = "Dé-validation d'un matériel"; //$msg = "$acteur a dé-validé le matériel \"$nom_materiel\""; // break; //case 'statusValidated': //$subject = "Validation d'un matériel"; //$msg = "$acteur a validé le matériel \"$nom_materiel\""; // break; case 'statusTobearchived': $subject = "Demande d'archivage d'un matériel"; $msg = "$acteur a demandé l'archivage du matériel \"$nom_materiel\""; break; case 'statusArchived': $subject = "Archivage d'un matériel"; $msg = "$acteur a archivé le matériel \"$nom_materiel\""; break; case 'setLabelIsPlaced': $subject = "Etiquette posée sur un matériel"; $msg = "Etiquette posée sur le matériel \"$nom_materiel\""; break; case 'printLabelRuban': $subject = "Etiquette imprimée"; $msg = "L'étiquette concerant votre matériel \"$nom_materiel\" a été imprimée"; $mailList[0] = $materiel->email_responsable; default: $subject = "Action \"$action\" sur un matériel"; $msg = "$acteur a effectué l'action \"$action\" sur le matériel \"$nom_materiel\""; break; } // end switch // (EP) Ajout de l'ID du materiel !!! $msg .= " (id=" . $materiel->id . ")."; // Only for "delete" action (for the moment...) if ($msgMore) $msg .= $msgMore; // $msg .= "\n\n"; } // subject is null // Et maintenant on construit la liste de mails... // Si l'envoi général est activé (et que l'action ne correspond pas à 'printLabelRuban'): if ($configuration->envoi_mail && $action != 'printLabelRuban') { // owner's mail (utilisateur du matériel) $mailList[0] = $materiel->email_responsable; // resp's mail $mailsRespMetier = null; $mailRespThematique = null; //if ($materiel->groupes_metier_id != null && $materiel->groupes_metier_id != 1) { if ($materiel->groupes_metier_id) { // Le ..!= 1 c'est parce que le groupe métier/thématique d'id 1 correspond au groupe N/A, soit aucun groupe $mailsRespMetier = TableRegistry::getTableLocator()->get('Users')->find() ->select('email') ->where([ 'role =' => 'Responsable', 'groupes_metier_id =' => $materiel->groupes_metier_id ]) ->toArray(); $mailRespThematique = TableRegistry::getTableLocator()->get('Users')->find() ->select('email') ->where([ 'role =' => 'Responsable', 'groupes_thematique_id =' => $materiel->groupes_thematique_id ]) ->toArray(); } if ($mailsRespMetier != null || $mailRespThematique != null) { $mailsResp = array_unique(array_merge($mailsRespMetier, $mailRespThematique)); for ($i = 0; $i < sizeof($mailsResp); $i ++) { $mailList[] = $mailsResp[$i]['email']; // $mailList[sizeof($mailList)] = $mailsResp[$i]['email']; } } // mail admin de reference (ici appele gestionnaire) -> Partie administration // Cela a été mis en commentaire car de toute façon l'utilisateur va voir un administratif pour faire valider sa fiche, // Pas la peine de spam l'administration de mails non plus hein ! /* * if ($action != 'statusValidated' && $action != 'statusArchived') { * $mailsAdmin = TableRegistry::getTableLocator()->get('Users')->find()->select('email') * ->where(['role =' => 'Administration']) * ->toArray(); * for ($i = 0; $i < sizeof($mailsAdmin); $i ++) { * $mailList[sizeof($mailList)] = $mailsAdmin[$i]['email']; * } * } */ } } // Materiel // @todo: ajouter quelques infos dans ces cas : else if ($entity instanceof Document) { ; } else if ($entity instanceof Suivi) { ; } else if ($entity instanceof Emprunt) { ; } /* * @todo: * else if ($entity instanceof Configuration) { * ; * } * ... etc ... (il faut qu'on soit plus précis) */ // Si l'envoi à la liste spécifiée est activé (et que l'action ne correspond pas à 'printLabelRuban'): $specificUsers = []; if ($configuration->envoi_mail_guests && $action != 'printLabelRuban') { // mail aux adresses specifiees dans la config for ($i = 0; $i < 11; $i ++) { $specificUser = $configuration['emailGuest' . $i]; if ($specificUser) $specificUsers[] = $specificUser; // $mailList[sizeof($mailList)] = $configuration['emailGuest' . $i]; $mailList[] = $specificUser; // Le if vérifie que la ligne soit pas null } } // On dedoublonne la liste des mails, c'pas tres cool de se faire spam 2-3 fois pour la meme action sur le meme materiel, non mais ! $mailList = array_unique($mailList); // ... Pour envoyer les mails aux personnes concernees foreach ($mailList as $mail) { // On envoi des mails à toute la liste, sauf pour "l'acteur", il sait ce qu'il a fait, pas besoin de le spam non plus hein if ($mail == $_SESSION['Auth']['User']['mail'][0]) continue; $message = $msg; // Sisi, cette variable $message est utile, m'enfin vous pouvez toujours essayer de la supprimer ..... Et pensez à regarder le contenu de vos mails !!! Sinon ca fait une tumeur // Génération du message "Vous recevez ce message en tant que $role" // Si $role inexistant (lorsque c'est un mail de la liste entrée en configuration), le message est plutot "Vous recevez ce message car vous avez demandé à le recevoir. [...]" if ($specificUsers) $role = "car vous etes dans la liste spécifique des emails de LabInvent. \n\nPour faire retirer votre mail de cette liste, veuillez contacter un SuperAdmin."; else { $role = TableRegistry::getTableLocator()->get('Users')->find() ->select('role') ->where([ 'email =' => $mail ]) ->first()['role']; // Default role is Utilisateur (for people in LDAP but without priviledge, not in the users table) if (is_null($role)) $role = 'Utilisateur'; $role = 'en tant que ' . $role; } if ($entity != null && ! in_array($action, [ 'delete', 'statusValidated', 'statusCreated' ])) $message .= "\n\nVeuillez vérifier et compléter si besoin la fiche correspondante."; $message .= "\n\nVous recevez ce message " . $role; $this->sendEmailTo("$subject", $message, $mail, $configuration); } return $mailList; } // Fonction d'envoi de mails private function sendEmailTo($subject, $msg, $mail, $config) { if ($mail != null && ! $config->test) { if (filter_var($mail, FILTER_VALIDATE_EMAIL)) { $email = new Email(); $etiquetteFrom = explode("@", $config->sender_mail); $email->transport('default') ->from([ $config->sender_mail => $etiquetteFrom[0] ]) ->to($mail) ->subject("[LabInvent] " . $subject) ->send($msg); } } } // Fonction d'envoi de mails avec photo jointe private function sendEmailImgTo($subject, $msg, $mail, $config, $nomImg) { if ($mail != null && ! $config->test) { if (filter_var($mail, FILTER_VALIDATE_EMAIL)) { $email = new Email(); $etiquetteFrom = explode("@", $config->sender_mail); // (EP) Je vais tuer le stagiaire qui a fait ça : //$email->attachments(["/var/www/html/labinvent/webroot/img/photos/$nomImg"]); // Il fallait plutot faire ça : $wwwroot_dir = new \Cake\Filesystem\Folder(WWW_ROOT); $absFileName = $wwwroot_dir->pwd() . DS . 'img' . DS . 'photos' . DS . $nomImg; $email->attachments([$absFileName]); $email->transport('default') ->from([ $config->sender_mail => $etiquetteFrom[0] ]) ->to($mail) ->subject("[LabInvent] " . $subject) ->send($msg); } } } // MI Fonction d'envoi de mails avec pièce jointe private function sendEmailPJTo($subject, $msg, $mail, $config, $nomDoc) { if ($mail!=null && !$config->test) { if (filter_var($mail, FILTER_VALIDATE_EMAIL)) { $email = new Email(); $etiquetteFrom = explode("@", $config->sender_mail); // (EP) Je vais tuer le stagiaire qui a fait ça : //$email->attachments(["/var/www/html/labinvent/webroot/files/$nomDoc"]); // Il fallait plutot faire ça : $wwwroot_dir = new \Cake\Filesystem\Folder(WWW_ROOT); //$absFileName = $wwwroot_dir->pwd() . DS . 'files' . DS . $nomDoc; $extension = explode(".", $nomDoc)[1]; // Photo ou doc ? $path_to_doc = in_array($extension, ['png','jpg','jpeg']) ? 'img'.DS.'photos' : 'files'; $absFileName = $wwwroot_dir->pwd().$path_to_doc.DS.$nomDoc; $email->attachments([$absFileName]); /* debug($mail); debug($etiquetteFrom); debug($absFileName); debug($email); exit; */ $email->transport('default') ->from([ $config->sender_mail => $etiquetteFrom[0] ]) ->to($mail) ->subject("[LabInvent] " . $subject) ->send($msg); } } } /**Version MI - version modifiée de la fonction sendEmail par malik du 18 juin au 24 août * * Envoi un mail avec un sujet, contenant un message à destination d'un email, selon l'action effectuée. * * @param $entity : * L'entité concernée (principalement un Matériel, mais ça peut aussi etre un Document) * @param $subject : * Sujet du message à envoyer. Si $subject n'est pas renseigné, un sujet par défaut sera généré. * @param $msg : * Message à envoyer. Si $msg n'est pas renseigné, un message par défaut sera généré. */ public function sendmail($entity, $mode, $subject = null, $msg = null) { //$this->myDebug("photo send mail"); //debug("photo send mail"); //exit; /* * $_SESSION['Auth']['User'] pour retrouver TOUTES les infos de la session courante (tout est du string) : * nom $_SESSION['Auth']['User']['sn'][0] * prenom $_SESSION['Auth']['User']['givenname'][0] * mail $_SESSION['Auth']['User']['mail'][0] * login $_SESSION['Auth']['User']['xxx'][0] /!\ Ce champ est suceptible de changer de nom, dans les tests ce champ est ['cn'][0] * mdp $_SESSION['Auth']['User']['userpassword'][0] */ $configuration = $this->confLabinvent; $action = $this->request->getAttribute('params')['action']; // add or edit or delete or ... // Si les deux cases "Activer l'envoi des mails.." sont décochées, on se fatigue pas à exécuter la fonction if (!$configuration->envoi_mail && !$configuration->envoi_mail_guests) return null; $mailList = []; // On détermine le message et le sujet du mail en fonction de l'action effectuee // on bloque l'envoi de mail à l'edition et à la validation pour eviter trop d'envoi de mail // le temps que soit trouvé une autre solution $acteur = $_SESSION['Auth']['User']['givenname'][0] . ' ' . $_SESSION['Auth']['User']['sn'][0]; /* * - mail pour un MATERIEL */ // if ($entity != null) { if ($entity instanceof Materiel) { $materiel = $entity; $nom_materiel = $materiel->designation; if ($subject == null && $msg == null) { $msgMore = ''; Switch ($action) { case 'add': $subject = "Ajout d'un matériel"; $msg = "$acteur a ajouté le matériel \"$nom_materiel\""; break; case 'edit': $subject = "Modification d'un matériel"; $msg = "$acteur a modifié le matériel \"$nom_materiel\""; break; case 'delete': $subject = "Suppression d'un matériel"; $msg = "$acteur a supprimé le matériel \"$nom_materiel\""; // @todo: mettre le nom des domaine, categ, et sous-categ, et non pas l'id if ($materiel->sur_categorie_id != "") $msgMore .= "\n\nDomaine : " . $materiel->sur_categorie_id; if ($materiel->categorie_id != "") $msgMore .= "\n\nCatégorie : " . $materiel->categorie_id; if ($materiel->sous_categorie_id != "") $msgMore .= "\n\nSous-catégorie : " . $materiel->sous_categorie_id; if ($materiel->description != "") $msgMore .= "\n\nDescription :\n" . $materiel->description; break; case 'statusCreated': $subject = "Dé-validation d'un matériel"; $msg = "$acteur a dé-validé le matériel \"$nom_materiel\""; break; case 'statusValidated': $subject = "Validation d'un matériel"; $msg = "$acteur a validé le matériel \"$nom_materiel\""; break; case 'statusTobearchived': $subject = "Demande d'archivage d'un matériel"; $msg = "$acteur a demandé l'archivage du matériel \"$nom_materiel\""; break; case 'statusArchived': $subject = "Archivage d'un matériel"; $msg = "$acteur a archivé le matériel \"$nom_materiel\""; break; case 'setLabelIsPlaced': $subject = "Etiquette posée sur un matériel"; $msg = "Etiquette posée sur le matériel \"$nom_materiel\""; break; case 'printLabelRuban': $subject = "Etiquette imprimée"; $msg = "L'étiquette concerant votre matériel \"$nom_materiel\" a été imprimée"; $mailList[0] = $materiel->email_responsable; default: $subject = "Action \"$action\" sur un matériel"; $msg = "$acteur a effectué l'action \"$action\" sur le matériel \"$nom_materiel\""; break; } // end switch // (EP) Ajout de l'ID du materiel !!! $msg .= " (id=" . $materiel->id . ")."; // Only for "delete" action (for the moment...) if ($msgMore) $msg .= $msgMore; // $msg .= "\n\n"; } // subject is null // Et maintenant on construit la liste de mails... // Si l'envoi général est activé (et que l'action ne correspond pas à 'printLabelRuban'): if ($configuration->envoi_mail && $action != 'printLabelRuban') { // owner's mail (utilisateur du matériel) $mailList[0] = $materiel->email_responsable; // resp's mail $mailsRespMetier = []; $mailRespThematique = []; //TODO: changer ça car c'est pas forcément id=1 //if ($materiel->groupes_metier_id != null && $materiel->groupes_metier_id != 1) { if ($materiel->groupes_metier_id) { // Le ..!= 1 c'est parce que le groupe métier/thématique d'id 1 correspond au groupe N/A, soit aucun groupe $mailsRespMetier = TableRegistry::getTableLocator()->get('Users')->find() ->select('email') ->where([ 'role =' => 'Responsable', 'groupes_metier_id =' => $materiel->groupes_metier_id ]) ->toArray(); } //TODO: changer ça car c'est pas forcément id=1 //if ($materiel->groupes_thematique_id != null && $materiel->groupes_thematique_id != 1) { if ($materiel->groupes_thematique_id) { // Le ..!= 1 c'est parce que le groupe métier/thématique d'id 1 correspond au groupe N/A, soit aucun groupe $mailRespThematique = TableRegistry::getTableLocator()->get('Users')->find() ->select('email') ->where([ 'role =' => 'Responsable', 'groupes_thematique_id =' => $materiel->groupes_thematique_id ]) ->toArray(); } if ($mailsRespMetier != [] || $mailRespThematique != []) { $mailsResp = array_unique(array_merge($mailsRespMetier, $mailRespThematique)); /* for ($i = 0; $i < sizeof($mailsResp); $i ++) { $mailList[] = $mailsResp[$i]['email']; // $mailList[sizeof($mailList)] = $mailsResp[$i]['email']; } */ foreach ($mailsResp as $mailResp) $mailList[] = $mailResp['email']; $mailList = array_unique($mailList); } //debug($mailList);exit(); // mail admin de reference (ici appele gestionnaire) -> Partie administration // Cela a été mis en commentaire car de toute façon l'utilisateur va voir un administratif pour faire valider sa fiche, // Pas la peine de spam l'administration de mails non plus hein ! /* * if ($action != 'statusValidated' && $action != 'statusArchived') { * $mailsAdmin = TableRegistry::getTableLocator()->get('Users')->find()->select('email') * ->where(['role =' => 'Administration']) * ->toArray(); * for ($i = 0; $i < sizeof($mailsAdmin); $i ++) { * $mailList[sizeof($mailList)] = $mailsAdmin[$i]['email']; * } * } */ } } // Materiel /* * - mail pour un DOCUMENT LIÉ */ // @todo: ajouter quelques infos dans ces cas : else if ($entity instanceof Document) { //debug("doc"); exit; $doc = $entity; $nom_doc = $doc->nom; $id_doc = $doc->id; $type_doc = $doc->type_doc; $id_mat = $doc->materiel_id; $id_suiv = $doc->suivi_id; if ($subject == null && $msg == null) { $msgMore = ''; Switch ($action) { case 'add': $subject = "Ajout d'un document"; $msg = "$acteur a ajouté le document \"$nom_doc\" au format \"$type_doc\""; break; //ajoutons un contenu de message plus clair pour l'envoi de document case 'mailDevis': $subject = "$acteur a partagé un document avec vous"; $msg = "$acteur après avoir ajouté le document \"$nom_doc\", a voulu le partager avec vous, c'est un document ayant le format \"$type_doc\" ."; $msg .="\n\n Le document est en pièce jointe."; break; //L'edition //comme il n'étais pas actuellement activé, on le laisse en commentaire //case 'edit': //$subject = "Modification d'un document"; //$msg = "$acteur a modifié le matériel \"$nom_doc\""; //break; //La suppression //comme il n'étais pas actuellement activé, on le laisse en commentaire //case 'delete': //$subject = "Suppression d'un document"; //$msg = "$acteur a supprimé le document\"$nom_doc\""; //break; default: $subject = "Action \"$action\" sur un matériel"; $msg = "$acteur a effectué l'action \"$action\" sur le document \"$nom_doc\" au format \"$type_doc\""; break; } // end switch // (EP) Ajout de l'ID du document, et de l'id du materiel associé !!! //On change le contenu en fonction de si le document a été lié à un matériel, ou a un suivi if (!$id_mat == Null) { $msg .= "\n\n (id doc=".$doc->id.", Materiel associé d'id=\"$id_mat\")"; $nomFic =$id_mat."_".$nom_doc."_".$id_doc.".".$type_doc; } else { $msg .= "\n\n (id doc=".$doc->id.", Materiel associé d'id=\"$id_suiv\")"; $nomFic =$id_suiv."_".$nom_doc."_".$id_doc.".".$type_doc; } } // Si le doc est lié à un matos, on ajoute le mail du gestionnaire du matos // (ssi l'envoi général est activé et que l'action ne correspond pas à 'printLabelRuban') if ( !$id_mat == Null && $configuration->envoi_mail && $action!='printLabelRuban' ) { // (EP) Recup du materiel associé /* $materiel = TableRegistry::getTableLocator()->get('Materiels')->find() ->where([ 'id =' => $doc->materiel_id ])->first(); */ $materiel = TableRegistry::getTableLocator()->get('Materiels')->get($doc->materiel_id); //debug("envoi"); //debug("matos = ".$materiel); //exit; // owner's mail (utilisateur du matériel associé ) //$mailList[0] = $entity->materiel->email_responsable; // (MI) - gestionaire ratachée au matériel //$mailList[1]= TableRegistry::getTableLocator()->get('Users')->find() $mailList[]= TableRegistry::getTableLocator()->get('Users')->find() ->select('email') ->where([ 'role =' => 'Administration', 'id =' => $materiel->gestionnaire_id ]); } // if matos } // DOC lié else if ($entity instanceof Suivi) { ; } else if ($entity instanceof Emprunt) { ; } /* * @todo: * else if ($entity instanceof Configuration) { * ; * } * ... etc ... (il faut qu'on soit plus précis) */ // Et maintenant on construit la liste de mails... // Si l'envoi à la liste spécifiée est activé (et que l'action ne correspond pas à 'printLabelRuban'): $specificUsers = []; if ($configuration->envoi_mail_guests && $action != 'printLabelRuban') { // mail aux adresses specifiees dans la config for ($i = 0; $i < 11; $i ++) { $specificUser = $configuration['emailGuest' . $i]; if ($specificUser) $specificUsers[] = $specificUser; // $mailList[sizeof($mailList)] = $configuration['emailGuest' . $i]; $mailList[] = $specificUser; // Le if vérifie que la ligne soit pas null } } // On dedoublonne la liste des mails, c'pas tres cool de se faire spam 2-3 fois pour la meme action sur le meme materiel, non mais ! // Ca supprime aussi les lignes vides $mailList = array_unique($mailList); // ... Pour envoyer les mails aux personnes concernees foreach ($mailList as $mail) { // On envoi des mails à toute la liste, sauf pour "l'acteur", il sait ce qu'il a fait, pas besoin de le spam non plus hein //if ($mail == $_SESSION['Auth']['User']['mail'][0]) //continue; $message = $msg; // Sisi, cette variable $message est utile, m'enfin vous pouvez toujours essayer de la supprimer ..... Et pensez à regarder le contenu de vos mails !!! Sinon ca fait une tumeur // Génération du message "Vous recevez ce message en tant que $role" // Si $role inexistant (lorsque c'est un mail de la liste entrée en configuration), le message est plutot "Vous recevez ce message car vous avez demandé à le recevoir. [...]" //if ($specificUsers) $role = "car vous etes dans la liste spécifique des emails de LabInvent. \n\nPour faire retirer votre mail de cette liste, veuillez contacter un super-administrateur."; /* (EP 13/319) : à quoi sert toute cette suite du texte du mail ??? * Ca sent le bon vieux copier-coller sans réfléchir... //else { //$role = $role. TableRegistry::get('Users')->find() $role = $role. TableRegistry::getTableLocator()->get('Users')->find() ->select('role') ->where([ 'email =' => $mail ]) ->first()['role'].' + '; // Default role is Utilisateur (for people in LDAP but without priviledge, not in the users table) // if (is_null($role)) $role =$role .'en tant que ' .'Utilisateur'; //} */ if ($entity != null && !in_array($action, ['delete','statusValidated','statusCreated'])) { $message .= "\n\nVeuillez vérifier et compléter si besoin la fiche correspondante."; $message .= "\n\nVous recevez ce message " . $role; //en fonction du mode à l'appel, on utilise un envoi de mail différent switch($mode) { //si le mode 1 est sélectionné c'est un envoi de mail avec ajout d'une photo //explique le document qui a été ajouté, et le met en pièce jointe case 1 : $this->sendEmailImgTo("$subject", $message, $mail, $configuration, $nomFic); break; //si le mode 2 est sélectionné c'est un envoi de mail avec ajout d'un document //à personnaliser case 2 : $this->sendEmailPJTo("$subject", $message, $mail, $configuration, $nomFic); break; //si le mode defaut est sélectionné c'est un simple envoi de mail //récapitule une action (mieux pour les add...) default : $this->sendEmailTo("$subject", $message, $mail, $configuration); break; } // switch } } //foreach ($mailList as $mail) return $mailList; } // function sendmail } // class AppController