diff --git a/VERSIONS_WIP/64203 b/VERSIONS_WIP/64203 new file mode 100644 index 0000000000000000000000000000000000000000..6aa97dafcf2fe4c4d304fd1463b2faaebc0bb67b --- /dev/null +++ b/VERSIONS_WIP/64203 @@ -0,0 +1,2 @@ + - ticket #64203 : Administration : ajout d'une interface de gestion des doublons d'utilsateurs. + \ No newline at end of file diff --git a/application/modules/admin/controllers/UsersController.php b/application/modules/admin/controllers/UsersController.php index 72f3753164d161305e965e69a8add42b392a0f95..c9570c46edc08a7f812659989e93216d3f9e4438 100644 --- a/application/modules/admin/controllers/UsersController.php +++ b/application/modules/admin/controllers/UsersController.php @@ -1,6 +1,6 @@ <?php /** - * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved. + * Copyright (c) 2012 Agence Française Informatique (AFI). All rights reserved. * * BOKEH is free software; you can redistribute it and/or modify * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by @@ -62,5 +62,88 @@ class Admin_UsersController extends ZendAfi_Controller_Action { $settings = Class_User_Settings::newWith($user); $settings->set($this->_getParam('key'), $this->_getParam('value')); $user->save(); - } + } + + + public function manageDoubleAction() { + $this->view->titre = $this->_('Gestion des doublons d\'abonnés'); + $this->view->double_manager = new Class_User_DbDoubleFinder; + + if(!$this->view->double_manager->hasDouble()) { + $this->_helper->notify($this->_('Aucun doublon d\'abonné dans votre base de données')); + return $this->_redirectToIndex(); + } + } + + + public function manageDoubleManualAction() { + $this->view->titre = $this->_('Gestion manuelle des doublons d\'abonnés'); + $this->view->double_manager = new Class_User_DbDoubleFinder; + + if(!$this->view->double_manager->hasDouble()) { + $this->_helper->notify($this->_('Aucun doublon d\'abonné dans votre base de données')); + return $this->_redirectToIndex(); + } + } + + + public function deleteDoubleAction() { + $total = (int) $this->_getParam('total', 0); + $cursor = (int) $this->_getParam('cursor', 0); + + $db_double_finder = new Class_User_DbDoubleFinder; + $new_cursor = $db_double_finder->dedupeUsers($cursor); + + $continue = $new_cursor + ? true + : false; + + if(!$continue) + $this->_helper->notify($this->_('Le dédoublonnage automatique des doublons est terminé.')); + + $done = $total - $db_double_finder->countDouble(); + + return $this->_helper->progressbar($total, $done, $new_cursor, $continue); + } + + + public function manageDoubleUserAction() { + if(!$id_user = $this->_getParam('id_user', null)) { + $this->_helper->notify($this->_('ID_USER invalide')); + return $this->_redirectToIndex(); + } + + if(!$user = Class_Users::find($id_user)) { + $this->_helper->notify($this->_('Utilisateur invalide')); + return $this->_redirectToIndex(); + } + + $this->view->double_manager = new Class_User_DbDoubleFinder; + $this->view->users = $this->view->double_manager->findDoubleFor($user); + $this->view->titre = $this->_('Gestion manuelle des doublon pour l\'ID ABON : %s', $user->getIdabon()); + $this->view->id_user = $id_user; + $this->view->next = $this->view->double_manager->getNextDouble($id_user); + $this->view->previous = $this->view->double_manager->getPreviousDouble($id_user); + } + + + public function manageDoubleMergeAction() { + + if ((!$users_from = $this->_getParam('id_user_from',null)) + || (!$user_to = Class_Users::find($this->_getParam('id_user_to',null)))) { + $this->_helper->notify($this->_('id_users invalides')); + return $this->_redirectToIndex(); + } + $double_manager = new Class_User_DbDoubleFinder; + $next = $double_manager->getNextDouble($this->_getParam('id_user')); + + if (!$double_manager->mergeUsersInto($user_to, Class_Users::findAllBy(['id_user' => explode('_',$users_from)]))) { + $this->_helper->notify($this->_('Echec de la migration')); + return $this->_redirectToIndex(); + } + + $this->_helper->notify($this->_('La migration pour l\'utilisateur %s a été effectué.',$user_to->getLogin())); + return $this->_redirect('/admin/users/manage-double-user/id_user/'.$next); + } + } diff --git a/application/modules/admin/views/scripts/users/index.phtml b/application/modules/admin/views/scripts/users/index.phtml index 22a26d3d9f8ea923421f4bfe4e7b0f15c0467d06..25072612d2a4aaee996c7a49ed623697121d1da2 100644 --- a/application/modules/admin/views/scripts/users/index.phtml +++ b/application/modules/admin/views/scripts/users/index.phtml @@ -1,43 +1,26 @@ <?php if(Class_Users::getIdentity()->isAdmin()) echo $this->Button_New((new Class_Entity()) - ->setText($this->_('Ajouter un utilisateur'))); + ->setText($this->_('Ajouter un utilisateur'))); -$map =[['url' => ['module' => 'admin', - 'controller' => 'users', - 'action' => 'edit', - 'id' => '%s'], - 'icon' => 'edit', - 'label' => $this->_('modifier')], +$double_finder = (new Class_User_DbDoubleFinder); +$has_double = $double_finder->hasDouble(); - ['url' => ['module' => 'admin', - 'controller' => 'users', - 'action' => 'delete', - 'id' => '%s'], - 'icon' => 'delete', - 'label' => $this->_('supprimer')], - - ['url' => ['module' => 'opac', - 'controller' => 'blog', - 'action' => 'viewauteur', - 'id' => '%s'], - 'icon' => 'star', - 'label' => $this->_('avi(s)'), - 'condition' => 'hasAvis', - 'anchorOptions' => ['target' => '_blank']], - - ['url' => ['module' => 'opac', - 'controller' => 'panier', - 'action' => 'viewauteur', - 'id' => '%s'], - 'icon' => 'basket', - 'label' => $this->_('panier(s)'), - 'condition' => 'hasPaniers', - 'anchorOptions' => ['target' => '_blank']]]; - -$actions = function($user) use($map) { - return $this->renderModelActions($user,$map); -}; +echo $this->button( + (new Class_Entity()) + ->setText($this->_('Gérer les doublons')) + ->setAttribs($has_double + ? ['title' => $this->_('Il y a %s doublons', $double_finder->countDouble())] + : ['title' => $this->_('Il n\'y a pas de doublon'), + 'disabled' => 'disabled']) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'manage-double'], + null, true)) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'users'), + ['style' => 'filter: invert();']))); echo $this->Admin_SearchUsers($this->users, @@ -45,4 +28,7 @@ echo $this->Admin_SearchUsers($this->users, $this->form, $this->page, $this->params, - $actions); + function($model) + { + return $this->renderPluginsActions($model); + }); diff --git a/application/modules/admin/views/scripts/users/manage-double-manual.phtml b/application/modules/admin/views/scripts/users/manage-double-manual.phtml new file mode 100644 index 0000000000000000000000000000000000000000..a9dac65ca9474f5c661077176837203c802bba60 --- /dev/null +++ b/application/modules/admin/views/scripts/users/manage-double-manual.phtml @@ -0,0 +1,13 @@ +<?php +echo $this->tag('p', + $this->_('Vous avez %s comptes abonnés possédant au moins un doublon dans votre base de données qui ne peuvent pas être supprimés automatiquement.', + $this->double_manager->countDouble())); + +echo $this->tag('p', + $this->tag('small', + $this->_('Requête d\'identification des doublons : %s', $this->tag('b', $this->double_manager->getRequest())))); + +echo $this->button((new Class_Entity()) + ->setUrl($this->url(['action' => 'manage-double-user', + 'id_user' => $this->double_manager->getFirstDouble()])) + ->setText($this->_('Gérer manuellement les doublons'))); diff --git a/application/modules/admin/views/scripts/users/manage-double-user.phtml b/application/modules/admin/views/scripts/users/manage-double-user.phtml new file mode 100644 index 0000000000000000000000000000000000000000..8b9e94368b55cc11e61d851b47e05bebda7616b6 --- /dev/null +++ b/application/modules/admin/views/scripts/users/manage-double-user.phtml @@ -0,0 +1,99 @@ +<?php + +echo $this->tag('p', + $this->_('Il reste %s comptes abonnés possédant au moins un doublon dans votre base de données.', + $this->tag('b', $this->double_manager->countDouble()))); + + +$description = (new Class_TableDescription('double-users')) + ->addColumn($this->_('ID'), ['attribute' => 'id_user']) + ->addColumn($this->_('Login'), ['attribute' => 'login']) + ->addColumn($this->_('Nom'), ['attribute' => 'nom']) + ->addColumn($this->_('Prenom'), ['attribute' => 'prenom']) + ->addColumn($this->_('Email'), ['attribute' => 'mail']) + ->addColumn($this->_('Bibliothèque'), ['attribute' => 'libelleBib']) + ->addColumn($this->_('Expiration de l\'abo'), function($user) + { + return Class_Date::humanDate($user->getDateFin(), 'dd MMMM yyyy'); + }) + ->addColumn($this->_('Exporté par le SIGB'), function($model) + { + return $model->getStatut() + ? $this->_('Non') + : $this->_('Oui'); + }) + ->addRowAction(function ($model) + { + $id_users = (new Storm_Model_Collection($this->users)) + ->collect('id_user') + ->getArrayCopy(); + $id_users = array_diff($id_users, [$model->getId()]); + return $this->button((new Class_Entity()) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'manage-double-merge', + 'id_user_to' => $model->getIdUser(), + 'id_user_from' => implode('_', $id_users)])) + + ->setText($this->_('Conserver')));}); + +echo $this->renderTable($description, + $this->users, + ['sorter' => true]); + +$attribs = []; +if ($this->previous == '') + $attribs = ['disabled' => 'disabled']; + +echo $this->button((new Class_Entity()) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'index' + ])) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'back'), + ['style' => 'filter: invert();'])) + ->setText($this->_('Retour à la gestion des utilisateurs'))); + +echo $this->button((new Class_Entity()) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'manage-double' + ])) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'back'), + ['style' => 'filter: invert();'])) + ->setText($this->_('Retour à la gestion des doublons'))); + +echo $this->button((new Class_Entity()) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'manage-double-user', + 'id_user' => $this->previous] + )) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'down'), + ['style' => 'filter: invert(); transform: rotate(90deg);'])) + + ->setText($this->_('Précédent')) + ->setAttribs($attribs)); + +$attribs = []; +if ($this->next == '') + $attribs = ['disabled' => 'disabled']; + +echo $this->button((new Class_Entity()) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'manage-double-user', + 'id_user' => $this->next] + )) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'down'), + ['style' => 'filter: invert(); transform: rotate(270deg);'])) + + ->setText($this->_('Ignorer et continuer'))); diff --git a/application/modules/admin/views/scripts/users/manage-double.phtml b/application/modules/admin/views/scripts/users/manage-double.phtml new file mode 100644 index 0000000000000000000000000000000000000000..36d21803f3af86eca94fcc23cb8992ea879ea055 --- /dev/null +++ b/application/modules/admin/views/scripts/users/manage-double.phtml @@ -0,0 +1,45 @@ +<?php +echo $this->tag('p', + $this->_('Vous avez %s comptes abonnés possédant au moins un doublon dans votre base de données.', + $this->tag('b', $this->double_manager->countDouble()))); + +echo $this->button((new Class_Entity()) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'index' + ])) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'back'), + ['style' => 'filter: invert();'])) + ->setText($this->_('Retour à la gestion des utilisateurs'))); + +echo $this->button((new Class_ButtonDescription()) + ->beProgressbar($this, Class_Url::relative('/admin/users/delete-double'), + $this->double_manager->countDouble(), + $this->_('Lancer le dédoublonnage automatique'))); + + +echo $this->button((new Class_Entity()) + ->setUrl($this->url(['action' => 'manage-double-user', + 'id_user' => $this->double_manager->getFirstDouble()])) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'users'), + ['style' => 'filter: invert();'])) + + ->setText($this->_('Gérer manuellement les doublons'))); + + +echo $this->button((new Class_Entity()) + ->setAttribs([ + 'onclick' => '$(this).next().toggle();']) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'help'), + ['style' => 'filter: invert();'])) + ->setText($this->_('Voir la requete'))); + +echo $this->tag('pre', + $this->double_manager->getRequest(), + ['style' => 'display: none;']); diff --git a/library/Class/Admin/Skin.php b/library/Class/Admin/Skin.php index 9765371c682d45fa802f4dbee0944f269bea4b99..c63b83785e96abe8cca3333a7bcd2b5875deeab7 100644 --- a/library/Class/Admin/Skin.php +++ b/library/Class/Admin/Skin.php @@ -143,7 +143,8 @@ class Class_Admin_Skin { public function renderButtonCssOn($script_loader) { - return $this->_renderCssOn($script_loader, 'buttons.css'); + return $this->_renderCssOn($script_loader, 'buttons.css') + ->renderJQueryCssOn($script_loader); } diff --git a/library/Class/ButtonDescription.php b/library/Class/ButtonDescription.php new file mode 100644 index 0000000000000000000000000000000000000000..c55089245620a6a5ece5d93cc4b541b3910a7faf --- /dev/null +++ b/library/Class/ButtonDescription.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_ButtonDescription extends Class_Entity { + public function beProgressbar($view, $url, $total, $text) { + + Class_ScriptLoader::getInstance()->addAdminScript('progressbar.js'); + $id = md5(implode(',',$this->_attribs)); + $this->setAttribs([ + 'id' => $id, + 'onclick' => sprintf('progressbar(\'%s\',\'%s\', %d);', + $id, $url,$total) + ]) + ->setImage($view->tagImg(Class_Admin_Skin::current() + ->getIconUrl('actions', + 'test'), + ['style' => 'filter: invert();'])) + ->setText($text.$view->tag('span', '')); + return $this; + } +} +?> \ No newline at end of file diff --git a/library/Class/User/Datas.php b/library/Class/User/Datas.php index 2f80c2d4b076ad809c7783d68a63773024c30e5c..aad8a96adaac3817a0a88d96e091c3c2ef2dda30 100644 --- a/library/Class/User/Datas.php +++ b/library/Class/User/Datas.php @@ -20,20 +20,58 @@ */ -class Class_User_Datas extends Class_Entity { - protected $_relations = []; +class Class_User_Datas { + protected + $_attribs = [], + $_relations = []; + + + public static function hasDataInIds($ids) { + $instance = new static(null); + return $instance->hasDataIn($ids); + } + public function __construct($user) { $this->setUser($user); - $this->_relations = [new Class_User_DatasRelation('notices_paniers', 'id_user'), + $this->_relations = [ + new Class_User_DatasRelation('notices_paniers', 'id_user'), + new Class_User_DatasRelation('user_group_memberships', 'user_id'), new Class_User_DatasRelationAvisNotice(), new Class_User_DatasRelation('cms_avis', 'id_user'), + new Class_User_DatasRelation('linked_cards', 'parent_id'), + new Class_User_DatasRelation('linked_cards', 'child_id'), + new Class_User_DatasRelation('session_activity_inscriptions', 'stagiaire_id'), new Class_User_DatasRelation('suggestion_achat', 'user_id'), - new Class_User_DatasRelation('session_formation_inscriptions', 'stagiaire_id'), - new Class_User_DatasRelation('user_group_memberships', 'user_id'), new Class_User_DatasRelation('formulaires', 'id_user'), - new Class_User_DatasRelation('multimedia_devicehold', 'id_user')]; + new Class_User_DatasRelation('multimedia_devicehold', 'id_user') + ]; + } + + + public function hasDataIn($ids) { + foreach($this->_relations as $relation) + if (0 < $this->_countIdsContainningData($relation, $ids)) + return true; + + return false; + } + + + protected function _countIdsContainningData($relation, $ids) { + return $relation->countIdsContainingData($ids); + } + + + public function setUser($user) { + $this->_attribs['User'] = $user; + return $this; + } + + + public function getUser() { + return $this->_attribs['User']; } @@ -85,11 +123,25 @@ class Class_User_Datas extends Class_Entity { return current($targets); } + + + public function setError($key) { + $this->_attribs['Error'] = $key; + return $this; + } + + + public function getError() { + return $this->_attribs['Error']; + } } -class Class_User_DatasRelation extends Class_Entity { + +class Class_User_DatasRelation { + protected $_attribs; + public function __construct($table, $key) { $this->setTable($table) ->setKey($key) @@ -97,6 +149,39 @@ class Class_User_DatasRelation extends Class_Entity { } + public function setTable($table) { + $this->_attribs['Table'] = $table; + return $this; + } + + + public function getTable() { + return $this->_attribs['Table']; + } + + + public function setSql($sql) { + $this->_attribs['Sql'] = $sql; + return $this; + } + + + public function getSql() { + return $this->_attribs['Sql']; + } + + + public function setKey($key) { + $this->_attribs['Key'] = $key; + return $this; + } + + + public function getKey() { + return $this->_attribs['Key']; + } + + public function countFor($user) { return $this ->getSql() @@ -105,6 +190,16 @@ class Class_User_DatasRelation extends Class_Entity { } + public function countIdsContainingData($ids) { + return $this + ->getSql() + ->fetchOne(sprintf('select count(id) from %s where %s in (%s)', + $this->getTable(), + $this->getKey(), + implode(',', $ids))); + } + + public function giveFromTo($from, $to) { $this ->getSql() diff --git a/library/Class/User/DbDoubleFinder.php b/library/Class/User/DbDoubleFinder.php new file mode 100644 index 0000000000000000000000000000000000000000..e99195cbd1ae11039e494597301899d12c1b31f8 --- /dev/null +++ b/library/Class/User/DbDoubleFinder.php @@ -0,0 +1,236 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_User_DbDoubleFinder { + + const LIMIT_DEDUPE = 10; + + + public function getRequest($cursor = 0) { + return sprintf('select min(id_user) as id_user, password, login, idabon, ordreabon, count(*) as doublon from bib_admin_users where role_level = 2 and id_user > %s group by idabon, ordreabon, login, password having doublon > 1 order by id_user asc', + $cursor); + } + + + public function getDouble($cursor = 0) { + return Zend_Registry::get('sql') + ->fetchAll($this->getRequest($cursor)); + } + + + public function hasDouble() { + return $this->countDouble() > 0; + } + + + public function countDouble() { + return count($this->getDouble()); + } + + + public function getFirstDoubleInLimit($cursor = 0) { + $double = $this->getDouble($cursor); + return array_slice($double, 0, static::LIMIT_DEDUPE); + } + + + public function findDoubleFor($user) { + return $this->_findUsersWithParams($user->getIdabon(), + $user->getLogin(), + $user->getOrdreabon(), + $user->getPassword()); + } + + + public function hasDoubleFor($user) { + return 1 < count($this->findDoubleFor($user)); + } + + + public function getFirstDouble() { + $ids = $this->_getUserIdsFromDouble(); + return array_shift($ids); + } + + + public function getNextDouble($id_user) { + $ids = $this->_getUserIdsFromDouble(); + + if(false === ($position = array_search($id_user, $ids))) + return ''; + + $next = $position + 1; + return isset($ids[$next]) + ? $ids[$next] + : ''; + } + + + public function getPreviousDouble($id_user) { + $ids = $this->_getUserIdsFromDouble(); + + if(false === ($position = array_search($id_user, $ids))) + return ''; + + $previous = $position - 1; + return isset($ids[$previous]) + ? $ids[$previous] + : ''; + } + + + public function dedupeUsers($cursor = 0) { + $double = $this->getFirstDoubleInLimit($cursor); + foreach($double as $data) + $this->_autoMergeOrDelete($this->_findUsersFromDouble($data)); + + $last = array_pop($double); + + if(empty($last)) + return null; + + return isset($last['id_user']) + ? (int) $last['id_user'] + : null; + } + + + protected function _autoMergeOrDelete($users) { + if(!$user = $this->_findUserToKeep($users)) + return $this->_autoDeleteDoubles($users); + + return $this->mergeUsersInto($user, $users); + } + + + public function mergeUsersInto($user, $users) { + $users = array_filter($users, function($instance) use ($user) + { + return $instance->getId() !== $user->getId(); + }); + + foreach ($users as $deletable_user) { + $datas = new Class_User_Datas($deletable_user); + + if (!$datas->giveTo(['id_user' => $user->getIdUser()], true)) + return; + + $deletable_user->delete(); + } + + return true; + } + + + protected function _findUsersFromDouble($data) { + return $this->_findUsersWithParams($data['idabon'], + $data['login'], + $data['ordreabon'], + $data['password']); + } + + + protected function _findUsersWithParams($idabon, $login, $ordreabon, $password) { + return Class_Users::findAllBy(['idabon' => $idabon, + 'password' => $password, + 'login' => $login, + 'ordreabon' => $ordreabon]); + } + + + protected function _findUserToKeep($users) { + $last_name = ''; + $first_name =''; + $status = null; + + $keep_user = null; + foreach($users as $user) { + if ((!$last_name = $this->_userAsSame($user->getNom(), $last_name)) + || (!$first_name = $this->_userAsSame($user->getPrenom(), $first_name))) + return; + + if (!$user->hasDateFin()) + continue; + + if ($user->hasToBeDelete()) + continue; + + if ($keep_user) + return; + + $keep_user = $user; + } + + return $this->_hasGreaterDates($keep_user, $users); + } + + + protected function _userAsSame($name, $expected_name) { + $name = Class_Indexation::getInstance()->alphaMaj($name); + + if ($expected_name == '') + $expected_name = $name; + + return $expected_name == $name + ? $name + : false; + } + + + protected function _hasGreaterDates($user, $users) { + if(!$user) + return null; + + foreach($users as $other) { + if (strtotime($other->getDateFin()) > strtotime($user->getDateFin())) + return null; + } + + return $user; + } + + + protected function _autoDeleteDoubles($users) { + if(!$ids = $this->_getDoubleUsersWithOutDatas($users)) + return; + + return Zend_Registry::get('sql') + ->query(sprintf('delete from bib_admin_users where id_user in (%s)', implode(',',$ids))); + } + + + protected function _getDoubleUsersWithOutDatas($users) { + $ids = (new Storm_Model_Collection($users)) + ->collect('id_user') + ->getArrayCopy(); + + if(Class_User_Datas::hasDataInIds($ids)) + return null; + + return $ids; + } + + + protected function _getUserIdsFromDouble() { + return array_column($this->getDouble(), 'id_user'); + } +} \ No newline at end of file diff --git a/library/Class/Users.php b/library/Class/Users.php index c5c17052a5216d40e2db294fbf960da88f0108cd..70e0e32881c4b74d63031722387c83317e7d86c4 100644 --- a/library/Class/Users.php +++ b/library/Class/Users.php @@ -1859,4 +1859,9 @@ class Class_Users extends Storm_Model_Abstract { public function hasPaniers() { return (0 < $this->numberOfPaniers()); } + + + public function hasToBeDelete() { + return static::STATUT_TO_BE_DELETED == $this->getStatut(); + } } diff --git a/library/ZendAfi/Controller/Action/Helper/Progressbar.php b/library/ZendAfi/Controller/Action/Helper/Progressbar.php new file mode 100644 index 0000000000000000000000000000000000000000..df7391cc8f97f5869cd47d4323cae4d87ef28bd4 --- /dev/null +++ b/library/ZendAfi/Controller/Action/Helper/Progressbar.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_Controller_Action_Helper_Progressbar extends Zend_Controller_Action_Helper_Abstract { + public function progressbar($total, $done, $cursor, $run) { + $this->getActionController() + ->getHelper('json') + ->direct( ['total' => $total, + 'done' => $done, + 'cursor' => $cursor, + 'run' => $run]); + + } + + + public function direct($total, $done, $cursor, $run) { + return $this->progressbar($total, $done, $cursor, $run); + } +} diff --git a/library/ZendAfi/Controller/Plugin/Manager/User.php b/library/ZendAfi/Controller/Plugin/Manager/User.php index 34148948ee8ec00ad75a0bdbdf07fbc4ba1397ee..40fd1f0d35f295c02cada011f1291acf45c05961 100644 --- a/library/ZendAfi/Controller/Plugin/Manager/User.php +++ b/library/ZendAfi/Controller/Plugin/Manager/User.php @@ -21,6 +21,53 @@ class ZendAfi_Controller_Plugin_Manager_User extends ZendAfi_Controller_Plugin_Manager_Manager { + public function getActions($model) { + return [['url' => ['module' => 'admin', + 'controller' => 'users', + 'action' => 'edit', + 'id' => '%s'], + 'icon' => 'edit', + 'label' => $this->_('modifier')], + + ['url' => ['module' => 'admin', + 'controller' => 'users', + 'action' => 'delete', + 'id' => '%s'], + 'icon' => 'delete', + 'label' => $this->_('supprimer')], + + ['url' => ['module' => 'opac', + 'controller' => 'blog', + 'action' => 'viewauteur', + 'id' => '%s'], + 'icon' => 'star', + 'label' => $this->_('avi(s)'), + 'condition' => 'hasAvis', + 'anchorOptions' => ['target' => '_blank']], + + ['url' => ['module' => 'opac', + 'controller' => 'panier', + 'action' => 'viewauteur', + 'id' => '%s'], + 'icon' => 'basket', + 'label' => $this->_('panier(s)'), + 'condition' => 'hasPaniers', + 'anchorOptions' => ['target' => '_blank']], + + ['url' => ['module' => 'admin', + 'controller' => 'users', + 'action' => 'manage-double-user', + 'id_user' => '%s'], + 'icon' => 'help', + 'label' => $this->_('Doublons'), + 'condition' => function ($model) { + return (new Class_User_DbDoubleFinder())->hasDoubleFor($model); + } + ] + ]; + } + + protected function _getPost() { $post = $this->_request->getPost(); $post['user_groups'] = array_filter( diff --git a/library/ZendAfi/View/Helper/Admin/Button.php b/library/ZendAfi/View/Helper/Admin/Button.php index d6d364d4fb4686c09dd81626dc516c000ec378eb..91f9d69613da7807f7533c7669b57def006f8858 100644 --- a/library/ZendAfi/View/Helper/Admin/Button.php +++ b/library/ZendAfi/View/Helper/Admin/Button.php @@ -76,4 +76,5 @@ class ZendAfi_View_Helper_Admin_Button extends ZendAfi_View_Helper_Button { return $button->getElement(); } + } \ No newline at end of file diff --git a/public/admin/js/onload_utils.js b/public/admin/js/onload_utils.js index 696095416f11c87c76fb55e50f6d9380f4a50c4c..d11eacdfc50612ff8f94b153ffe14b80afc66aea 100644 --- a/public/admin/js/onload_utils.js +++ b/public/admin/js/onload_utils.js @@ -150,3 +150,5 @@ var updateSelectWidget = function(element) { url = url + '/categories/' + categories_ids; $('.selected_articles_widget a').attr('href', url); } + + diff --git a/public/admin/js/progressbar.js b/public/admin/js/progressbar.js new file mode 100644 index 0000000000000000000000000000000000000000..a1c0bb9c384a01612a65bce71986541fd55cfa65 --- /dev/null +++ b/public/admin/js/progressbar.js @@ -0,0 +1,28 @@ +var progressbar = function(id, url, total, cursor = 0) { + var run; + var tag = $("#" + id + " span"); + $.ajax({ + type: 'GET', + url: url, + data: {'total': total, + 'cursor': cursor}, + success: function(data) + { + var percent = data.done * 100 / total; + var new_cursor = data.cursor; + run = data.run; + percent = percent ? percent : 1; + tag.progressbar({value: percent}); + + if(run) + progressbar(id, url, total, new_cursor); + + }, + complete: function(event, ui) { + if(run) + return; + tag.progressbar({value: 100}); + + location.reload(); + }}); +} diff --git a/public/admin/skins/bokeh74/buttons.css b/public/admin/skins/bokeh74/buttons.css index 7e78097b72029592ea93b8eaed8fa8c471a31dde..ffa3ba453b01f66066a6306779f517bdd8c6dda9 100644 --- a/public/admin/skins/bokeh74/buttons.css +++ b/public/admin/skins/bokeh74/buttons.css @@ -26,6 +26,7 @@ transition: background 0.4s; border: none; cursor: pointer; + vertical-align: top; } .admin-button > img { @@ -44,4 +45,10 @@ div.admin-buttons { .admin-button:disabled > img { filter: opacity(0.2); +} + + +.admin-button span.ui-progressbar { + display: block; + margin: 5px; } \ No newline at end of file diff --git a/public/admin/skins/bokeh74/global.css b/public/admin/skins/bokeh74/global.css index 59733f9854b7238266e11d111e938522a4fe4e17..f8fe1afe0084d8a12026e48af5cf3ec39585c935 100755 --- a/public/admin/skins/bokeh74/global.css +++ b/public/admin/skins/bokeh74/global.css @@ -161,6 +161,11 @@ td[id*="menu_item"] { box-shadow: 1px 1px 5px var(--widget-shadow); } +.modules pre { + box-shadow: inset 1px 1px 5px var(--widget-shadow); +} + + /* Font */ body, body * { @@ -994,3 +999,9 @@ table#logs img { .modules a[data-order$="desc"] { background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); } + +.modules pre { + margin: 1ex 1em; + padding: 1ex 1em; + overflow: auto; +} diff --git a/public/admin/skins/bokeh74/jquery.css b/public/admin/skins/bokeh74/jquery.css index bf00c573346b7de0b5f37d445c1b1bd5487aaaf4..8225cfd2499f3e73a07bffd2121aa3932ca5c3d1 100644 --- a/public/admin/skins/bokeh74/jquery.css +++ b/public/admin/skins/bokeh74/jquery.css @@ -151,3 +151,13 @@ body .ui-tabs a.errors.ui-tabs-anchor { color: white; background: var(--error-text); } + +body .ui-progressbar .ui-progressbar-value { + background : var(--success-background); + margin: 0; + +} + +body .ui-progressbar { + height: 1em; +} diff --git a/public/opac/js/subModal.js b/public/opac/js/subModal.js index ebc20192df84a48d45fe89850890d53d766860ab..4445f2cc5283d2cf7709e54bccbbb206b1d30fd4 100644 --- a/public/opac/js/subModal.js +++ b/public/opac/js/subModal.js @@ -5,8 +5,10 @@ var current_anchor; window.initializePopups = function() { - $('[data-popup="true"]') - .unbind('click').click(function(event){ + $('[data-popup="true"], [data-popup="1"]') + .unbind('onclick') + .unbind('click') + .click(function(event){ event.preventDefault(); current_anchor=$(this); addLoadingClass(); diff --git a/tests/application/modules/admin/controllers/UsersControllerTest.php b/tests/application/modules/admin/controllers/UsersControllerTest.php index d65c549915a9d87fd3ad6c7bd0f66db2d544243d..c1d09857f9f967336a5f9ebc744e74c422a705eb 100644 --- a/tests/application/modules/admin/controllers/UsersControllerTest.php +++ b/tests/application/modules/admin/controllers/UsersControllerTest.php @@ -27,12 +27,12 @@ abstract class UsersControllerWithMarcusTestCase extends AbstractControllerTestC $group_vodeclic = $this->fixture('Class_UserGroup', ['id' => 20, 'libelle' => 'Multimedia']) - ->addRight(Class_UserGroup::RIGHT_ACCES_VODECLIC); + ->addRight(Class_UserGroup::RIGHT_ACCES_VODECLIC); $group_referent = $this->fixture('Class_UserGroup', ['id' => 22, 'libelle' => 'Referent']) - ->addRight(Class_UserGroup::RIGHT_USER_DOMAINES_SUPPRESSION_LIMIT); + ->addRight(Class_UserGroup::RIGHT_USER_DOMAINES_SUPPRESSION_LIMIT); $group_stagiaires = $this->fixture('Class_UserGroup',['id' => 25, 'libelle' => 'Stagiaires']); @@ -86,14 +86,26 @@ abstract class UsersControllerWithMarcusTestCase extends AbstractControllerTestC $this->dispatch('/admin/users/edit/id/10', true); } + } + + + class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { public function setUp() { parent::setUp(); Zend_Registry::set('sql', $this->mock() + ->whenCalled('fetchAll') + ->with('select min(id_user) as id_user, password, login, idabon, ordreabon, count(*) as doublon from bib_admin_users where role_level = 2 and id_user > 0 group by idabon, ordreabon, login, password having doublon > 1 order by id_user asc') + ->answers([]) + + ->whenCalled('fetchAll') + ->with('select idabon, count(*) as doublon from bib_admin_users where role_level = 2 group by idabon having doublon > 1;') + ->answers([]) + ->whenCalled('fetchAllByColumn') ->with('select distinct(id_user) as id from notices_avis') ->answers([2233, 987398])); @@ -119,6 +131,13 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { ->whenCalled('hasIdentity') ->answers($user) + ->whenCalled('findAllBy') + ->with(['idabon' => '', + 'password' => 'francis', + 'login' => 'francis', + 'ordreabon' => '']) + ->answers($francis) + ->whenCalled('findAllBy') ->with(['role_level' => 2, 'order' => 'nom asc', @@ -131,7 +150,6 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { 'order' => 'nom asc', 'where' => '(STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()) AND (id_user in (2233,987398)) AND (login LIKE "%francis%" OR nom LIKE "%francis%" OR prenom LIKE "%francis%" OR pseudo LIKE "%francis%" OR mail LIKE "%francis%" OR idabon LIKE "%francis%") AND (role_level <= 7)']) ->answers(55) - ->beStrict(); $this->dispatch('/admin/users?search_id_site=all&search_role_level=2&search_valid_subscription=1&search_review=1&search_search_for=\"\'fra"n\'cis"', true); @@ -733,10 +751,10 @@ class UsersControllerReferentIndexTest extends UsersControllerWithMarcusTestCase $this->user_loader = Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Users'); $this->user_loader->whenCalled('getIdentity') - ->answers($user = Class_Users::newInstanceWithId(2) - ->setLogin('referent') - ->setRoleLevel(ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL) - ->setPseudo('referent')); + ->answers($user = Class_Users::newInstanceWithId(2) + ->setLogin('referent') + ->setRoleLevel(ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL) + ->setPseudo('referent')); $this->addUserToRightsReferent($user); @@ -881,15 +899,15 @@ abstract class Admin_UsersControllerEditAdminTestCase extends Admin_AbstractCont 'libelle' => 'Region Savoie']); $this->_lib_ac = $this->fixture('Class_Bib', - ['id' => 7, - 'libelle' => 'AC', - 'id_zone' => 1]); + ['id' => 7, + 'libelle' => 'AC', + 'id_zone' => 1]); $this->_lib_po = $this->fixture('Class_Bib', - ['id' => 15, - 'libelle' => 'PO', - 'id_zone' => 1, - 'redmine_api_key' => '123abc']); + ['id' => 15, + 'libelle' => 'PO', + 'id_zone' => 1, + 'redmine_api_key' => '123abc']); $this->fixture('Class_Bib', ['id' => 13, @@ -946,7 +964,7 @@ class Admin_UsersControllerFormEditAdminTest extends Admin_UsersControllerEditAd /** @test */ public function withModoPortailRedmineLibrarySelectorShouldBePresent() { - $this->assertXPath('//form//select[@name="redmine_library"]', $this->_response->getBody()); + $this->assertXPath('//form//select[@name="redmine_library"]', $this->_response->getBody()); } @@ -1165,7 +1183,7 @@ class UsersControllerWithAdminPortalTest extends Admin_AbstractControllerTestCas } - /** @test */ + /** @test */ public function linkToShowTumPanierShouldNotBePresent() { $this->assertNotXPath('//a[contains(@href, "/panier/viewauteur/id/3")]'); } @@ -1176,3 +1194,555 @@ class UsersControllerWithAdminPortalTest extends Admin_AbstractControllerTestCas $this->assertXPath('//th/a[contains(@href, "/search_order/nom/")]'); } } + + + + +abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTestCase { + protected $_storm_default_to_volatile = true; + + + public function setUp() { + parent::setUp(); + $mock_sql = + $this->mock() + ->whenCalled('fetchAll') + ->with('select min(id_user) as id_user, password, login, idabon, ordreabon, count(*) as doublon from bib_admin_users where role_level = 2 and id_user > 0 group by idabon, ordreabon, login, password having doublon > 1 order by id_user asc') + ->answers([ + ['id_user' => '25', + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '89', + 'ordreabon' => '18', + 'doublon' => '2'], + + ['id_user' => '2', + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '49', + 'ordreabon' => '1', + 'doublon' => '2'], + + ['id_user' => '100', + 'login' => 'rita', + 'password' => 'rita', + 'idabon' => '89', + 'ordreabon' => '18', + 'doublon' => '3'], + + ['id_user' => '103', + 'login' => 'rita', + 'password' => 'rita', + 'idabon' => '90', + 'ordreabon' => '18', + 'doublon' => '3'], + + ['id_user' => '106', + 'login' => 'rita', + 'password' => 'rita', + 'idabon' => '91', + 'ordreabon' => '18', + 'doublon' => '3'], + + ['id_user' => '110', + 'login' => 'rita', + 'password' => 'rita', + 'idabon' => '100', + 'ordreabon' => '18', + 'doublon' => '3'] + + ]) + + ->whenCalled('fetchOne') + ->with('select count(id) from notices_paniers where id_user in (25,654,655)') + ->answers(1) + + ->whenCalled('fetchOne') + ->with('select count(id) from notices_paniers where id_user in (100,101,102)') + ->answers(1) + + ->whenCalled('query') + ->with('delete from bib_admin_users where id_user in (2,29)') + ->willDo(function() + { + Class_Users::find(2)->delete(); + Class_Users::find(29)->delete(); + }) + + ->whenCalled('fetchOne') + ->with('select count(id) from notices_paniers where id_user in (103,104,105)') + ->answers(1) + + ->whenCalled('fetchOne') + ->with('select count(id) from notices_paniers where id_user in (106,107,108)') + ->answers(1) + + ->whenCalled('fetchOne') + ->with('select count(id) from notices_paniers where id_user in (110,111)') + ->answers(1) + + ->whenCalled('fetchOne') + ->answers(0) + + ->whenCalled('query') + ->answers(true) + + ->whenCalled('query') + ->with('update notices_paniers set id_user=654 where id_user=25') + ->willDo(function() { + return Class_PanierNotice::find(4)->setIdUser(654)->save(); + }) + ->whenCalled('query') + ->with('update notices_paniers set id_user=100 where id_user=101') + ->willDo(function() { + return Class_PanierNotice::find(101)->setIdUser(100)->save(); + }) + ->whenCalled('query') + ->with('update notices_paniers set id_user=100 where id_user=102') + ->willDo(function() { + return Class_PanierNotice::find(102)->setIdUser(100)->save(); + }); + + Zend_Registry::set('sql', $mock_sql); + + $this->fixture('Class_Users', + ['id' => 2, + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '49', + 'ordreabon' => 1]); + + $this->fixture('Class_Users', + ['id' => 29, + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '49', + 'ordreabon' => 1]); + + $this->fixture('Class_Users', + ['id' => 123, + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '49', + 'ordreabon' => 2]); + + $this->fixture('Class_Users', + ['id' => 25, + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '89', + 'ordreabon' => 18]); + + $this->fixture('Class_Users', + ['id' => 654, + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '89', + 'ordreabon' => 18]); + + $this->fixture('Class_Users', + ['id' => 655, + 'login' => 'Ret', + 'password' => 'urn', + 'idabon' => '89', + 'ordreabon' => 18]); + + $this->createUsersWithStatusDifferentAndSameNames(89, [100,101,102], [0,1,1]); + $this->createUsersWithStatusDifferentAndSameNames(90, [103,104,105], [1,1,1]); + $this->createUsersWithStatusDifferentAndSameNames(91, [106,107,108], [0,0,1]); + $this->createUsersWithEmptyValidityDate(); + $this->fixture('Class_PanierNotice', + ['id' => 4, + 'libelle' => 's', + 'id_user' => 25]); + } + + + protected function createUsersWithEmptyValidityDate() { + $this->fixture('Class_Users', + ['id' => 110, + 'nom' => 'Abatzi', + 'prenom' => 'rita', + 'statut' => 1, + 'login' => 'rita', + 'date_fin' => null, + 'password' => 'rita', + 'idabon' => 100, + 'ordreabon' => 18]); + + $this->fixture('Class_Users', + ['id' => 111, + 'nom' => 'Abatzi', + 'prenom' => 'rita', + 'statut' => 0, + 'date_fin' => null, + 'login' => 'rita', + 'password' => 'rita', + 'idabon' => 100, + 'ordreabon' => 18]); + + $this->fixture('Class_PanierNotice', + ['id' => 40, + 'libelle' => 's', + 'id_user' => 110]); + + } + + + protected function createUsersWithStatusDifferentAndSameNames($id_abon, $ids, $status) { + $this->fixture('Class_Users', + ['id' => $ids[0], + 'nom' => 'test', + 'prenom' => 'test', + 'statut' => $status[0], + 'login' => 'rita', + 'date_fin' => '2017-01-08', + 'password' => 'rita', + 'idabon' => $id_abon, + 'ordreabon' => 18]); + + $this->fixture('Class_Users', + ['id' => $ids[1], + 'nom' => 'test', + 'prenom' => 'test', + 'statut' => $status[1], + 'date_fin' => '2017-01-07', + 'login' => 'rita', + 'password' => 'rita', + 'idabon' => $id_abon, + 'ordreabon' => 18]); + + $this->fixture('Class_Users', + ['id' => $ids[2], + 'nom' => 'test', + 'prenom' => 'test', + 'statut' => $status[2], + 'date_fin' => '2016-09-07', + 'login' => 'rita', + 'password' => 'rita', + 'idabon' => $id_abon, + 'ordreabon' => 18]); + + $this->fixture('Class_PanierNotice', + ['id' => $ids[0], + 'libelle' => 'mybasket', + 'id_user' => $ids[0]]); + + $this->fixture('Class_PanierNotice', + ['id' => $ids[1], + 'libelle' => 'mybasket', + 'id_user' => $ids[1]]); + + $this->fixture('Class_PanierNotice', + ['id' => $ids[2], + 'libelle' => 'mybasket', + 'id_user' => $ids[2]]); + } +} + + + + +class UsersControllerManageDoubleTest extends UsersControllerDoubleTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/manage-double', true); + } + + + /** @test */ + public function sixDoubleAccountsShouldBeFounded() { + $this->assertXPathContentContains('//p', 'Vous avez <b>6</b> comptes abonnés possédant au moins un doublon',$this->_response->getBody()); + } + + + /** @test */ + public function purgeButtonShouldBePresent() { + $this->assertXPathContentContains('//button[contains(@onclick, "/admin/users/delete-double")]', 'Lancer le dédoublonnage automatique'); + } +} + + + +class UsersControllerDeleteDoubleEndCursorTest extends Admin_AbstractControllerTestCase { + + public function setUp() { + parent::setUp(); + Zend_Registry::set('sql', $this->mock() + ->whenCalled('fetchAll') + ->answers([])); + + $this->dispatch('/admin/users/delete-double/total/6/cursor/1000', true); + } + + + /** @test */ + public function jsonShouldBeRendered() { + $this->assertEquals(['total' => 6, + 'done' => 6, + 'cursor' => null, + 'run' => false], json_decode($this->_response->getBody(),true)); + } +} + + + + + +class UsersControllerDeleteDoubleTest extends UsersControllerDoubleTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/delete-double/total/6', true); + } + + + /** @test */ + public function jsonShouldBeRendered() { + $this->assertEquals(['total' => 6, + 'done' => 0, + 'cursor' => 110, + 'run' => true], json_decode($this->_response->getBody(),true)); + } + + + /** @test */ + public function userId123456ShouldNotBeDeleted() { + $this->assertNotNull(Class_Users::find(123)); + } + + + /** @test */ + public function userId2ShouldHaveBeendDeleted() { + $this->assertNull(Class_Users::find(2)); + } + + + /** @test */ + public function userId101And102ShouldHaveBeendDeleted() { + $this->assertNull(Class_Users::find(101)); + $this->assertNull(Class_Users::find(102)); + $this->assertNotNull(Class_Users::find(100)); + } + + + /** @test */ + public function userId103And104ShouldNotHaveBeendDeleted() { + $this->assertNotNull(Class_Users::find(103)); + $this->assertNotNull(Class_Users::find(104)); + $this->assertNotNull(Class_Users::find(105)); + } + + + /** @test */ + public function userId106And107ShouldNotHaveBeendDeleted() { + $this->assertNotNull(Class_Users::find(106)); + $this->assertNotNull(Class_Users::find(107)); + $this->assertNotNull(Class_Users::find(108)); + } + + + /** @test */ + public function userId110And111ShouldNotHaveBeendDeleted() { + $this->assertNotNull(Class_Users::find(110)); + $this->assertNotNull(Class_Users::find(111)); + } + + + /** @test */ + public function userId100ShouldHaveBaskets() { + $this->assertEquals(3,Class_PanierNotice::countBy(['id_user' => 100,'id' =>[100,101,102]])); + } + + + /** @test */ + public function userId29ShouldHaveBeendDeleted() { + $this->assertNull(Class_Users::find(29)); + } + + + /** @test */ + public function userId25ShouldNotBeDeleted() { + $this->assertNotNull(Class_Users::find(25)); + } + + + /** @test */ + public function userId654ShouldNotBeDeleted() { + $this->assertNotNull(Class_Users::find(654)); + } +} + + + + +class UsersControllerManageDoubleManualTest extends UsersControllerDoubleTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/manage-double-manual', true); + } + + + /** @test */ + public function shouldDisplayContinuButton() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-user/id_user/25")]'); + } +} + + + + +class UsersControllerManageDoubleUserTest extends UsersControllerDoubleTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/manage-double-user/id_user/25', true); + } + + + /** @test */ + public function shouldDisplayUsers() { + $this->assertXpath('//div'); + } + + + /** @test */ + public function backButtonShouldBeDisplayed() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double")]',$this->_response->getBody()); + } + + + /** @test */ + public function buttonMergeShouldBe654to25() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/25/id_user_to/25/id_user_from/654")]',$this->_response->getBody()); + } + + + /** @test */ + public function buttonMergeShouldBe25to654() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/25/id_user_to/654/id_user_from/25_655")]',$this->_response->getBody()); + } + + + /** @test */ + public function buttonIgnoreAndContinueShouldHaveUserId2() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-user/id_user/2")]',$this->_response->getBody()); + } + + + /** @test */ + public function buttonPreviousShouldNotBeAvailable() { + $this->assertXpathContentContains('//button[contains(@disabled, "disabled")]','Précédent',$this->_response->getBody()); + } +} + + + + +class UsersControllerManageNextDoubleUserTest extends UsersControllerDoubleTestCase { + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/manage-double-user/id_user/2', true); + } + + + /** @test*/ + public function buttonMergeShouldBe2to29() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/2/id_user_to/29/id_user_from/2")]',$this->_response->getBody()); + } + + + /** @test */ + public function buttonPreviousAndNextShouldBeAvailable() { + $this->assertNotXPath('//button[contains(@disabled, "disabled")]'); + } + + + /** @test */ + public function buttonPreviousShouldHaveUserId25() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-user/id_user/25")]',$this->_response->getBody()); + } +} + + + + +class UsersControllerManageDoubleMergeTest extends UsersControllerDoubleTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/manage-double-merge/id_user_from/25/id_user_to/654', true); + } + + + /** @test */ + public function user25ShouldBeDeleted() { + $this->assertNull(Class_Users::find(25)); + } + + + /** @test */ + public function panier4ShouldHaveIdUser654() { + $this->assertEquals(654,Class_PanierNotice::find(4)->getIdUser()); + } +} + + + + +class UsersControllerManageDoubleMergeWithMultipleSourcesTest extends UsersControllerDoubleTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/manage-double-merge/id_user_from/25_655/id_user_to/654', true); + } + + + /** @test */ + public function user25ShouldBeDeleted() { + $this->assertNull(Class_Users::find(25)); + } + + + /** @test */ + public function user655ShouldBeDeleted() { + $this->assertNull(Class_Users::find(655)); + } +} + + + + +class UsersControllerIndexWithDoubleTest extends UsersControllerDoubleTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/index', true); + } + + + /** @test */ + public function buttonManageDoubleShouldBePresent() { + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double")]'); + } + + + /** @test */ + public function linkToManageDoubleOfUserId25ShouldBePresent() { + $this->assertXpath('//td//a[contains(@href, "/admin/users/manage-double-user/id_user/25")]'); + } + + + /** @test */ + public function idUser123ShouldBePresent() { + $this->assertXPath('//td//a[contains(@href, "/admin/users/edit/id/123")]'); + } + + + /** @test */ + public function idUser123ShouldNotHaveLinkToManageDouble() { + $this->assertNotXPath('//td//a[contains(@href, "/admin/users/manage-double-user/id_user/123")]'); + } +} diff --git a/tests/library/Class/UserDatasTest.php b/tests/library/Class/UserDatasTest.php index 8260fc02ff1d15d7d32e50d0d6cbfa2066d5914e..f67537ef647f221f4485a7a0b24f8f374306a0a4 100644 --- a/tests/library/Class/UserDatasTest.php +++ b/tests/library/Class/UserDatasTest.php @@ -96,10 +96,12 @@ class UserDatasTest extends UserDatasTestCase { ['notices_avis', 'id_user'], ['cms_avis', 'id_user'], ['suggestion_achat', 'user_id'], - ['session_formation_inscriptions', 'stagiaire_id'], + ['session_activity_inscriptions', 'stagiaire_id'], ['user_group_memberships', 'user_id'], ['formulaires', 'id_user'], - ['multimedia_devicehold', 'id_user'] + ['multimedia_devicehold', 'id_user'], + ['linked_cards', 'parent_id'], + ['linked_cards', 'child_id'] ]; foreach($queries as $query)