diff --git a/FEATURES/77694 b/FEATURES/77694 new file mode 100644 index 0000000000000000000000000000000000000000..bc1b07d3809841949b0521738f5f33fc68990851 --- /dev/null +++ b/FEATURES/77694 @@ -0,0 +1,10 @@ + '77694' => + ['Label' => $this->_('Suppression d\'utilisateurs par lot'), + 'Desc' => $this->_('Bokeh permet la suppression d'utilisateurs par lot correspondant aux critères de recherche sélectionnés'), + 'Image' => '', + 'Video' => 'https://www.youtube.com/watch?v=nX_z3rWnql8', + 'Category' => 'Administration', + 'Right' => function($feature_description, $user) {return true;}, + 'Wiki' => 'http://wiki.bokeh-library-portal.org/index.php?title=Gestion_des_utilisateurs#Suppression_par_lot', + 'Test' => '', + 'Date' => '2019-06-20'], \ No newline at end of file diff --git a/VERSIONS_WIP/77694 b/VERSIONS_WIP/77694 new file mode 100644 index 0000000000000000000000000000000000000000..15bafff91d3946af3faca1fafcdc0ae467e3a6a0 --- /dev/null +++ b/VERSIONS_WIP/77694 @@ -0,0 +1 @@ + - ticket #77694 : Administration : Bokeh permet la suppression d'utilisateurs par lot correspondant aux critères de recherche sélectionnés \ No newline at end of file diff --git a/application/modules/admin/controllers/UsersController.php b/application/modules/admin/controllers/UsersController.php index c9570c46edc08a7f812659989e93216d3f9e4438..c9ba4fcc562f4b172a3ce6f702b96df81ae92a21 100644 --- a/application/modules/admin/controllers/UsersController.php +++ b/application/modules/admin/controllers/UsersController.php @@ -30,10 +30,10 @@ class Admin_UsersController extends ZendAfi_Controller_Action { public function indexAction() { $this->view->titre = $this->_('Gestion des utilisateurs'); $params = $this->_request->getParams(); - $this->_helper - ->userSearch([], - (new Class_User_SearchCriteria($params)) - ->addCriteria(new Class_User_SearchCriteria_RoleLevelLimit($params))); + $this->view->search = $this->_helper + ->search([], + (new Class_User_SearchCriteria($params)) + ->addCriteria(new Class_User_SearchCriteria_RoleLevelLimit($params))); } diff --git a/application/modules/admin/views/scripts/newsletter/edit-subscribers.phtml b/application/modules/admin/views/scripts/newsletter/edit-subscribers.phtml index c1f138dbf63313d5e078902022172c874b89a68e..11d116719451188b721b6c808251c7fb9513a29d 100644 --- a/application/modules/admin/views/scripts/newsletter/edit-subscribers.phtml +++ b/application/modules/admin/views/scripts/newsletter/edit-subscribers.phtml @@ -45,50 +45,4 @@ echo $this->tagModelTable($this->groups, [$actions], 'newsletter_user_groups'); -$build_url = function($action) { - return $this->url(array_merge(['module' => 'admin', - 'controller' => 'newsletter', - 'action' => 'edit-subscribers', - 'id' => $this->newsletter->getId(), - 'page' => $this->page ? $this->page: null], - $this->params), - null, true) . '/' . $action . '/%s'; -}; - -$no_mail_action = $this->tag('div' , - $skin->renderActionIconOn('help', - $this, - ['title' => $this->_('Utilisateur sans mail'), - 'class' => 'ico']), - ['class' => 'actions']); - -$actions = function($model) use ($build_url, $no_mail_action) { - $is_recipient = $this->newsletter->hasRecipient($model, false); - $is_blacklisted = $this->newsletter->isBlackListed($model); - - if (!$is_recipient) - return $this->renderModelActions($model, - [['url' => $build_url('subscribe'), - 'icon' => 'add', - 'label' => $this->_('Inscrire')] - ]); - - if ($is_blacklisted) - return $this->renderModelActions($model, - [['url' => $build_url('subscribe'), - 'icon' => 'back', - 'label' => $this->_('Réinscrire')] - ]);; - - if (! $model->hasMail()) - return $no_mail_action; - - return $this->renderModelActions($model, - [['url' => $build_url('unsubscribe'), - 'icon' => 'cancel', - 'label' => $this->_('Désinscrire')] - ]); -}; - -echo '<br><br>' - . $this->Admin_SearchUsers($this->users, $this->total, $this->form, $this->page, $this->params, $actions); +echo '<br><br>' . $this->searchNewsletterUsers($this->newsletter, $this->search); diff --git a/application/modules/admin/views/scripts/usergroup-agenda/all.phtml b/application/modules/admin/views/scripts/usergroup-agenda/all.phtml index 093655819dfb5450b7ff41220ca4f0ce6f79ff17..7261467d4b42b3fdf759975f6db4f9a4a96866c5 100644 --- a/application/modules/admin/views/scripts/usergroup-agenda/all.phtml +++ b/application/modules/admin/views/scripts/usergroup-agenda/all.phtml @@ -1,2 +1,2 @@ <?php -echo $this->searchRendezVous($this->search, $this->rendezvous); +echo $this->searchRendezVous($this->search); diff --git a/application/modules/admin/views/scripts/usergroup-agenda/user-select.phtml b/application/modules/admin/views/scripts/usergroup-agenda/user-select.phtml index d7610e8ad0368efefca8d32247b8f9067b73cb49..4b100db8810b55c7db6e6a7e454624c1b5887aa7 100644 --- a/application/modules/admin/views/scripts/usergroup-agenda/user-select.phtml +++ b/application/modules/admin/views/scripts/usergroup-agenda/user-select.phtml @@ -1,16 +1,3 @@ <?php -$actions = function($model) { - return $this->renderModelActions($model, - [['url' => '#', - 'icon' => 'add_user', - 'label' => $this->_('Ajouter "%s" comme destinataire', - $model->getNomComplet()), - 'anchorOptions' => ['class' => 'user_add_action', - 'data-userid' => $model->getId(), - 'data-username' => $model->getNomComplet()]] - ]); -}; - -echo $this->tag('div', $this->Admin_SearchUsers($this->users, $this->total, $this->form, - $this->page, $this->params, $actions), +echo $this->tag('div', $this->searchRendezVousUsers($this->search), ['class' => 'modules']); diff --git a/application/modules/admin/views/scripts/users/index.phtml b/application/modules/admin/views/scripts/users/index.phtml index aca988264f97563a108ce870efbf6764711e2b9f..9ff564788b2319a6c37b7522197efa7c1834e452 100644 --- a/application/modules/admin/views/scripts/users/index.phtml +++ b/application/modules/admin/views/scripts/users/index.phtml @@ -1,5 +1,5 @@ <?php -if(Class_Users::getIdentity()->isAdmin()) +if (Class_Users::isCurrentUserAdmin()) echo $this->Button_New((new Class_Entity()) ->setText($this->_('Ajouter un utilisateur'))); @@ -23,12 +23,4 @@ echo $this->button( 'users'), ['style' => 'filter: invert();']))); -echo $this->Admin_SearchUsers($this->users, - $this->total, - $this->form, - $this->page, - $this->params, - function($model) - { - return $this->renderPluginsActions($model); - }); +echo $this->searchUsers($this->search, true); diff --git a/application/modules/admin/views/scripts/users/mass-delete-run.phtml b/application/modules/admin/views/scripts/users/mass-delete-run.phtml new file mode 100644 index 0000000000000000000000000000000000000000..ec1035177e9c22af357d3f84e5a5f27683c970aa --- /dev/null +++ b/application/modules/admin/views/scripts/users/mass-delete-run.phtml @@ -0,0 +1,47 @@ +<?php +echo $this->tag('h3', 'Critères') + . $this->searchCriteriaDescription($this->criteria_description, + $this->_('Tous les utilisateurs')); + +echo $this->tag('h3', 'Progression'); + +echo $this->tag('div', $this->tag('span', ''), + ['id' => 'userDeleteProgress']); + +Class_ScriptLoader::getInstance() +->addJQueryReady(' +$("#userDeleteProgress").progressbar({value:false, max:' . $this->count . '}); + +function runNext(done) { + $.getJSON("' . $this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'mass-delete-run-step', + 'total' => $this->count], + null, true) . '/done/" + done + "?' . http_build_query($this->criteria_params) . '", + function(data) { + $("#userDeleteProgress").progressbar("option", "max", data.total); + $("#userDeleteProgress").progressbar("value", data.done); + if (data.done < data.total) + return runNext(data.done); + + $("#userDeleteProgress").progressbar("destroy"); + $("#userDeleteProgress").html(\'<p class="success">Suppression terminée</p>\'); + } + ) + .fail(function() { + $("#userDeleteProgress").progressbar("destroy"); + $("#userDeleteProgress").html(\'<p class="error">Une erreur est survenue</p>\'); + }); +} + +runNext(0); +'); + + +echo $this->tag('br') + . $this->button_Back((new Class_Entity) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'index'], + null, true) + . '?' . http_build_query($this->criteria_params))); diff --git a/application/modules/admin/views/scripts/users/mass-delete.phtml b/application/modules/admin/views/scripts/users/mass-delete.phtml new file mode 100644 index 0000000000000000000000000000000000000000..1e3a3b0285b541c614120b2f671f142952030bac --- /dev/null +++ b/application/modules/admin/views/scripts/users/mass-delete.phtml @@ -0,0 +1,57 @@ +<?php +echo + $this->tag('h3', $this->_('ATTENTION : vous vous apprêtez à supprimer %s utilisateurs', + $this->count), + ['class' => 'error']) + + . $this->tag('p', $this->_('Correspondants aux critères suivants : ')); + +echo $this->searchCriteriaDescription($this->criteria_description, + $this->_('Tous les utilisateurs')); + +echo $this->tag('p', $this->tag('strong', $this->_('NB : Votre compte ne peut pas être supprimé par cette mécanique.')), + ['style' => 'font-size:80%']); + +echo + $this->tag('h3', $this->_('Données liées supprimées')) + . $this->tag('p', $this->_('Les types de données suivants sont supprimés en même temps que les utilisateurs')) + . $this->tagUlLi([$this->_('L\'appartenance aux groupes'), + $this->_('L\'inscription aux lettres d\'informations'), + $this->_('L\'apartenance aux agendas de rendez-vous'), + $this->_('Les cartes liées'), + $this->_('Les recherches enregistrées')]) + ; + +echo + $this->tag('h3', $this->_('Données liées anonymisées')) + . $this->tag('p', $this->_('Les types de données suivants sont anonymisés lorsque leurs utilisateurs sont supprimés')) + . $this->tagUlLi([$this->_('L\'apartenance à un envoi de lettre d\'informations'), + $this->_('Les avis sur les notices'), + $this->_('Les avis sur les articles'), + $this->_('Les paniers de notices'), + $this->_('Les suggestions d\'achat'), + $this->_('L\'inscription aux activités'), + $this->_('L\'intervention dans les activités'), + $this->_('Les formulaires envoyés'), + $this->_('Les réservations de postes multimédia')]) + ; + +echo + $this->tag('br') + . $this->button_Back((new Class_Entity) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'index'], + null, true) + . '?' . http_build_query($this->criteria_params))) + + . $this->button((new Class_Entity) + ->setText($this->_('Lancer la suppression')) + ->setImage($this->tagImg(Class_Admin_Skin::current() + ->getIconUrl('buttons', 'validate'))) + ->setUrl($this->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'mass-delete-run'], + null, true) + . '?' . http_build_query($this->criteria_params))) + ; diff --git a/library/Class/Formulaire.php b/library/Class/Formulaire.php index e8dcffa769e0d05c6fee1cc78cf25de729184d40..9f06f343a717a6441074489b3a862d9060328f44 100644 --- a/library/Class/Formulaire.php +++ b/library/Class/Formulaire.php @@ -48,9 +48,8 @@ class Class_Formulaire extends Storm_Model_Abstract { public static function mergeDataNames($formulaires) { $names = []; - foreach($formulaires as $formulaire) { + foreach($formulaires as $formulaire) $names=array_merge($names,$formulaire->getDataNames()); - } return array_unique($names); } @@ -92,9 +91,9 @@ class Class_Formulaire extends Storm_Model_Abstract { return ''; } + public function getDataNames() { return array_keys(array_change_key_case($this->getDatas())); - } @@ -173,4 +172,12 @@ class Class_Formulaire extends Storm_Model_Abstract { public function beValidated() { return $this->setValidated(true); } + + + public function anonymize() { + if ($mail = $this->getMail()) + $this->setMailAnswer(serialize($mail->clearRecipients())); + + return $this; + } } diff --git a/library/Class/Newsletter/DispatchUser.php b/library/Class/Newsletter/DispatchUser.php index 7935ad5a2a851482fa11d6a2e1ef62c9de8f8d40..b054dddc9f4d7b3f007775d62ba9cf708da0ce4b 100644 --- a/library/Class/Newsletter/DispatchUser.php +++ b/library/Class/Newsletter/DispatchUser.php @@ -50,4 +50,9 @@ class Class_Newsletter_DispatchUser extends Storm_Model_Abstract { $this->setSent(1)->save(); return $this; } + + + public function anonymize() { + return $this->setMail(''); + } } diff --git a/library/Class/RendezVous/SearchCriteria/Date.php b/library/Class/RendezVous/SearchCriteria/Date.php index 948edb414408f3c69027a74f28636a857c350b64..40d260af5bb3885d7a519289c326452f561c7747 100644 --- a/library/Class/RendezVous/SearchCriteria/Date.php +++ b/library/Class/RendezVous/SearchCriteria/Date.php @@ -20,81 +20,24 @@ */ -class Class_RendezVous_SearchCriteria_Date extends Class_SearchCriteria_Abstract { - use Trait_TimeSource; +class Class_RendezVous_SearchCriteria_Date extends Class_SearchCriteria_DateRange { + protected $_name = 'date'; - const DATE_FORMAT = 'd/m/Y'; - - protected - $_name = 'date', - $_start_name, - $_end_name, - $_value_start = '', - $_value_end = ''; - - - public function __construct($params) { - $this->_start_name = $this->getName() . '_start'; - $this->_end_name = $this->getName() . '_end'; - - parent::__construct($params); - - $this->_value_start = isset($params[$this->_start_name]) - ? $this->_filterDate($params[$this->_start_name]) - : $this->getTimeSource()->dateFormat(static::DATE_FORMAT); - $this->_element->setStartValue($this->_value_start); - - $this->_value_end = isset($params[$this->_end_name]) - ? $this->_filterDate($params[$this->_end_name]) - : $this->getTimeSource()->asDateTime() - ->modify('+3 month') - ->format(static::DATE_FORMAT); - $this->_element->setEndValue($this->_value_end); - } - - - protected function buildElement() { - $options = ['label' => $this->_('Date'), - 'start' => ['name' => $this->_start_name], - 'end' => ['name' => $this->_end_name], - ]; - - return new ZendAfi_Form_Element_DateRangePicker($this->getName(), $options); + protected function _defaultStart() { + return $this->getTimeSource()->dateFormat(static::DATE_FORMAT); } - public function acceptSearchVisitor($visitor) { - if ($this->_value_start) - $visitor->addWhereParam('date >= "' . $this->_sqlFormat($this->_value_start) . '"'); - - if ($this->_value_end) - $visitor->addWhereParam('date <= "' . $this->_sqlFormat($this->_value_end) . '"'); + protected function _defaultEnd() { + return $this->getTimeSource()->asDateTime() + ->modify('+3 month') + ->format(static::DATE_FORMAT); } - protected function _filterDate($value) { - if (null === $value) - return; - - if ('' === $value) - return ''; - - if (!(new ZendAfi_Validate_DateFormat())->isValid($value, static::DATE_FORMAT)) { - $this->_element->addError($this->_('Les dates doivent être au format JJ/MM/AAAA')); - return; - } - - return $value; - } - - - protected function _sqlFormat($value) { - return implode('-', array_reverse(explode('/', $value))); - } - - - public function getCompositeValues() { - return [$this->_start_name => $this->_value_start, - $this->_end_name => $this->_value_end]; + protected function buildElement() { + $element = parent::buildElement(); + $element->setLabel($this->_('Date')); + return $element; } } diff --git a/library/Class/SearchCriteria.php b/library/Class/SearchCriteria.php index bdd4b1f7f7e043c24a090f91847350c93d58d246..282368b6136f2d18f59b969f254bbcca6cfcab2e 100644 --- a/library/Class/SearchCriteria.php +++ b/library/Class/SearchCriteria.php @@ -48,13 +48,13 @@ abstract class Class_SearchCriteria { } - public function findPage($page=1) { + public function findPage($page=1, $page_size=20) { $this->_buildSearchParams(); return $this->_has_no_result ? [] : call_user_func([$this->_model_class, 'findAllBy'], - array_merge($this->_search_params, ['limitPage' => [$page, 20]])); + array_merge($this->_search_params, ['limitPage' => [$page, $page_size]])); } @@ -140,4 +140,11 @@ abstract class Class_SearchCriteria { $this->_has_no_result = true; return $this; } + + + public function describeOn($view) { + return array_filter((new Storm_Collection($this->_criteria)) + ->collect(function($c) use($view) { return $c->describeOn($view); }) + ->getArrayCopy()); + } } diff --git a/library/Class/SearchCriteria/Abstract.php b/library/Class/SearchCriteria/Abstract.php index aa8233c0978495f823efb437dc190ba0685f4fdd..817d0e18023714c0cf3ef7d07284dc5b70db5492 100644 --- a/library/Class/SearchCriteria/Abstract.php +++ b/library/Class/SearchCriteria/Abstract.php @@ -66,4 +66,8 @@ abstract class Class_SearchCriteria_Abstract { $visitor->addParam($this->_name, $this->_value); } + + + public function describeOn($view) { + } } \ No newline at end of file diff --git a/library/Class/SearchCriteria/DateRange.php b/library/Class/SearchCriteria/DateRange.php new file mode 100644 index 0000000000000000000000000000000000000000..81d54b34159abb03778e43490c8379d1b14182c9 --- /dev/null +++ b/library/Class/SearchCriteria/DateRange.php @@ -0,0 +1,121 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_SearchCriteria_DateRange extends Class_SearchCriteria_Abstract { + use Trait_TimeSource; + + const DATE_FORMAT = 'd/m/Y'; + + protected + $_start_name, + $_end_name, + $_value_start = '', + $_value_end = ''; + + + public function __construct($params) { + $this->_start_name = $this->getName() . '_start'; + $this->_end_name = $this->getName() . '_end'; + + parent::__construct($params); + + $this->_value_start = isset($params[$this->_start_name]) + ? $this->_filterDate($params[$this->_start_name]) + : $this->_defaultStart(); + $this->_element->setStartValue($this->_value_start); + + $this->_value_end = isset($params[$this->_end_name]) + ? $this->_filterDate($params[$this->_end_name]) + : $this->_defaultEnd(); + $this->_element->setEndValue($this->_value_end); + } + + + protected function _defaultStart() { + return ''; + } + + + protected function _defaultEnd() { + return ''; + } + + + protected function buildElement() { + return new ZendAfi_Form_Element_DateRangePicker($this->getName(), + ['start' => ['name' => $this->_start_name], + 'end' => ['name' => $this->_end_name]]); + } + + + public function acceptSearchVisitor($visitor) { + if ($this->_value_start) + $visitor->addWhereParam($this->_name . ' >= "' . $this->_sqlFormat($this->_value_start) . '"'); + + if ($this->_value_end) + $visitor->addWhereParam($this->_name . ' <= "' . $this->_sqlFormat($this->_value_end) . '"'); + } + + + protected function _filterDate($value) { + if (null === $value) + return; + + if ('' === $value) + return ''; + + if (!(new ZendAfi_Validate_DateFormat())->isValid($value, static::DATE_FORMAT)) { + $this->_element->addError($this->_('Les dates doivent être au format JJ/MM/AAAA')); + return; + } + + return $value; + } + + + protected function _sqlFormat($value) { + return implode('-', array_reverse(explode('/', $value))); + } + + + public function getCompositeValues() { + return [$this->_start_name => $this->_value_start, + $this->_end_name => $this->_value_end]; + } + + + public function describeOn($view) { + if ('' == $this->_value_start && '' == $this->_value_end) + return; + + $description = $this->_element->getLabel() . ' : '; + if ('' != $this->_value_start && '' != $this->_value_end) + return $description . $this->_('entre le %s et le %s', + $this->_value_start, $this->_value_end); + + if ('' != $this->_value_start) + return $description . $this->_('depuis le %s', $this->_value_start); + + if ('' != $this->_value_end) + return $description . $this->_('jusqu\'au %s', $this->_value_end); + } +} diff --git a/library/Class/SearchCriteria/Select.php b/library/Class/SearchCriteria/Select.php new file mode 100644 index 0000000000000000000000000000000000000000..ce2cbfeeb50b3684131f41e64e6ca258d3b825e8 --- /dev/null +++ b/library/Class/SearchCriteria/Select.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_SearchCriteria_Select extends Class_SearchCriteria_Abstract { + protected $_value = Class_SearchCriteria_Abstract::DEFAULT_VALUE; + + protected function buildElement() { + return new Zend_Form_Element_Select($this->getName(), ['value' => $this->_value]); + } + + + public function describeOn($view) { + return ($this->_element && static::DEFAULT_VALUE != $this->_value) + ? $this->_element->getLabel() . ' : ' . $this->_element->getMultiOption($this->_value) + : ''; + } +} diff --git a/library/Class/TableDescription/RendezVousUsers.php b/library/Class/TableDescription/RendezVousUsers.php new file mode 100644 index 0000000000000000000000000000000000000000..85f1f9d006938ab8421991ccf6144218a4476e02 --- /dev/null +++ b/library/Class/TableDescription/RendezVousUsers.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_TableDescription_RendezVousUsers extends Class_TableDescription_UsersBasic { + public function init() { + parent::init(); + $this + ->addRowAction(function($model) + { + return $this->renderModelActions($model, + [['url' => '#', + 'icon' => 'add_user', + 'label' => $this->_('Ajouter "%s" comme destinataire', + $model->getNomComplet()), + 'anchorOptions' => ['class' => 'user_add_action', + 'data-userid' => $model->getId(), + 'data-username' => $model->getNomComplet()]] + ]); +}) + ; + } +} diff --git a/library/Class/TableDescription/Users.php b/library/Class/TableDescription/Users.php index 5eb31b27d5b7904e679ae563fbf78ca14a6aa513..f72fcf68be1f35e6b12493a7595b44bc50e393e6 100644 --- a/library/Class/TableDescription/Users.php +++ b/library/Class/TableDescription/Users.php @@ -20,25 +20,9 @@ */ -class Class_TableDescription_Users extends Class_TableDescription { +class Class_TableDescription_Users extends Class_TableDescription_UsersBasic { public function init() { - $acl = new ZendAfi_Acl_AdminControllerRoles(); - - $role_renderer = function($model) use($acl) { - return $acl->getLibelleRole($model->getRoleLevel()); - }; - - $library_renderer = function($model) { - return $model->getLibelleBib(); - }; - - $this - ->addColumn($this->_('Identifiant'), 'login') - ->addColumn($this->_('Nom'), 'nom') - ->addColumn($this->_('Prénom'), 'prenom') - ->addColumn($this->_('Role'), ['attribute' => 'role_level', - 'callback' => $role_renderer]) - ->addColumn($this->_('Bibliothèque'), ['callback' => $library_renderer, - 'sortable' => false]); + parent::init(); + $this->addRowPluginsActions(); } } diff --git a/library/Class/TableDescription/UsersBasic.php b/library/Class/TableDescription/UsersBasic.php new file mode 100644 index 0000000000000000000000000000000000000000..e72654e0bb75452688835d48bc7ed1b2483c6a8d --- /dev/null +++ b/library/Class/TableDescription/UsersBasic.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_TableDescription_UsersBasic extends Class_TableDescription { + public function init() { + $role_renderer = function($model) { + return ZendAfi_Acl_AdminControllerRoles::getLibelleRole($model->getRoleLevel()); + }; + + $library_renderer = function($model) { + return $model->getLibelleBib(); + }; + + $this + ->addColumn($this->_('Identifiant'), 'login') + ->addColumn($this->_('Nom'), 'nom') + ->addColumn($this->_('Prénom'), 'prenom') + ->addColumn($this->_('Role'), ['attribute' => 'role_level', + 'callback' => $role_renderer]) + ->addColumn($this->_('Bibliothèque'), ['callback' => $library_renderer, + 'sortable' => false]); + } +} diff --git a/library/Class/User/SearchCriteria.php b/library/Class/User/SearchCriteria.php index 867c1a870334ec02043cf6c7cf52087edd64d525..8162b9b8f2609903673572cab2899b91e3d3096b 100644 --- a/library/Class/User/SearchCriteria.php +++ b/library/Class/User/SearchCriteria.php @@ -27,59 +27,65 @@ class Class_User_SearchCriteria extends Class_SearchCriteria { $this->_criteria = [new Class_User_SearchCriteriaLibrary($params), new Class_User_SearchCriteriaRoleLevel($params), new Class_User_SearchCriteriaValidSubscription($params), + new Class_User_SearchCriteria_DateFin($params), + new Class_User_SearchCriteria_InLastSigbExport($params), + new Class_User_SearchCriteria_DateMaj($params), new Class_User_SearchCriteria_NumberOfReviews($params), new Class_User_SearchCriteria_NumberOfBaskets($params), new Class_User_SearchCriteriaSearchFor($params), new Class_User_SearchCriteria_Order($params)]; } - - - public function getForm() { - Class_ScriptLoader::getInstance() - ->addJQueryReady('formSelectToggleVisibilityForElement("#search_role_level", $("#search_valid_subscription").closest("tr"), ["2"]);'); - - return parent::getForm(); - } } - -class Class_User_SearchCriteriaLibrary extends Class_SearchCriteria_Abstract{ - protected - $_name = 'id_site', - $_value = Class_SearchCriteria_Abstract::DEFAULT_VALUE; +class Class_User_SearchCriteriaLibrary extends Class_SearchCriteria_Select { + protected $_name = 'id_site'; public function buildElement() { - return new Zend_Form_Element_Select($this->getName(), - ['label' => $this->_('Bibliothèque'), - 'multiOptions' => ['all' => $this->_('Toutes')] + Class_Bib::findAllLabels(), - 'value' => $this->_value]); + return parent::buildElement() + ->setLabel($this->_('Bibliothèque')) + ->setMultiOptions(['all' => $this->_('Toutes')] + Class_Bib::findAllLabels()); } } -class Class_User_SearchCriteriaRoleLevel extends Class_SearchCriteria_Abstract { - protected - $_name = 'role_level', - $_value = Class_SearchCriteria_Abstract::DEFAULT_VALUE; +class Class_User_SearchCriteriaRoleLevel extends Class_SearchCriteria_Select { + protected $_name = 'role_level'; public function buildElement() { + $this->_headScript(); + if ((!Class_Users::getIdentity()->isAdmin()) - && $this->_value == Class_SearchCriteria_Abstract::DEFAULT_VALUE) + && static::DEFAULT_VALUE == $this->_value) $this->_value = ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB; - return new Zend_Form_Element_Select($this->getName(), - ['label' => $this->_('Niveau d\'accès'), - 'multiOptions' => ['all' => $this->_('Tous')] + ZendAfi_Acl_AdminControllerRoles::getRolesLabelsWithOutSuperAdmin(), - 'value' => $this->_value]); + return parent::buildElement() + ->setLabel($this->_('Niveau d\'accès')) + ->setMultiOptions(['all' => $this->_('Tous')] + + ZendAfi_Acl_AdminControllerRoles::getRolesLabelsWithOutSuperAdmin()); } public function isAbonneSigb() { - return $this->_value == ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB; + return ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB == $this->_value; + } + + + protected function _headScript() { + $toggles = array_map(function($other) + { + return sprintf('formSelectToggleVisibilityForElement("#%s", $("#%s").closest("tr"), ["2"]);', + $this->getName(), + static::NAME_PREFIX . $other); + }, + ['valid_subscription', + 'statut', + 'date_fin_start']); + + Class_ScriptLoader::getInstance()->addJQueryReady(implode($toggles)); } } @@ -112,6 +118,13 @@ class Class_User_SearchCriteriaValidSubscription extends Class_SearchCriteria_Ab $visitor->addWhereParam('STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()'); } + + + public function describeOn($view) { + return (0 != $this->_value) + ? $this->_element->getLabel() + : ''; + } } @@ -153,4 +166,11 @@ class Class_User_SearchCriteriaSearchFor extends Class_SearchCriteria_Abstract{ $visitor->addWhereParam(implode(' OR ', $table_or)); } + + + public function describeOn($view) { + return ($this->_value) + ? ($this->_element->getLabel() . ' : ' . $this->_value) + : ''; + } } \ No newline at end of file diff --git a/library/Class/User/SearchCriteria/DateFin.php b/library/Class/User/SearchCriteria/DateFin.php new file mode 100644 index 0000000000000000000000000000000000000000..67c733eb10629880935e41f8fd13ccb3f698a2c5 --- /dev/null +++ b/library/Class/User/SearchCriteria/DateFin.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_SearchCriteria_DateFin extends Class_SearchCriteria_DateRange { + protected + $_name = 'date_fin'; + + + protected function buildElement() { + return parent::buildElement()->setLabel($this->_('Date de fin d\'abonnement')); + } +} diff --git a/library/Class/User/SearchCriteria/DateMaj.php b/library/Class/User/SearchCriteria/DateMaj.php new file mode 100644 index 0000000000000000000000000000000000000000..ee3fd5661109a2f954c8bc30548062562f2842bc --- /dev/null +++ b/library/Class/User/SearchCriteria/DateMaj.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_SearchCriteria_DateMaj extends Class_SearchCriteria_DateRange { + protected + $_name = 'date_maj'; + + + protected function buildElement() { + return parent::buildElement()->setLabel($this->_('Mis à jour')); + } +} diff --git a/library/Class/User/SearchCriteria/InLastSigbExport.php b/library/Class/User/SearchCriteria/InLastSigbExport.php new file mode 100644 index 0000000000000000000000000000000000000000..98e93f2fa520e7d93a077a71bba40af4ab27d7fb --- /dev/null +++ b/library/Class/User/SearchCriteria/InLastSigbExport.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_SearchCriteria_InLastSigbExport extends Class_SearchCriteria_Select { + protected $_name = 'statut'; + + protected function buildElement() { + return parent::buildElement() + ->setLabel($this->_('Présent dans le dernier export SIGB')) + ->setMultiOptions([static::DEFAULT_VALUE => $this->_('Indifférent'), + '0' => $this->_('Oui'), + '1' => $this->_('Non')]); + } +} diff --git a/library/Class/User/SearchCriteria/NumberOfBaskets.php b/library/Class/User/SearchCriteria/NumberOfBaskets.php index 38b7010fdaddedae19f30bdcf6e9013debfe848b..76997334343bf24853a0623c0fd6686598d8c26c 100644 --- a/library/Class/User/SearchCriteria/NumberOfBaskets.php +++ b/library/Class/User/SearchCriteria/NumberOfBaskets.php @@ -19,24 +19,21 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -class Class_User_SearchCriteria_NumberOfBaskets extends Class_SearchCriteria_Abstract { - protected - $_name = 'basket', - $_value = 'all'; - +class Class_User_SearchCriteria_NumberOfBaskets extends Class_SearchCriteria_Select { + protected $_name = 'basket'; public function buildElement() { - return new Zend_Form_Element_Select($this->getName(), - ['label' => $this->_('A créé des paniers'), - 'multiOptions' => ['yes' => $this->_('Oui'), - 'no' => $this->_('Non'), - 'all' => $this->_('Indifférent')], - 'value' => $this->_value]); + return parent::buildElement() + ->setLabel($this->_('A créé des paniers')) + ->setMultiOptions(['yes' => $this->_('Oui'), + 'no' => $this->_('Non'), + 'all' => $this->_('Indifférent')]) + ; } public function acceptSearchVisitor($visitor) { - if ('all' == $this->_value) + if (static::DEFAULT_VALUE == $this->_value) return; $ids = Class_PanierNotice::findAllUserIds(); diff --git a/library/Class/User/SearchCriteria/NumberOfReviews.php b/library/Class/User/SearchCriteria/NumberOfReviews.php index 3b34c510fca6f907634d0bb441775d93dd6df141..5f069d055e62274321a3213e77de111ff14598d6 100644 --- a/library/Class/User/SearchCriteria/NumberOfReviews.php +++ b/library/Class/User/SearchCriteria/NumberOfReviews.php @@ -19,24 +19,21 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -class Class_User_SearchCriteria_NumberOfReviews extends Class_SearchCriteria_Abstract { - protected - $_name = 'review', - $_value = 'all'; - +class Class_User_SearchCriteria_NumberOfReviews extends Class_SearchCriteria_Select { + protected $_name = 'review'; public function buildElement() { - return new Zend_Form_Element_Select($this->getName(), - ['label' => $this->_('A rédigé des avis'), - 'multiOptions' => ['yes' => $this->_('Oui'), - 'no' => $this->_('Non'), - 'all' => $this->_('Indifférent')], - 'value' => $this->_value]); + return parent::buildElement() + ->setLabel($this->_('A rédigé des avis')) + ->setMultiOptions(['yes' => $this->_('Oui'), + 'no' => $this->_('Non'), + 'all' => $this->_('Indifférent')]) + ; } public function acceptSearchVisitor($visitor) { - if ('all' == $this->_value) + if (static::DEFAULT_VALUE == $this->_value) return; $ids = Class_AvisNotice::findAllUserIds(); diff --git a/library/Class/Users.php b/library/Class/Users.php index 9ca72c7a86b1a08d98f3390f73fc00f90a5b30c3..3b7a433574aaf5a0f4441133619c00c923a8dc5b 100644 --- a/library/Class/Users.php +++ b/library/Class/Users.php @@ -1942,4 +1942,13 @@ class Class_Users extends Storm_Model_Abstract { public function isAllowedToAccess($controller, $action) { return (new ZendAfi_Acl_AdminControllerGroup)->isAllowed($this, $controller, $action); } + + + public function afterDelete() { + foreach($this->getDispatchUsers() as $dispatch_user) + $dispatch_user->anonymize()->save(); + + foreach($this->getFormulaires() as $form) + $form->anonymize()->save(); + } } diff --git a/library/ZendAfi/Controller/Action/Helper/SearchRendezVous.php b/library/ZendAfi/Controller/Action/Helper/Search.php similarity index 81% rename from library/ZendAfi/Controller/Action/Helper/SearchRendezVous.php rename to library/ZendAfi/Controller/Action/Helper/Search.php index 7bc013dd97e476bb2ba69e0e307792fbbab8c80c..03bad744276f09963c92c8a3d00a49b87d456609 100644 --- a/library/ZendAfi/Controller/Action/Helper/SearchRendezVous.php +++ b/library/ZendAfi/Controller/Action/Helper/Search.php @@ -1,6 +1,6 @@ <?php /** - * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved. + * Copyright (c) 2012-2019, 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 @@ -20,11 +20,10 @@ */ -class ZendAfi_Controller_Action_Helper_SearchRendezVous +class ZendAfi_Controller_Action_Helper_Search extends Zend_Controller_Action_Helper_Abstract { protected - $view, $_models = [], $_total = 0, $_page = 1, @@ -33,21 +32,18 @@ class ZendAfi_Controller_Action_Helper_SearchRendezVous /** * @param $action_params array - * @param $criteria Class_RendezVous_SearchCriteria + * @param $criteria Class_SearchCriteria */ - public function searchRendezVous($action_params, $criteria) { + protected function _search($action_params, $criteria) { if (!$action_params) $action_params = []; - $this->view = $this->getActionController()->view; - $this->_page = $this->_getParam('page', 1); $this->_models = $criteria->findPage($this->_page); $this->_total = $criteria->count(); $this->_form = $this->_prepareForm($action_params, $criteria); $this->_params = array_merge($criteria->getFormValues(), - ['page' => $this->_page, - 'search_order' => $this->_getParam('search_order', 'date desc')]); + ['page' => $this->_page]); return $this; } @@ -96,6 +92,6 @@ class ZendAfi_Controller_Action_Helper_SearchRendezVous public function direct($action_params=[], $criteria) { - return $this->searchRendezVous($action_params, $criteria); + return $this->_search($action_params, $criteria); } } \ No newline at end of file diff --git a/library/ZendAfi/Controller/Action/Helper/UserSearch.php b/library/ZendAfi/Controller/Action/Helper/UserSearch.php deleted file mode 100644 index 68d0f1158b4ecb4c8cd5498c27b2cae2c70b4f9e..0000000000000000000000000000000000000000 --- a/library/ZendAfi/Controller/Action/Helper/UserSearch.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * Copyright (c) 2012-2014, 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_UserSearch extends Zend_Controller_Action_Helper_Abstract { - protected $view; - - /** - * @param $action_params array - * @param $criteria Class_User_SearchCriteria - */ - public function userSearch($action_params, $criteria) { - if (!$action_params) - $action_params = []; - - $this->view = $this->getActionController()->view; - - $this->view->page = $this->_getParam('page', 1); - $this->view->users = $criteria->findPage($this->view->page); - $this->view->total = $criteria->count(); - $this->view->form = $this->_prepareForm($action_params, $criteria); - $this->view->params = array_merge($this->view->form->getValues(), - ['page' => $this->view->page, - 'search_order' => $this->_getParam('search_order', 'nom asc')]); - - } - - - protected function _prepareForm($action_params, $criteria) { - $form = $criteria->getForm(); - - $url_params = array_merge(['module' => $this->getRequest()->getModuleName(), - 'controller' => $this->getRequest()->getControllerName(), - 'action' => $this->getRequest()->getActionName()], - $action_params); - - return $form->setAction(Class_Url::absolute($url_params, null, true)); - } - - - protected function _getParam($name, $default=null) { - return $this->getRequest()->getParam($name, $default); - } - - - public function direct($action_params=[], $criteria) { - return $this->userSearch($action_params, $criteria); - } -} \ No newline at end of file diff --git a/library/ZendAfi/Controller/Plugin/Manager/Newsletter.php b/library/ZendAfi/Controller/Plugin/Manager/Newsletter.php index 29e7af8fde0b8dc4d673ac8202fdd89f8691a6c7..a5d3a8ae966f2fe2fdee4575eac2cc4a59e88fc2 100644 --- a/library/ZendAfi/Controller/Plugin/Manager/Newsletter.php +++ b/library/ZendAfi/Controller/Plugin/Manager/Newsletter.php @@ -181,11 +181,11 @@ class ZendAfi_Controller_Plugin_Manager_Newsletter extends ZendAfi_Controller_Pl $this->_view->newsletter = $model; $this->_view->groups = $model->getSortedRecipientsByDedicatedAndLabel(); - $criteria = (new Class_User_SearchCriteria($this->_request->getParams())) - ->addCriteria(new Class_User_SearchCriteria_NewsletterSubscriptionStatus($this->_request->getParams())) - ->addCriteria(new Class_User_SearchCriteria_WithMail($this->_request->getParams())); + $params = $this->_request->getParams(); + $criteria = (new Class_User_SearchCriteria($params)) + ->addCriteria(new Class_User_SearchCriteria_NewsletterSubscriptionStatus($params)) + ->addCriteria(new Class_User_SearchCriteria_WithMail($params)); - $this->_helper->userSearch(['id' => $model->getId()], $criteria); + $this->_view->search = $this->_helper->search(['id' => $model->getId()], $criteria); } } -?> \ No newline at end of file diff --git a/library/ZendAfi/Controller/Plugin/Manager/User.php b/library/ZendAfi/Controller/Plugin/Manager/User.php index 71440fb095b9b0abe99d18a6f234ec17f59f52f0..7637f518550c5cfe70406ec6bed4e9aef11873b0 100644 --- a/library/ZendAfi/Controller/Plugin/Manager/User.php +++ b/library/ZendAfi/Controller/Plugin/Manager/User.php @@ -123,4 +123,63 @@ class ZendAfi_Controller_Plugin_Manager_User extends ZendAfi_Controller_Plugin_M protected function _canEdit($model) { return $model->getRoleLevel() <= Class_Users::getIdentity()->getRoleLevel(); } + + + public function massDeleteAction() { + $this->_massDelete(); + } + + + public function massDeleteRunAction() { + $this->_massDelete(); + } + + + protected function _massDelete() { + if (!$criteria = $this->_massDeleteCriteria()) + return; + + $this->_view->titre = $this->_('Suppression de %s utilisateurs', $this->_view->count); + $this->_view->criteria_description = $criteria->describeOn($this->_view); + $this->_view->criteria_params = $criteria->getFormValues(); + } + + + public function massDeleteRunStepAction() { + if (!$criteria = $this->_massDeleteCriteria()) { + $this->_helper->json([]); + return $this->_response->setHttpResponseCode(400); + } + + $criteria + ->addParam('id_user not', Class_Users::getIdentity()->getId()) + ->addParam('role_level not', ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN); + + if (!$page = $criteria->findPage(1, 100)) { + $total = $this->_getParam('total', 0); + return $this->_helper->json(['total' => $total, 'done' => $total]); + } + + foreach($page as $user) + $user->delete(); + + $this->_helper->json(['total' => $this->_getParam('total', 0), + 'done' => $this->_getParam('done', 0) + count($page)]); + } + + + protected function _massDeleteCriteria() { + $params = $this->_request->getParams(); + $criteria = (new Class_User_SearchCriteria($params)) + ->addCriteria(new Class_User_SearchCriteria_RoleLevelLimit($params)); + + $this->_view->count = $criteria->count(); + if (1 < $this->_view->count) + return $criteria; + + $this->_helper + ->notify($this->_('Impossible de supprimer une sélection de moins de 2 utilisateurs')); + + $this->_redirectToReferer(); + } } \ No newline at end of file diff --git a/library/ZendAfi/Controller/Plugin/Manager/UsergroupAgenda.php b/library/ZendAfi/Controller/Plugin/Manager/UsergroupAgenda.php index af68dd42bab2ec774f4d28ad05543a460521677a..eebaba6df889fae789a7fc43f8399d5d4d840405 100644 --- a/library/ZendAfi/Controller/Plugin/Manager/UsergroupAgenda.php +++ b/library/ZendAfi/Controller/Plugin/Manager/UsergroupAgenda.php @@ -52,12 +52,7 @@ class ZendAfi_Controller_Plugin_Manager_UsergroupAgenda public function allAction() { $this->_view->titre = $this->_('Tous les rendez-vous'); - $this->_view->rendezvous = Class_RendezVous::findAllBy([ "order" => ["date desc", "begin_time desc" , "end_time desc"]]); - - $params = $this->_request->getParams(); - $this->_view->search = $this->_helper - ->searchRendezVous([], - new Class_RendezVous_SearchCriteria($params)); + $this->_view->search = $this->_helper->search([], new Class_RendezVous_SearchCriteria($this->_request->getParams())); } @@ -69,7 +64,7 @@ class ZendAfi_Controller_Plugin_Manager_UsergroupAgenda ->withoutCriteria('Class_User_SearchCriteria_NumberOfReviews') ->withoutCriteria('Class_User_SearchCriteria_NumberOfBaskets'); - $this->_helper->userSearch([], $criteria); + $this->_view->search = $this->_helper->search([], $criteria); } diff --git a/library/ZendAfi/Form/Decorator/UserSelection.php b/library/ZendAfi/Form/Decorator/UserSelection.php index bd38a2150ca52a16c45744a7b6809c02e17ce06f..67298fd12c5c3914ef6402df7c49e0b9e8f47bc9 100644 --- a/library/ZendAfi/Form/Decorator/UserSelection.php +++ b/library/ZendAfi/Form/Decorator/UserSelection.php @@ -36,7 +36,7 @@ remove_icon_url:' . json_encode($skin->getIconUrl('actions', 'delete')) . ', add_message:' . json_encode($this->_element->getAddMessage()). ', delete_message:' . json_encode($this->_element->getDeleteMessage()). '})'); - $description = (new Class_TableDescription_Users('current_user_selection_' . $this->_element->getName())) + $description = (new Class_TableDescription_UsersBasic('current_user_selection_' . $this->_element->getName())) ->addRowAction(function($model) use($view) { return $view->renderModelActions($model, diff --git a/library/ZendAfi/Mail.php b/library/ZendAfi/Mail.php index fc8ab96a5d515226fd111a3767a757d5b35d109e..a1b7039c084f39212dc7b2f0814ee0b2369f80ff 100644 --- a/library/ZendAfi/Mail.php +++ b/library/ZendAfi/Mail.php @@ -92,6 +92,11 @@ class ZendAfi_Mail extends Zend_Mail { parent::setBodyText($txt, 'utf-8', Zend_Mime::ENCODING_8BIT); return $this; } -} -?> \ No newline at end of file + + public function clearRecipients() { + $this->_recipients = []; + $this->_headers['To'] = []; + return $this; + } +} diff --git a/library/ZendAfi/View/Helper/Admin/Search.php b/library/ZendAfi/View/Helper/Admin/Search.php new file mode 100644 index 0000000000000000000000000000000000000000..c1a437b29ab6af160ea404186678900f12a6ed8b --- /dev/null +++ b/library/ZendAfi/View/Helper/Admin/Search.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright (c) 2012-2019, 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 + */ + + +abstract class ZendAfi_View_Helper_Admin_Search extends ZendAfi_View_Helper_BaseHelper { + protected + $_context, + $_table_description_class, + $_table_id; + + protected function _search($context) { + $this->_context = $context; + + return + $this->view->renderForm($context->getForm()) + . $this->_headerLine() + . $this->_getTable() + ; + } + + + protected function _headerLine() { + return $this->_tag('p', + $this->_resultMessage($this->_context->getTotal())); + } + + + protected function _resultMessage($total) { + return $this->view->_plural($total, + 'Auncun élément trouvé', + '%d élément trouvé', + '%d éléments trouvés', + $total); + } + + + protected function _getTable() { + $pager = $this->view->Pager($this->_context->getTotal(), + 20, + $this->_context->getPage(), + array_merge($this->_context->getParams(), ['page' => null])); + return $pager + . $this->view->renderTable($this->_getTableDescription(), $this->_context->getModels()) + . $pager; + } + + + protected function _getTableDescription() { + $description_class = $this->_table_description_class; + $order_anchor_callback = function($label, $attribute) { + return $this->_orderAnchor($label, $attribute); + }; + + return (new $description_class($this->_table_id, $order_anchor_callback)) + ->setSorterServer(); + } + + + protected function _orderAnchor($label, $attribute) { + $order = $this->_context->getParams()['search_order']; + $order_param = $attribute; + + if((0 === strpos($order, $attribute)) && (false === strpos($order, 'desc'))) + $order_param .= ' desc'; + + $data_order = (0 === strpos($order, $attribute)) + ? str_replace(' ', '_', 'order_' . $order_param) + : ''; + + $action_params = ['module' => 'admin', + 'controller' => $this->_context->getRequest()->getControllerName(), + 'action' => $this->_context->getRequest()->getActionName()]; + + if ($this->view->isPopup()) + $action_params['render'] = 'popup'; + + $url = $this->view->url($action_params, null, true) + . '?' + . http_build_query(array_merge($this->_context->getParams(), + ['search_order' => $order_param, + 'page' => null])) + ; + $html = $this->view->tagAnchor($url, $label, ['data-order' => $data_order]); + + return function() use($html) { return $html; }; + } +} \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Admin/SearchCriteriaDescription.php b/library/ZendAfi/View/Helper/Admin/SearchCriteriaDescription.php new file mode 100644 index 0000000000000000000000000000000000000000..f1ee0bce6e912540d01ca529c52e43c033befe11 --- /dev/null +++ b/library/ZendAfi/View/Helper/Admin/SearchCriteriaDescription.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright (c) 2012-2019, 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_View_Helper_Admin_SearchCriteriaDescription extends ZendAfi_View_Helper_BaseHelper { + public function searchCriteriaDescription($description, $empty_label=null) { + if (!$empty_label) + $empty_label = $this->_('Tous'); + + return $this->_tag('ul', + implode(array_map(function($item) { return $this->_tag('li', $item); }, + $description ? $description : [$empty_label]))); + } +} diff --git a/library/ZendAfi/View/Helper/Admin/SearchNewsletterUsers.php b/library/ZendAfi/View/Helper/Admin/SearchNewsletterUsers.php new file mode 100644 index 0000000000000000000000000000000000000000..5cc11c697656883c6e1b4c03af54826bc020c29e --- /dev/null +++ b/library/ZendAfi/View/Helper/Admin/SearchNewsletterUsers.php @@ -0,0 +1,89 @@ +<?php +/** + * Copyright (c) 2012-2014, 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_View_Helper_Admin_SearchNewsletterUsers + extends ZendAfi_View_Helper_Admin_SearchUsers { + + protected + $_table_description_class = 'Class_TableDescription_UsersBasic', + $_newsletter; + + + public function searchNewsletterUsers($newsletter, $context) { + $this->_newsletter = $newsletter; + return $this->_search($context); + } + + + protected function _getTableDescription() { + $description = parent::_getTableDescription(); + + $no_mail_action = $this->_tag('div' , + Class_Admin_Skin::current() + ->renderActionIconOn('help', + $this->view, + ['title' => $this->_('Utilisateur sans mail'), + 'class' => 'ico']), + ['class' => 'actions']); + + $actions = function($model) use ($no_mail_action) { + $is_recipient = $this->_newsletter->hasRecipient($model, false); + $is_blacklisted = $this->_newsletter->isBlackListed($model); + + if (!$is_recipient) + return $this->view->renderModelActions($model, + [['url' => $this->_buildUrl('subscribe'), + 'icon' => 'add', + 'label' => $this->_('Inscrire')] + ]); + + if ($is_blacklisted) + return $this->view->renderModelActions($model, + [['url' => $this->_buildUrl('subscribe'), + 'icon' => 'back', + 'label' => $this->_('Réinscrire')] + ]);; + + if (!$model->hasMail()) + return $no_mail_action; + + return $this->view->renderModelActions($model, + [['url' => $this->_buildUrl('unsubscribe'), + 'icon' => 'cancel', + 'label' => $this->_('Désinscrire')] + ]); + }; + + return $description->addRowAction($actions); + } + + + protected function _buildUrl($action) { + return $this->view->url(['module' => 'admin', + 'controller' => 'newsletter', + 'action' => 'edit-subscribers', + 'id' => $this->_newsletter->getId()], + null, true) + . '/' . $action . '/%s' + . '?' . http_build_query($this->_context->getParams()); + } +} \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Admin/SearchRendezVous.php b/library/ZendAfi/View/Helper/Admin/SearchRendezVous.php index 89af2681183053ccda471da9ce2c4e6ea21fe07f..279a0f859dd4f7984ba9bac42f36cb006ad545bb 100644 --- a/library/ZendAfi/View/Helper/Admin/SearchRendezVous.php +++ b/library/ZendAfi/View/Helper/Admin/SearchRendezVous.php @@ -20,77 +20,23 @@ */ -class ZendAfi_View_Helper_Admin_SearchRendezVous extends ZendAfi_View_Helper_BaseHelper { +class ZendAfi_View_Helper_Admin_SearchRendezVous + extends ZendAfi_View_Helper_Admin_Search { + protected - $_context; + $_table_description_class = 'Class_TableDescription_RendezVousSearch', + $_table_id = 'rendez-vous'; public function searchRendezVous($context) { - $this->_context = $context; - $total = $context->getTotal(); - - return - $this->view->renderForm($context->getForm(), - [$this->view->button((new Class_Entity()) - ->setText($this->_('Rechercher')) - ->setImage($this->view->tagImg(Class_Admin_Skin::current() - ->getIconUrl('actions', - 'loupe'), - ['style' => 'filter: invert();'])) - ->setAttribs(['onclick' => "var form=$(this).parents('form'); if (!form.length) form=$(this).parents('.boutons, .admin-buttons').prevAll('form');if (!form.length) form=$(this).parents('.boutons, .admin-buttons').nextAll('form');form.submit(); return false;", - 'type' => 'submit', - 'class' => 'search', - 'title' => $this->_('Lancer la recherche')]))]) . - - $this->_tag('p', $this->view->_plural($total, - 'Auncun rendez-vous trouvé', - '%d rendez-vous trouvé', - '%d rendez-vous trouvés', - $total)) . - $this->_getTable(); - } - - - protected function _getTable() { - $pager = $this->view->Pager($this->_context->getTotal(), - 20, - $this->_context->getPage(), - array_merge($this->_context->getParams(), ['page' => null])); - - $description = (new Class_TableDescription_RendezVousSearch('rendez-vous', - function($label, $attribute) - { - return $this->_orderAnchor($label, $attribute); - })) - ->setSorterServer(); - - return $pager - . $this->view->renderTable($description, $this->_context->getModels()) - . $pager; + return $this->_search($context); } - protected function _orderAnchor($label, $attribute) { - $order = $this->_context->getParams()['search_order']; - $order_param = $attribute; - - if((0 === strpos($order, $attribute)) && (false === strpos($order, 'desc'))) - $order_param .= ' desc'; - - $data_order = (0 === strpos($order, $attribute)) - ? str_replace(' ', '_', 'order_' . $order_param) - : ''; - - $url = $this->view->url(['module' => 'admin', - 'controller' => $this->_context->getRequest()->getControllerName(), - 'action' => $this->_context->getRequest()->getActionName()], - null, true) - . '?' - . http_build_query(array_merge($this->_context->getParams(), - ['search_order' => $order_param, - 'page' => null])) - ; - $html = $this->view->tagAnchor($url, $label, ['data-order' => $data_order]); - - return function() use($html) { return $html; }; + protected function _resultMessage($total) { + return $this->_tag('p', $this->view->_plural($total, + 'Auncun rendez-vous trouvé', + '%d rendez-vous trouvé', + '%d rendez-vous trouvés', + $total)); } } \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Admin/SearchRendezVousUsers.php b/library/ZendAfi/View/Helper/Admin/SearchRendezVousUsers.php new file mode 100644 index 0000000000000000000000000000000000000000..6d445c7b38b136f500e9b092d3fdd8fb34b4ef57 --- /dev/null +++ b/library/ZendAfi/View/Helper/Admin/SearchRendezVousUsers.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright (c) 2012-2014, 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_View_Helper_Admin_SearchRendezVousUsers + extends ZendAfi_View_Helper_Admin_SearchUsers { + + protected $_table_description_class = 'Class_TableDescription_UsersBasic'; + + + public function searchRendezVousUsers($context) { + return $this->_search($context); + } + + + protected function _getTableDescription() { + $description = parent::_getTableDescription(); + $actions = function($model) { + return $this->view + ->renderModelActions($model, + [['url' => '#', + 'icon' => 'add_user', + 'label' => $this->_('Ajouter "%s" comme destinataire', + $model->getNomComplet()), + 'anchorOptions' => ['class' => 'user_add_action', + 'data-userid' => $model->getId(), + 'data-username' => $model->getNomComplet()]] + ]); + }; + $description->addRowAction($actions); + + return $description; + } +} \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Admin/SearchUsers.php b/library/ZendAfi/View/Helper/Admin/SearchUsers.php index 65b57586b1e412803d984508e6cb8e70c14e3891..015e79889637bcb60c8baa61394d7a9613b69aaf 100644 --- a/library/ZendAfi/View/Helper/Admin/SearchUsers.php +++ b/library/ZendAfi/View/Helper/Admin/SearchUsers.php @@ -20,85 +20,50 @@ */ -class ZendAfi_View_Helper_Admin_SearchUsers extends ZendAfi_View_Helper_BaseHelper { +class ZendAfi_View_Helper_Admin_SearchUsers + extends ZendAfi_View_Helper_Admin_Search { protected - $users, - $total, - $params, - $actions; + $_table_description_class = 'Class_TableDescription_Users', + $_table_id = 'users_table', + $_with_delete; - public function admin_searchUsers($users, $total, $form, $page, $params, $actions) { - $this->users = $users; - $this->total = $total; - $this->page = $page; - $this->params = $params; - $this->actions = $actions; - return - $this->view->renderForm($form, - [$this->view->button((new Class_Entity()) - ->setText($this->_('Rechercher')) - ->setImage($this->view->tagImg(Class_Admin_Skin::current() - ->getIconUrl('actions', - 'loupe'), - ['style' => 'filter: invert();'])) - ->setAttribs(['onclick' => "var form=$(this).parents('form'); if (!form.length) form=$(this).parents('.boutons, .admin-buttons').prevAll('form');if (!form.length) form=$(this).parents('.boutons, .admin-buttons').nextAll('form');form.submit(); return false;", - 'type' => 'submit', - 'class' => 'search', - 'title' => $this->_('Lancer la recherche')]))]) . - $this->_tag('p', $this->view->_plural($this->total, - 'Auncun utilisateur trouvé', - '%d utilisateur trouvé', - '%d utilisateurs trouvés', - $this->total)) . - $this->_getUsersTable(); + public function searchUsers($context, $with_delete=false) { + $this->_with_delete = $with_delete; + return $this->_search($context); } - protected function _getUsersTable() { - $pager = $this->view->Pager($this->total, - 20, - $this->page, - array_merge($this->params, ['page' => null])); - - return $pager - . $this->_getTable() - . $pager; - } - - - protected function _getTable() { - $description = (new Class_TableDescription_Users('users_table', - function($label, $attribute) - { - return $this->_orderAnchor($label, $attribute); - })) - ->addRowAction($this->actions) - ->setSorterServer(); + protected function _headerLine() { + if (!$this->_with_delete) + return parent::_headerLine(); + + $total = $this->_context->getTotal(); + $mass_delete = 1 < $total && Class_Users::isCurrentUserAdmin() + ? $this->view->button((new Class_Entity()) + ->setText($this->_('Supprimer ces utilisateurs ...')) + ->setUrl($this->view->url(['module' => 'admin', + 'controller' => 'users', + 'action' => 'mass-delete'], + null, true) + . '?' . http_build_query($this->_context->getParams())) + ->setImage($this->view->tagImg(Class_Admin_Skin::current() + ->getIconUrl('buttons', + 'delete'), + ['style' => 'filter: invert();'])) + ->setAttribs(['style' => 'vertical-align: middle;'])) + : ''; - return $this->view->renderTable($description, - (new Class_TableDescription_Models($this->users))); + return $this->_tag('p', $this->_resultMessage($total) . $mass_delete); } - protected function _orderAnchor($label, $attribute) { - $order = $this->params['search_order']; - $order_param = $attribute; - - if((0 === strpos($order, $attribute)) && (false === strpos($order, 'desc'))) - $order_param .= ' desc'; - - $data_order = (0 === strpos($order, $attribute)) - ? str_replace(' ', '_', 'order_' . $order_param) - : ''; - - return function($view) use($order_param, $label, $data_order) { - return $view->tagAnchor(array_merge(array_filter($this->params), - ['search_order' => $order_param, - 'page' => null]), - $label, - ['data-order' => $data_order]); - }; + protected function _resultMessage($total) { + return $this->view->_plural($total, + 'Aucun utilisateur trouvé', + '%d utilisateur trouvé', + '%d utilisateurs trouvés', + $total); } } \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/TagUlLi.php b/library/ZendAfi/View/Helper/TagUlLi.php new file mode 100644 index 0000000000000000000000000000000000000000..8a113da93acf92604fa68ec6f682c8f6a62c96c4 --- /dev/null +++ b/library/ZendAfi/View/Helper/TagUlLi.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright (c) 2019, 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_View_Helper_TagUlLi extends ZendAfi_View_Helper_BaseHelper { + public function tagUlLi($items) { + return $items + ? $this->_tag('ul', + implode(array_map(function($item) { return $this->_tag('li', $item); }, + $items))) + : ''; + } +} diff --git a/library/storm b/library/storm index facf291bab370a3f01057114eecab38c2349cb97..8e752b86bc642f6563eb4b42b20fcbe8ece45b5c 160000 --- a/library/storm +++ b/library/storm @@ -1 +1 @@ -Subproject commit facf291bab370a3f01057114eecab38c2349cb97 +Subproject commit 8e752b86bc642f6563eb4b42b20fcbe8ece45b5c diff --git a/tests/application/modules/admin/controllers/NewsletterControllerTest.php b/tests/application/modules/admin/controllers/NewsletterControllerTest.php index 38f1401956f4458391bbfc934168644842ad6df3..c2f7b5e762cf8328e7a0f7cb3e3822864ebacd78 100644 --- a/tests/application/modules/admin/controllers/NewsletterControllerTest.php +++ b/tests/application/modules/admin/controllers/NewsletterControllerTest.php @@ -1335,6 +1335,12 @@ class Admin_NewsletterControllerEditSubcsribersSearchAllSubscriptionTest } + /** @test */ + public function massDeleteButtonShouldNotBePresent() { + $this->assertNotXPath('//button[contains(@onclick, "admin/users/mass-delete")]'); + } + + /** @test */ public function laurentShouldBeInList() { $this->assertXPathContentContains('//table[contains(@class, "models")]//td', 'laurent'); @@ -1598,7 +1604,7 @@ class Admin_NewsletterControllerEditSubcsribersSearchUnsubscribedWithoutResultTe /** @test */ public function shouldFindNobody() { - $this->assertNotXPathContentContains('//p', 'Aucun utilisateur trouvé'); + $this->assertXPathContentContains('//p', 'Aucun utilisateur trouvé'); } } diff --git a/tests/application/modules/admin/controllers/UsersControllerTest.php b/tests/application/modules/admin/controllers/UsersControllerTest.php index d9a967a1bbc4a32fe447681a72e2de8fc8eb7075..bafe7faa9617709a88b81db82719d66e0705ec05 100644 --- a/tests/application/modules/admin/controllers/UsersControllerTest.php +++ b/tests/application/modules/admin/controllers/UsersControllerTest.php @@ -125,6 +125,9 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { ->whenCalled('isCurrentUserCanAccesBackend') ->answers(false) + ->whenCalled('isCurrentUserAdmin') + ->answers(true) + ->whenCalled('getIdentity') ->answers($user) @@ -157,13 +160,13 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { /** @test */ - public function formShouldContainsInputSearch() { + public function formShouldContainsTextSearch() { $this->assertXPath('//input[@name="search_search_for"]'); } /** @test */ - public function formShouldContainsInputReview() { + public function formShouldContainsHasReviewSearch() { $this->assertXPath('//select[@name="search_review"]'); } @@ -174,6 +177,27 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { } + /** @test */ + public function formShouldContainsSubscriptionEndDateRange() { + $this->assertXPath('//input[@name="search_date_fin_start"]'); + $this->assertXPath('//input[@name="search_date_fin_end"]'); + } + + + /** @test */ + public function formShouldContainsInLastExportSelect() { + $this->assertXPathContentContains('//select[@name="search_statut"]//option[@value="all"]', + 'Indifférent'); + } + + + /** @test */ + public function formShouldContainsUpdateDateRange() { + $this->assertXPath('//input[@name="search_date_maj_start"]'); + $this->assertXPath('//input[@name="search_date_maj_end"]'); + } + + /** @test */ public function libSelectorShouldBePresent() { $this->assertXPath('//select[@name="search_id_site"]'); @@ -188,7 +212,7 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { /** @test */ public function totalUsersShouldBeFiftyFive() { - $this->assertXPathContentContains('//p','55 utilisateurs trouvés'); + $this->assertXPathContentContains('//p', '55 utilisateurs trouvés'); } @@ -227,6 +251,13 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase { public function allLibraryShouldBeSelectable() { $this->assertXPath('//select[@name="search_id_site"]//option[@value="all"]'); } + + + /** @test */ + public function massDeleteButtonWithCurrentQueryParamsShouldBePresent() { + $this->assertXPathContentContains('//button[contains(@onclick, "admin/users/mass-delete?search_id_site=all&search_role_level=2&search_valid_subscription=1&search_statut=all&search_review=1")]', + 'Supprimer ces utilisateurs'); + } } @@ -421,6 +452,7 @@ class UsersControllerEditMarcusAsAdminPortailTest extends UsersControllerWithMar + class UsersControllerDeleteMarcusTest extends UsersControllerWithMarcusTestCase { public function setUp() { parent::setUp(); @@ -438,6 +470,7 @@ class UsersControllerDeleteMarcusTest extends UsersControllerWithMarcusTestCase + class UsersControllerPostMarcusDataTest extends UsersControllerWithMarcusTestCase { public function setUp() { parent::setUp(); @@ -472,76 +505,94 @@ class UsersControllerPostMarcusDataTest extends UsersControllerWithMarcusTestCas Class_Users::find(10)); } + /** @test */ public function civiliteShouldBeMadame() { $this->assertEquals(Class_Users::CIVILITE_MADAME, $this->marcus->getCivilite()); } + /** @test */ public function mobileShouldBe0612450987() { $this->assertEquals('06 12 45 09 87', $this->marcus->getMobile()); } + public function testLoginIsMDavis() { $this->assertEquals('mdavis', $this->marcus->getLogin()); } + public function testPasswordIsTutu() { $this->assertEquals('tutu', $this->marcus->getPassword()); } + public function testNomIsDavis() { $this->assertEquals('Davis', $this->marcus->getNom()); } + public function testPrenomIsMiles() { $this->assertEquals('Miles', $this->marcus->getPrenom()); } + public function testNaissanceIs1976() { $this->assertEquals('1976-02-17', $this->marcus->getNaissance()); } + public function testTelephoneIs09_87_76_54_32_12() { $this->assertEquals('09 87 76 54 32 12', $this->marcus->getTelephone()); } + public function testAdresseIs12RueMiles() { $this->assertEquals('12 rue miles', $this->marcus->getAdresse()); } + public function testCodePostalIs75000() { $this->assertEquals('75000', $this->marcus->getCodePostal()); } + public function testVilleIsParis() { $this->assertEquals('Paris', $this->marcus->getVille()); } + public function testMailIsMDavisAtFreeDotFr() { $this->assertEquals('mdavis@free.fr', $this->marcus->getMail()); } + public function testRoleLevelIsFour() { $this->assertEquals(4, $this->marcus->getRoleLevel()); } + public function testIdSiteIsOne() { $this->assertEquals(1, $this->marcus->getIdSite()); } + public function testRoleIsAdministrateur() { $this->assertEquals('admin_bib', $this->marcus->getNomRole()); } + public function testOrdreabonIsTwo() { $this->assertEquals(2, $this->marcus->getOrdreabon()); } + public function testPseudoIsDave() { $this->assertEquals('Dave', $this->marcus->getPseudo()); } + public function testUserGroupsAreReferentAndStagiaires() { $this->assertEquals([22, 25], $this->marcus->getUserGroupsIds()); } @@ -549,6 +600,7 @@ class UsersControllerPostMarcusDataTest extends UsersControllerWithMarcusTestCas + class UsersControllerPostMarcusInvalidDataTest extends UsersControllerWithMarcusTestCase { public function testNoLoginPasswordAndRole() { $this->_postEditData(['login' => '', @@ -607,6 +659,8 @@ class UsersControllerPostMarcusInvalidDataTest extends UsersControllerWithMarcus } + + class UsersControllerPostValidDataWithCommOpsysTest extends UsersControllerWithMarcusTestCase { @@ -680,6 +734,7 @@ class UsersControllerPostValidDataWithCommOpsysTest + class UsersControllerAddViewTest extends AbstractControllerTestCase { protected $_storm_default_to_volatile = true; @@ -716,51 +771,53 @@ class UsersControllerAddViewTest extends AbstractControllerTestCase { + class UsersControllerReferentIndexTest extends UsersControllerWithMarcusTestCase { use Trait_UserGroupFixtures; - protected function _loginHook($account) { - $account->ROLE_LEVEL = ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL; - $account->ROLE = 'moderateur'; - - } - public function setUp() { parent::setUp(); - $roger = $this->fixture('Class_Users', - ['id' => 345, - 'login' => 'roger', - 'password' => 'roger']); - + $this->fixture('Class_Users', ['id' => 345, + 'login' => 'roger', + 'password' => 'roger']); + $this->fixture('Class_Users', ['id' => 346, + 'login' => 'norbert', + 'password' => 'norbert']); - $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')); + $user = $this->fixture('Class_Users', + ['id' => 2, + 'login' => 'referent', + 'password' => 'referent', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL]); $this->addUserToRightsReferent($user); + ZendAfi_Auth::getInstance()->logUser($user); $this->dispatch('/admin/users/index/order/prenom+desc', true); } /** @test **/ - public function testSelectedRoleForReferentIsAbonneSIGB() { + public function selectedRoleShouldBeAbonneSIGB() { $this->assertXPathContentContains("//select[@name='search_role_level']/option[@value='2'][@selected='selected']", 'Abonné SIGB'); } /** @test **/ - public function testReferentCanNotCreateNewUser() { - $this->assertNotXPathContentContains("//td", 'Ajouter un utilisateur'); + public function pageShouldContainsLinkToAddUser() { + $this->assertNotXPath('//button[contains(@onclick, "/admin/users/add")]'); + } + + + /** @test */ + public function pageShouldNotContainsLinkToMassDelete() { + $this->assertNotXPath('//button[contains(@onclick, "/admin/users/mass-delete")]'); } /** @test **/ - public function testReferentCanNotEditUser() { + public function pageShouldNotContainsLinkToEditUser() { $this->assertNotXPath("//table//a[contains(@href, 'admin/users/edit/id/345')]"); } } @@ -842,6 +899,7 @@ class UsersControllerAddActionPostTest extends UsersControllerWithMarcusTestCase + abstract class Admin_UsersControllerEditAdminTestCase extends Admin_AbstractControllerTestCase { protected @@ -900,6 +958,7 @@ abstract class Admin_UsersControllerEditAdminTestCase extends Admin_AbstractCont + class Admin_UsersControllerFormEditAdminTest extends Admin_UsersControllerEditAdminTestCase { public function setUp() { parent::setup(); @@ -950,6 +1009,7 @@ class Admin_UsersControllerFormEditAdminTest extends Admin_UsersControllerEditAd + class UsersControllerPostEditAdminTest extends Admin_UsersControllerEditAdminTestCase { public function setUp() { parent::setUp(); @@ -999,6 +1059,7 @@ class UsersControllerPostEditAdminTest extends Admin_UsersControllerEditAdminTes + class UsersControllerPostEditWithHashedPasswordAdminTest extends Admin_UsersControllerEditAdminTestCase { public function setUp() { parent::setUp(); @@ -1036,6 +1097,7 @@ class UsersControllerPostEditWithHashedPasswordAdminTest extends Admin_UsersCont + class UsersControllerEditSuperAdminTest extends Admin_AbstractControllerTestCase { protected $_storm_default_to_volatile = true; @@ -1101,6 +1163,8 @@ class Admin_UsersControllerChangeAdminSkinActionTest extends Admin_AbstractContr } + + class Admin_UsersControllerChangeRoleLevelOfUserInMyBibAsAdminBibTest extends Admin_AbstractControllerTestCase { protected $_storm_default_to_volatile = true; @@ -1159,6 +1223,7 @@ class Admin_UsersControllerChangeRoleLevelOfUserInMyBibAsAdminBibTest extends Ad + class UsersControllerWithAdminPortalTest extends Admin_AbstractControllerTestCase { protected $_storm_default_to_volatile = true; @@ -1208,13 +1273,13 @@ class UsersControllerWithAdminPortalTest extends Admin_AbstractControllerTestCas ->answers(1) ; - $this->dispatch('/admin/users/index/search_order/prenom+desc', true); + $this->dispatch('/admin/users/index?search_order=prenom+desc', true); } /** @test */ public function tableHeaderShouldContainsLinkToOrderByLastNameAsc() { - $this->assertXPath('//th//a[contains(@href, "/search_order/prenom/")]'); + $this->assertXPath('//th//a[contains(@href, "search_order=prenom")]'); } @@ -1263,7 +1328,7 @@ class UsersControllerWithAdminPortalTest extends Admin_AbstractControllerTestCas /** @test */ public function tableHeadShouldContainsLinksWithOrderNameAsc() { - $this->assertXPath('//th/a[contains(@href, "/search_order/nom/")]'); + $this->assertXPath('//th/a[contains(@href, "search_order=nom")]'); } } @@ -1575,6 +1640,7 @@ class UsersControllerManageDoubleTest extends UsersControllerDoubleTestCase { + class UsersControllerManageDoubleWithCustomCriteriaTest extends UsersControllerDoubleTestCase { public function setUp() { @@ -1602,6 +1668,7 @@ class UsersControllerManageDoubleWithCustomCriteriaTest extends UsersControllerD + class UsersControllerDeleteDoubleEndCursorTest extends Admin_AbstractControllerTestCase { public function setUp() { @@ -1626,7 +1693,6 @@ class UsersControllerDeleteDoubleEndCursorTest extends Admin_AbstractControllerT - class UsersControllerDeleteDoubleTest extends UsersControllerDoubleTestCase { public function setUp() { @@ -1889,3 +1955,229 @@ class UsersControllerIndexWithDoubleTest extends UsersControllerDoubleTestCase { $this->assertNotXPath('//td//a[contains(@href, "/admin/users/manage-double-user/id_user/123")]'); } } + + + + +abstract class UsersControllerMassDeleteTestCase extends Admin_AbstractControllerTestCase { + protected $_storm_default_to_volatile = true; + + public function setUp() { + parent::setUp(); + + $this->onLoaderOfModel('Class_Users') + ->whenCalled('countBy') + ->with(['role_level' => 2, + 'statut' => 1, + 'order' => 'nom asc', + 'where' => '(date_fin <= "2018-05-28") AND (date_maj <= "2018-05-28") AND (login LIKE "%andy%" OR nom LIKE "%andy%" OR prenom LIKE "%andy%" OR pseudo LIKE "%andy%" OR mail LIKE "%andy%" OR idabon LIKE "%andy%") AND (role_level <= 7)']) + ->answers(2) + + ->whenCalled('countBy') + ->willDo(function($params) + { + $this->fail('Unexpected call to countBy with : ' . json_encode($params)); + }) + ; + } +} + + + + +class UsersControllerMassDeleteTest extends UsersControllerMassDeleteTestCase { + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/mass-delete?search_id_site=all&search_role_level=2&search_statut=1&search_date_fin_start=&search_date_fin_end=28%2F05%2F2018&search_date_maj_start=&search_date_maj_end=28%2F05%2F2018&search_search_for=andy'); + } + + + /** @test */ + public function pageTitleShouldBeSuppressionDe2DUtilisateurs() { + $this->assertXPathContentContains('//h1', 'Suppression de 2 utilisateurs'); + } + + + /** @test */ + public function pageShouldContainsRoleLevelDescription() { + $this->assertXPathContentContains('//li', 'Niveau d\'accès : Abonné SIGB'); + } + + + /** @test */ + public function pageShouldContainsStatutDescription() { + $this->assertXPathContentContains('//li', 'Présent dans le dernier export SIGB : Non'); + } + + + /** @test */ + public function pageShouldContainsSubscriptionEndDateDescription() { + $this->assertXPathContentContains('//li', 'Date de fin d\'abonnement : jusqu\'au 28/05/2018'); + } + + + /** @test */ + public function pageShouldContainsUpdateDateDescription() { + $this->assertXPathContentContains('//li', 'Mis à jour : jusqu\'au 28/05/2018'); + } + + + /** @test */ + public function pageShouldContainsSearchForDescription() { + $this->assertXPathContentContains('//li', 'Rechercher : andy', $this->_response->getBody()); + } + + + /** @test */ + public function pageShouldContainsBackButton() { + $this->assertXPathContentContains('//button[contains(@onclick, "&search_date_fin_end=28%2F05%2F2018")]', 'Retour'); + } + + + /** @test */ + public function pageShouldContainsRunButton() { + $this->assertXPathContentContains('//button[contains(@onclick, "/admin/users/mass-delete-run")][contains(@onclick, "&search_date_fin_end=28%2F05%2F2018")]', 'Lancer la suppression'); + } +} + + + + +class UsersControllerMassDeleteRunTest extends UsersControllerMassDeleteTestCase { + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/mass-delete-run?search_id_site=all&search_role_level=2&search_statut=1&search_date_fin_start=&search_date_fin_end=28%2F05%2F2018&search_date_maj_start=&search_date_maj_end=28%2F05%2F2018&search_search_for=andy'); + } + + + /** @test */ + public function progressBarShouldBeLoaded() { + $this->assertXPathContentContains('//script', + '$("#userDeleteProgress").progressbar({value:false, max:2})'); + } +} + + + +class UsersControllerMassDeleteRunStepWithOneUserTest extends UsersControllerMassDeleteTestCase { + public function setUp() { + parent::setUp(); + $this->fixture('Class_Users', + ['id' => 999, + 'login' => 'junchiro', + 'password' => 'makoto', + 'role_level' => 2, + 'statut' => 1, + 'id_site' => 3, + 'idabon' => '00399933J28332']); + + $this->dispatch('/admin/users/mass-delete-run-step/total/2/done/0?search_id_site=all&search_role_level=2&search_statut=1&search_date_fin_start=&search_date_fin_end=28%2F05%2F2018&search_date_maj_start=&search_date_maj_end=28%2F05%2F2018&search_search_for=andy'); + } + + + /** @test */ + public function shouldHaveDeletedJunchiro() { + $this->assertNull(Class_Users::find(999)); + } + + + /** @test */ + public function shouldRespondDoneOverTotalInJson() { + $json = json_decode($this->_response->getBody()); + $this->assertEquals(1, $json->done); + $this->assertEquals(2, $json->total); + } +} + + + + +class UsersControllerMassDeleteRunStepWithoutUserTest extends UsersControllerMassDeleteTestCase { + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/users/mass-delete-run-step/total/2/done/0?search_id_site=all&search_role_level=2&search_statut=1&search_date_fin_start=&search_date_fin_end=28%2F05%2F2018&search_date_maj_start=&search_date_maj_end=28%2F05%2F2018&search_search_for=andy'); + } + + + /** @test */ + public function shouldRespondTotallyDoneInJson() { + $json = json_decode($this->_response->getBody()); + $this->assertEquals(2, $json->done); + $this->assertEquals(2, $json->total); + } +} + + + + +class UsersControllerMassDeleteRunStepMatchingCurrentUserTest + extends UsersControllerMassDeleteTestCase { + + public function setUp() { + parent::setUp(); + ZendAfi_Auth::getInstance() + ->logUser($this->fixture('Class_Users', + ['id' => 78789, + 'login' => 'admin', + 'password' => 'admin', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ADMIN_PORTAIL])); + Class_Users::getLoader() + ->whenCalled('countBy') + ->with(['order' => 'nom asc', + 'where' => '(role_level <= 6)']) + ->answers(2); + + $this->dispatch('/admin/users/mass-delete-run-step/total/2/done/0?search_id_site=all'); + } + + + /** @test */ + public function shouldNotDeleteCurrentUser() { + $this->assertNotNull(Class_Users::find(78789)); + } + + + /** @test */ + public function shouldStillRespondAllDoneInJson() { + $json = json_decode($this->_response->getBody()); + $this->assertEquals(2, $json->done); + $this->assertEquals(2, $json->total); + } +} + + + + +class UsersControllerMassDeleteRunStepMatchingSuperAdminUserTest + extends UsersControllerMassDeleteTestCase { + + public function setUp() { + parent::setUp(); + $this->fixture('Class_Users', ['id' => 78789, + 'login' => 'super', + 'password' => 'admin', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN]); + + Class_Users::getLoader() + ->whenCalled('countBy') + ->with(['order' => 'nom asc', + 'where' => '(role_level <= 7)']) + ->answers(2); + + $this->dispatch('/admin/users/mass-delete-run-step/total/2/done/0?search_id_site=all'); + } + + + /** @test */ + public function shouldNotDeleteSuperAdminUser() { + $this->assertNotNull(Class_Users::find(78789)); + } + + + /** @test */ + public function shouldStillRespondAllDoneInJson() { + $json = json_decode($this->_response->getBody()); + $this->assertEquals(2, $json->done); + $this->assertEquals(2, $json->total); + } +} \ No newline at end of file diff --git a/tests/library/Class/UsersTest.php b/tests/library/Class/UsersTest.php index 0e8c278a66950458461d50dc0e0cf3a47d7540a7..264f7d3a267fc540377d220e960a8c6c2454965d 100644 --- a/tests/library/Class/UsersTest.php +++ b/tests/library/Class/UsersTest.php @@ -152,7 +152,6 @@ class UsersTestAssociations extends ModelTestCase { - class UsersAgeTest extends ModelTestCase { public function setUp() { parent::setUp(); @@ -197,7 +196,6 @@ class UsersAgeTest extends ModelTestCase { - abstract class UsersMailingActionTestCase extends ModelTestCase { protected $mock_transport, $user; @@ -487,7 +485,6 @@ class UsersFicheAbonneTest extends ModelTestCase { - class UsersGetIdentityWithSessionErrorTest extends ModelTestCase { /** @test */ public function getIdentityShouldReturnNullOnZendSessionException() { @@ -510,6 +507,7 @@ class UsersGetIdentityWithSessionErrorTest extends ModelTestCase { } + class UsersGetUsersWithBlowfishPasswordTest extends ModelTestCase { public function setUp() { parent::setUp(); @@ -541,7 +539,7 @@ class UsersGetUsersWithBlowfishPasswordTest extends ModelTestCase { -class UserGetBookmarkedLibraryTest extends ModelTestCase { +class UsersGetBookmarkedLibraryTest extends ModelTestCase { protected $_storm_default_to_volatile = true, $_steph; @@ -645,4 +643,55 @@ class UsersWithLoginThroughSigbOnlyTest extends ModelTestCase { $this->assertTrue((new Class_User_Password($user))->isBlowFish()); } +} + + + +class UsersDeleteAnonymizeTest extends ModelTestCase { + public function setUp() { + parent::setUp(); + + $godzy = $this->fixture('Class_Users', + ['id' => 1967, + 'login' => 'Godzilla', + 'password' => 'GrrRRrrR']); + + $this->fixture('Class_Newsletter_DispatchUser', + ['id' => 90, + 'user_id' => 1967, + 'mail' => 'godzy@my-kaiju-heaven.nl', + 'sent' => 1]); + + $mail = (new ZendAfi_Mail()) + ->setFrom('admin@my-bokeh.tw') + ->addTo('godzy@my-kaiju-heaven.nl') + ->setSubject('Never mind') + ->setBodyText('Just ignore tanks and pass through the city center'); + + $this->fixture('Class_Formulaire', + ['id' => 804, + 'id_user' => 1967, + 'mail_answer' => serialize($mail)]); + + $godzy->delete(); + } + + + /** @test */ + public function newsletterDispatchUserShouldBeAnonymized() { + $this->assertEquals('', Class_Newsletter_DispatchUser::find(90)->getMail()); + } + + + /** @test */ + public function formMailAnswerRecipientShouldBeAnonymized() { + $this->assertEquals('', Class_Formulaire::find(804)->getMailDestinataire()); + } + + + /** @test */ + public function formMailAnswerHeadersShouldBeAnonymized() { + $to = Class_Formulaire::find(804)->getMail()->getHeaders()['To']; + $this->assertNotContains('godzy@my-kaiju-heaven.nl', $to, json_encode($to, JSON_PRETTY_PRINT)); + } } \ No newline at end of file diff --git a/tests/scenarios/RendezVous/UsergroupAgendaAdminTest.php b/tests/scenarios/RendezVous/UsergroupAgendaAdminTest.php index 779d866ccb8e7b5489e57c4198adc82e4256e931..925d63e02ddd853a915c409040964ab81ee973ab 100644 --- a/tests/scenarios/RendezVous/UsergroupAgendaAdminTest.php +++ b/tests/scenarios/RendezVous/UsergroupAgendaAdminTest.php @@ -501,6 +501,12 @@ class UsergroupAgendaAdminUserSelectActionTest extends UsergroupAgendaAdminModoP } + /** @test */ + public function massDeleteButtonShouldNotBePresent() { + $this->assertNotXPath('//button[contains(@onclick, "admin/users/mass-delete")]'); + } + + /** @test */ public function useradminPortailShouldBePresent() { $this->assertXPathContentContains('//td','padawan'); @@ -508,7 +514,7 @@ class UsergroupAgendaAdminUserSelectActionTest extends UsergroupAgendaAdminModoP /** @test */ - public function lienAjoutShouldBePresent() { + public function addLinkShouldBePresent() { $this->assertXPath('//a[contains(@data-userid, "35")][@data-username="padawan"]'); } }