name); //return strtolower($this->getName()); if ($alias_controller_name == 'ChefSciences') return 'responsables scientifiques (PI)'; if ($alias_controller_name == 'ChefProjets') return 'chefs de projet'; return 'utilisateurs'; } // "l'" utilisateur (et non pas "le utilisateur") // @deprecated // @override parent public function getArticle() { return "L'"; } public $paginate = [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ], 'limit' => 20, 'order' => [ 'Users.nom' => 'asc' ] ]; public function initialize() { parent::initialize(); $this->loadComponent('Paginator'); // déplacé dans beforeFilter() //$this->Auth->allow(['logout']); // Pour autoriser le SIGNUP des nouveaux utilisateurs //$this->Auth->allow(['logout', 'add']); } // 1) AVANT connexion public function beforeFilter(Event $event) { parent::beforeFilter($event); $this->LdapAuth->allow(['logout']); } /* * @Override * * Initialisation des autorisations pour les actions spécifiques à ce controleur * */ protected function setAuthorizations() { /* * a) Noms et verbes à utiliser (surtout dans les notifications) pour les actions * */ $this->setActionsNounAndPastVerb([ 'login' => ['Connexion','connecté'], 'logout' => ['Déconnexion','déconnecté'], ]); /* * b) Actions de ce controleur qui enverront des notifications (log et/ou email) * * 'log' = logger seulement * 'mail' => envoyer un mail seulement * 'both' = faire les 2 (logger ET envoyer un mail) * */ $this->setNotificationAllowedOnActions([ 'login' => 'log', // Ne marchera pas car pas d'utilisateur en session //'logout' => 'log', 'add' => 'log', 'edit' => 'log', 'delete' => 'log', // ... ]); /* * c) Règles d'accès (ACLs) * */ // Actions autorisées à tous foreach (['login', 'logout', 'getLdapLogin', 'getLdapEmail', 'indexRecap'] as $action) $this->setAuthorizationsForAction($action, 0); // Action autorisées seulement à superadmin // TODO: affiner dans le cas d'un LDAP : même superadmin ne doit pas pouvoir supprimer ou modifier (sauf certains attributs) un utilisateur foreach (['add', 'edit', 'delete'] as $action) $this->setAuthorizationsForAction($action, -1, ['super'=>0]); } // setAuthorizations // 2) APRES connexion /** * Give authorization for users * * @param * $user * @return boolean */ /* public function isAuthorized($user, $action=null, $id=null, $role=null, $userCname=null) { // $configuration = $this->confLabinvent; // $role = $this->Users->find()->where(['username' => $user[$configuration->authentificationType_ldap][0]])->first()['role']; // $action = $this->request->getAttribute('params')['action']; $action = $this->getActionPassed(); // Actions de CE controleur accessibles à tous les profils // if (in_array($action, ['index', 'view', 'getLdapLogin', 'getLdapEmail','indexRecap'])) return true; if (in_array($action, [ 'getLdapLogin', 'getLdapEmail', 'indexRecap' ])) return true; // Inutile car déjà dit dans parent::isAuthorized() // Super-Admin peut accéder à toutes les actions de CE controleur // if ($role == 'Super Administrateur') return true; // Par défaut refuser // return false; return parent::isAuthorized($user); } */ // ref: https://book.cakephp.org/4/fr/controllers/components/authentication.html#identifier-les-utilisateurs-et-les-connecter public function login() { $this->myDebug("step 2: UsersController.login()"); // Un utilisateur a essayé de se loguer if ($this->request->is('post')) { // Identification du user en utilisant les données POST // sans LDAP //$user = $this->Auth->identify(); // avec LDAP $user = $this->LdapAuth->connection(); //var_dump($user); //debug($user); // Le login a été accepté //if ($user != FALSE) { if ($user) { // Sauvegarde le user dans la session //$this->Auth->setUser($user); $this->LdapAuth->setUser($user); //debug($user); /* Voici ce que contient $user : [ 'sn' => [ (int) 0 => 'Pallier' ], 'mail' => [ (int) 0 => 'Etienne.Pallier@irap.omp.eu' ], 'givenname' => [ (int) 0 => 'Etienne' ], 'uid' => [ (int) 0 => 'epallier' ], 'userpassword' => [ (int) 0 => 'mot-de-passe-crypté' ] ] */ $this->_updateStatsForCurrentUserOnLogin(); //exit; // On va maintenant à la page qui etait demandée //return $this->redirect($this->Auth->redirectUrl()); return $this->redirect($this->LdapAuth->redirectUrl()); } // Utilisateur non reconnu $this->Flash->error(__('Login ou mot de passe invalide, réessayez')); } } public function logout() { //debug("LOGOUT !"); //debug($this->u); $this->_updateStatsForCurrentUserOnLogout(); //$this->Flash->success('You are now logged out.'); return $this->redirect($this->LdapAuth->logout()); // Puis ça va sur /users/login } /* * Renvoie les infos de l'utilisateur qui sont dans la session * * Voici ce que contient $_SESSION['Auth']['User'] par exemple : [ 'sn' => [ (int) 0 => 'Pallier' ], 'mail' => [ (int) 0 => 'Etienne.Pallier@irap.omp.eu' ], 'givenname' => [ (int) 0 => 'Etienne' ], 'uid' => [ (int) 0 => 'epallier' ], 'userpassword' => [ (int) 0 => 'mot-de-passe-crypté' ] ] */ private function _getCurrentUserInfosFromSession() { // Current user infos return isset($_SESSION['Auth']['User']) ? $_SESSION['Auth']['User'] : []; } private function _getCurrentUserFullNameFromSession($user_infos = null) { if (!$user_infos) $user_infos = $this->_getCurrentUserInfosFromSession(); // "Pallier Etienne" return $user_infos ? $user_infos['sn'][0].' '.$user_infos['givenname'][0] : 'Name Firstname'; } private function _getCurrentUserEntityFromSession($session_user = null) { $user_fullname = $this->_getCurrentUserFullNameFromSession($session_user); //debug($user_fullname); // "Pallier Etienne" return $this->Users->find()->where(['nom'=>$user_fullname])->first(); } /* * Mise à jour des stats pour ce user (et pour l'année courante) au moment du login * => on enregistre son heure de connexion * => on incrémente le nombre de connexions */ public function _updateStatsForCurrentUserOnLogin($user_infos = null) { $user_id = $this->_getCurrentUserEntityFromSession($user_infos)->id; //debug($user); $now = new FrozenTime(); //debug($last_login_time); $year = $now->format('yy'); //debug($year); // On recup la Stat du user courant $table_stats = $this->Users->Stats; $stat_id = [$year,$user_id]; $current_user_stat = null; try { // Si un enregistrement existe pour ce user (et cette année) => on le récupère $current_user_stat = $table_stats->get($stat_id); //debug("exists"); //$current_user_stat->last_logout_time = null; } catch (\Cake\Datasource\Exception\RecordNotFoundException $e) { //echo 'Exception reçue : ', $e->getMessage(), "\n"; // Pas d'enregistrement pour ce user (et cette année) => on le crée //debug("new"); /* $stat = [ //['year','user_id'] => [$year,$user->id], //'(year,user_id)' => [$year,$user->id], 'year' => $year, 'user_id' => $user->id, 'last_login_time' => $last_login_time, ]; debug($stat); */ //$stat_entity = $table_stats->newEntity($stat); $current_user_stat = $table_stats->newEntity(); $current_user_stat->year = $year; $current_user_stat->user_id = $user_id; } $last_login_time = $current_user_stat->last_login_time; $last_logout_time = $current_user_stat->last_logout_time; /* * Check le cas où le logout n'a pas été enregistré * (le user n'a pas fait logout, ça s'est fait tout seul par timeout) * => Dans ce cas, on ajoute à la durée totale le dernier temps de connexion last_connex_dur */ if ($last_logout_time < $last_login_time) { $last_connex_dur = $current_user_stat->last_connex_dur; /* * (Optimisation): Si la dernière session a été très courte (<10s), on ne le comptabilise pas * => on décrémente le nb de connexions (passées) */ if ($current_user_stat->connex_nb>0 && $last_connex_dur<10) $current_user_stat->connex_nb--; else $current_user_stat->connex_dur_tot += $last_connex_dur; } // On met à jour le champs last_login_time, RAZ last_connex_dur, et incrémente le nb de connexions $current_user_stat->last_login_time = $now; $current_user_stat->last_connex_dur = 0; // et 1 NOUVELLE connexion de plus, 1 ! $current_user_stat->connex_nb++; //debug($current_user_stat); // On sauvegarde en table if (! $table_stats->save($current_user_stat)) { echo "Impossible de sauvegarder une stat sur login !"; debug($current_user_stat->getErrors()); debug($current_user_stat); exit; } /* $query = $table_stats->findById($stat_id); if ($query->isEmpty()) { debug("no"); // record doesn't exist } else { debug("yes"); } */ } // _updateStatsForCurrentUserOnLogin() /* * Mise à jour des stats pour ce user (et pour l'année courante) durant la session, à chaque action * => on met à jour son temps de connexion */ public function updateStatsForCurrentUserDuringSession($session_user = null) { //debug("ici"); //exit; // Current user //$user_id = $this->u->id; //debug($session_user); $user_id = $this->_getCurrentUserEntityFromSession($session_user)->id; //debug($user_id); // On récupère la Stat de ce user $now = new FrozenTime(); //debug($last_login_time); $year = $now->format('yy'); //debug($year); $table_stats = $this->Users->Stats; $stat_id = [$year,$user_id]; //debug($stat_id); $current_user_stat = $table_stats->get($stat_id); // On met à jour le temps de connexion $connex_duration = $now->diff($current_user_stat->last_login_time); //debug($connex_duration); //exit; $current_user_stat->last_connex_dur = $connex_duration->h*3600 + $connex_duration->i*60 + $connex_duration->s; //debug($current_user_stat->last_connex_dur); // On sauvegarde en table if (! $table_stats->save($current_user_stat)) { echo "Impossible de sauvegarder une stat durant la session !"; debug($current_user_stat->getErrors()); debug($current_user_stat); exit; } } // updateStatsForCurrentUserDuringSession() /* * Mise à jour des stats pour ce user (et pour l'année courante) au moment du logout * => on enregistre son heure de dé-connexion * => on calcule son temps de connexion et on l'ajoute au champ qui totalise le temps de connexion : connex_dur_tot */ private function _updateStatsForCurrentUserOnLogout() { // Current user $user_id = $this->u->id; $last_logout_time = new FrozenTime(); //debug($last_login_time); $year = $last_logout_time->format('yy'); //debug($year); // On récup la stat de ce user (pour cette année) // Normalement, elle doit exister puisque il y a déjà eu login ! // TODO: Cas particulier où le login se fait le 31 décembre, et le logout l'année suivante => BUG !!! $table_stats = $this->Users->Stats; $stat_id = [$year,$user_id]; $current_user_stat = $table_stats->get($stat_id); $last_login_time = $current_user_stat->last_login_time; // 1) On met à jour le champ last_logout_time $current_user_stat->last_logout_time = $last_logout_time; // 2) On met à jour le temps de connexion total (cumulé) // - on calcule le temps de connexion $connex_duration = $last_logout_time->diff($last_login_time); $connex_duration = $connex_duration->h*3600 + $connex_duration->i*60 + $connex_duration->s; //debug($last_login_time); //debug($last_logout_time); //debug($connex_dur_totation); // - on cumule ce temps au temps total //debug($current_user_stat->connex_dur_tot); //debug($connex_dur_totation); $current_user_stat->connex_dur_tot += $connex_duration; //debug($current_user_stat->connex_dur_tot); // On sauvegarde en table if (! $table_stats->save($current_user_stat)) { echo "Impossible de sauvegarder une stat sur logout !"; debug($current_user_stat->getErrors()); debug($current_user_stat); exit; } } // _updateStatsForCurrentUserOnLogout() /** * Index method * * @return \Cake\Network\Response|null */ public function index() { $filtre = $this->request->getQuery('filtre'); //debug($this->viewVars); // Si on est sur l'instance de l'IRAP (InventIrap), // on affiche l'url vers la page de l'ANNUAIRE du site web du labo $lab_website_urls = ($this->confLabinvent->labNameShort != 'IRAP') ? [] : [ "Annuaire IRAP" => 'https://www.irap.omp.eu/annuaire', "Annuaire IRAP (OMP)" => 'http://ezomp2.omp.obs-mip.fr/annuaire/annuaire-irap2', ]; //$priviledgedUsers = $this->Users->find()->where(['role !=' => 'Utilisateur']); /* $this->paginate = [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ], 'limit' => 12, 'order' => [ 'Users.nom' => 'asc' ] ]; */ $this->paginate = [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ], 'sortWhitelist' => [ 'nom', 'email', 'role', 'GroupesThematiques.nom', 'GroupesMetiers.nom', 'SurCategories.nom', ], 'limit' => 20, /* 'order' => [ 'Users.nom' => 'asc' ] */ ]; $conditions = $filtre ? ['role =' => 'Responsable'] : []; $entities = $this->paginate($this->Users->find('all', [ 'conditions' => $conditions ])); // ALL users //$entities = $this->paginate(); // ce qui revient au même que : //$users = $this->paginate($this->Users); // Only priviledged users //$users = $this->paginate($priviledgedUsers); // Affichage informations disponible pour l'utilisateur connecté $this->myDebug($this->LdapAuth->user()); //////$this->set('nbUsers', $this->Users->find()->count()); //$this->set('nbUsers', $this->Users->find('all')->count()); //$this->set('nbUsers', $priviledgedUsers->count()); $this->set(compact('entities', 'lab_website_urls', 'filtre')); /* Inutile si pas de JSON $this->set('_serialize', [ 'users' ]); */ } // index() /** * Index_recap method * * @return \Cake\Network\Response|null */ /* (EP202010 fusionnée avec index()) public function indexRecap() { $this->paginate = [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ], 'sortWhitelist' => [ 'nom', 'email', 'GroupesThematiques.nom', 'GroupesMetiers.nom', 'SurCategories.nom', ], ]; $entities = $this->paginate($this->Users->find('all', [ 'conditions' => [ 'role =' => 'Responsable' ] ])); // Affichage informations disponible pour l'utilisateur connecté $this->myDebug($this->LdapAuth->user()); /S $this->set('nbUsers', $this->Users->find('all', [ 'conditions' => [ 'role =' => 'Responsable' ] ]) ->count()); S/ $this->set(compact('entities')); /S Uniquement pour JSON $this->set('_serialize', [ 'users' ]); S/ } */ /** * View method * * @param string|null $id * User id. * @return \Cake\Network\Response|null * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ public function view($id = null) { $user = $this->Users->get($id, [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ] ]); $this->set('user', $user); $this->set('_serialize', [ 'user' ]); } /** * Add method * * @return \Cake\Network\Response|void Redirects on successful add, renders view otherwise. */ public function add() { // Création d'un objet User VIDE avec tous les champs $user = $this->Users->newEntity(); // (POST) Un user vient d'être créé, on le sauve en BD, // puis on va sur la vue individuelle de ce nouveau user if ($this->request->is('post')) { $user = $this->Users->patchEntity($user, $this->request->getData()); if ($this->Users->save($user)) { $this->Flash->success(__('L\'utilisateur a bien été ajouté.')); // On va maintenant à la vue individuelle de ce nouvel utilisateur return $this->redirect([ 'action' => 'view', $user->id ]); } else { $this->Flash->error(__('L\'utilisateur n\'a pas pu être ajouté.')); } } // (pas POST) Ici, on vient sur la vue d'ajout (add.ctp) pour la première fois // On prépare donc quelques listes qui seront nécessaires à cette vue $groupesMetiers = $this->Users->GroupesMetiers->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); $groupesThematiques = $this->Users->GroupesThematiques->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); //->toArray(); /* Ajoute l'élément 0 => 'N/A' en tête de tableau * SANS changer les clés !!! // 1) on ajoute un élément vide à la clé "0", // et on trie le tableau sur les values (nom) (en conservant les clés) // => l'élément vide se retrouve donc en tête $groupesThematiques[0] = ''; asort($groupesThematiques); // 2) on remplace l'élément vide (en tête) par 'N/A', qui est donc toujours en tête ! $groupesThematiques[0] = 'N/A'; */ $sur_categorie = $this->Users->SurCategories->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); // TODO: Refactoriser: idem pour add() et edit() (ainsi que leurs pendants dans MaterielsController) $this->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]; } */ // On passe à la vue add.ctp toutes les variables créés ci-dessus // "user" est l'utilisateur $user créé au début, et qui est vide $this->set(compact( 'user', 'groupesMetiers', //'users_option_list', 'users_login_and_email', 'groupesThematiques', 'sur_categorie' )); $this->set('_serialize', [ 'user' ]); // Ici, la vue add.ctp (formulaire d'ajout d'un user) est maintenant automatiquement affichée } /** * Edit method * * @param string|null $id * User id. * @return \Cake\Network\Response|void Redirects on successful edit, renders view otherwise. * @throws \Cake\Network\Exception\NotFoundException When record not found. */ public function edit($id = null) { $user = $this->Users->get($id, [ 'contain' => [] ]); if ($this->request->is([ 'patch', 'post', 'put' ])) { //debug($this->request->getData()); //exit; /* 'username' => 'pdevoto', 'password' => '$2y$10$nBQMNstgN.sgad1ZANznY.pbJI.ZG/.Q5qX4gC8SXCFQnDIZC8rcW', (from DB = '$2y$10$nBQMNstgN.sgad1ZANznY.pbJI.ZG/.Q5qX4gC8SXCFQnDIZC8rcW') 'email' => 'Pierre.Devoto@irap.omp.eu', 'role' => 'Responsable', 'groupes_metier_id' => '2', 'groupes_thematique_id' => '1', 'sur_categorie_id' => '1' */ $user = $this->Users->patchEntity($user, $this->request->getData()); //debug($user); exit; if ($this->Users->save($user)) { $this->Flash->success(__("L'utilisateur a bien été modifié")); return $this->redirect([ 'action' => 'view', $id ]); } else { $this->Flash->error(__("L'utilisateur n'a pas pu être modifié")); } } $groupesMetiers = $this->Users->GroupesMetiers->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); $groupesThematiques = $this->Users->GroupesThematiques->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); /* Ajoute l'élément 0 => 'N/A' en tête de tableau ->toArray(); * SANS changer les clés !!! // 1) on ajoute un élément vide à la clé "0", // et on trie le tableau sur les values (nom) (en conservant les clés) // => l'élément vide se retrouve donc en tête $groupesThematiques[0] = ''; asort($groupesThematiques); // 2) on remplace l'élément vide (en tête) par 'N/A', qui est donc toujours en tête ! $groupesThematiques[0] = 'N/A'; */ $sur_categorie = $this->Users->SurCategories->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); $this->set(compact('user', 'groupesMetiers', 'groupesThematiques', 'sur_categorie')); $this->set('_serialize', [ 'user' ]); } // edit() /** * Delete method * * @param string|null $id * User id. * @return \Cake\Network\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ public function delete($id = null) { $this->request->allowMethod([ 'post', 'delete' ]); $user = $this->Users->get($id); if ($this->Users->delete($user)) { $this->Flash->success(__('L\'utilisateur a bien été supprimé.')); } else { $this->Flash->error(__('L\'utilisateur n\'a pas pu être supprimé.')); } return $this->redirect([ 'action' => 'index' ]); } // called from Javascript (Ajax) public function getLdapLogin($userName) { $u = TableRegistry::get('LdapConnections')->getListLoginUsers(); if ($u[$userName] !== null) { $this->set('login', $u[$userName]); } $this->viewBuilder()->layout = 'ajax'; } // called from Javascript (Ajax) public function getLdapEmail($userName) { $u = TableRegistry::get('LdapConnections')->getListEmailUsers(); if ($u[$userName] !== null) { $this->set('email', $u[$userName]); } else { $this->set('email', ' '); } $this->viewBuilder()->layout = 'ajax'; } }