diff --git a/core/core.php b/core/core.php index c86121e..e062841 100644 --- a/core/core.php +++ b/core/core.php @@ -51,7 +51,7 @@ class common const ACCESS_TIMER = 1800; // Numéro de version - const ZWII_VERSION = '1.8.01'; + const ZWII_VERSION = '1.9.00'; // URL autoupdate const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/campus-update/raw/branch/master/'; diff --git a/core/module/course/view/manage/manage.php b/core/module/course/view/manage/manage.php index 7b1d066..3a910f8 100644 --- a/core/module/course/view/manage/manage.php +++ b/core/module/course/view/manage/manage.php @@ -48,7 +48,6 @@ getUser('permission', 'course', 'edit') === true): ?>
- getUrl(2), [ 'href' => helper::baseUrl() . 'course/edit/' . $this->getUrl(2), 'value' => 'Éditer', @@ -58,13 +57,11 @@ getUser('permission', 'course', 'users') === true): ?>
- getUrl(2), [ 'href' => helper::baseUrl() . 'course/users/' . $this->getUrl(2), 'value' => 'Participants', 'ico' => 'users' ]); ?> -
diff --git a/core/module/user/user.php b/core/module/user/user.php index fbcb9f7..0b12501 100644 --- a/core/module/user/user.php +++ b/core/module/user/user.php @@ -19,6 +19,7 @@ class user extends common public static $actions = [ 'add' => self::GROUP_ADMIN, 'delete' => self::GROUP_ADMIN, + 'usersDelete' => self::GROUP_ADMIN, 'import' => self::GROUP_ADMIN, 'index' => self::GROUP_ADMIN, 'template' => self::GROUP_ADMIN, @@ -229,6 +230,145 @@ class user extends common } } + /** + * Désinscription de tous les utilisateurs + * Les désinscriptions ne suppriment pas les historiques + */ + public function usersDelete() + { + + // Contenu sélectionné + $courseId = $this->getUrl(2); + + // Accès limité aux admins, à l'auteur ou éditeurs inscrits + if ( + $this->getUser('permission', __CLASS__, __FUNCTION__) !== true + ) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + + // Inscription des utilisateurs cochés + if ( + isset($_POST['usersDeleteSubmit']) + ) { + foreach ($_POST as $keyPost => $valuePost) { + // Exclure les variables post qui ne sont pas des userId et ne traiter que les non inscrits + if ( + $this->getData(['user', $keyPost]) !== null + && $this->getData(['user', $keyPost]) !== null + ) { + $this->deleteData(['user', $keyPost]); + } + } + } + + // Liste des groupes et des profils + $usersGroups = $this->getData(['profil']); + + foreach ($usersGroups as $groupId => $groupValue) { + switch ($groupId) { + case "-1": + case "0": + break; + case "3": + self::$usersGroups['30'] = 'Administrateur'; + $profils['30'] = 0; + break; + case "1": + case "2": + foreach ($groupValue as $profilId => $profilValue) { + if ($profilId) { + self::$usersGroups[$groupId . $profilId] = sprintf(helper::translate('Groupe %s - Profil %s'), self::$groupPublics[$groupId], $profilValue['name']); + $profils[$groupId . $profilId] = 0; + } + } + } + } + + // Liste alphabétique + self::$alphabet = range('A', 'Z'); + $alphabet = range('A', 'Z'); + self::$alphabet = array_combine($alphabet, self::$alphabet); + self::$alphabet = array_merge(['all' => 'Tout'], self::$alphabet); + + // Liste des inscrits dans le contenu sélectionné. + $users = $this->getData(['user']); + if (is_array($users)) { + // Tri du tableau par défaut par $userId + ksort($users); + foreach ($users as $userId => $userValue) { + + // Compte les rôles + if (isset($profils[$this->getData(['user', $userId, 'group']) . $this->getData(['user', $userId, 'profil'])])) { + $profils[$this->getData(['user', $userId, 'group']) . $this->getData(['user', $userId, 'profil'])]++; + } + + // Filtres + if ( + isset($_POST['usersFilterGroup']) + || isset($_POST['usersFilterFirstName']) + || isset($_POST['usersFilterLastName']) + ) { + + // Groupe et profils + $group = (string) $this->getData(['user', $userId, 'group']); + $profil = (string) $this->getData(['user', $userId, 'profil']); + $firstName = $this->getData(['user', $userId, 'firstname']); + $lastName = $this->getData(['user', $userId, 'lastname']); + if ( + $this->getInput('usersFilterGroup', helper::FILTER_INT) > 0 + && $this->getInput('usersFilterGroup', helper::FILTER_STRING_SHORT) !== $group . $profil + ) + continue; + // Première lettre du prénom + if ( + $this->getInput('usersFilterFirstName', helper::FILTER_STRING_SHORT) !== 'all' + && $this->getInput('usersFilterFirstName', helper::FILTER_STRING_SHORT) !== strtoupper(substr($firstName, 0, 1)) + ) + continue; + // Première lettre du nom + if ( + $this->getInput('usersFilterLastName', helper::FILTER_STRING_SHORT) !== 'all' + && $this->getInput('usersFilterLastName', helper::FILTER_STRING_SHORT) !== strtoupper(substr($lastName, 0, 1)) + ) + continue; + } + + // Construction du tableau + self::$users[] = [ + template::checkbox($userId, true, '', ['class' => 'checkboxSelect']), + $userId, + $this->getData(['user', $userId, 'firstname']), + $this->getData(['user', $userId, 'lastname']), + $this->getData(['user', $userId, 'tags']), + ]; + + } + } + + // Ajoute les effectifs aux profils du sélecteur + foreach (self::$usersGroups as $groupId => $groupValue) { + if ($groupId === 'all') { + self::$usersGroups['all'] = self::$usersGroups['all'] . ' (' . array_sum($profils) . ')'; + } else { + self::$usersGroups[$groupId] = self::$usersGroups[$groupId] . ' (' . $profils[$groupId] . ')'; + } + } + + // Valeurs en sortie + $this->addOutput([ + 'title' => helper::translate('Désincription en masse'), + 'view' => 'usersDelete', + 'vendor' => [ + 'datatables' + ] + ]); + } + + /** * Édition */ diff --git a/core/module/user/view/index/index.php b/core/module/user/view/index/index.php index cf44cb4..b2acbd3 100644 --- a/core/module/user/view/index/index.php +++ b/core/module/user/view/index/index.php @@ -8,20 +8,28 @@
'https://doc.zwiicms.fr/gestion-des-utilisateurs', - 'target' => '_blank', - 'value' => template::ico('help'), - 'class' => 'buttonHelp', - 'help' => 'Consulter l\'aide en ligne' - ]);*/?> + 'href' => 'https://doc.zwiicms.fr/gestion-des-utilisateurs', + 'target' => '_blank', + 'value' => template::ico('help'), + 'class' => 'buttonHelp', + 'help' => 'Consulter l\'aide en ligne' + ]);*/ ?>
-
+
helper::baseUrl() . 'user/import', - 'value' => template::ico('upload'), + 'value' => template::ico('users'), 'help' => 'Importer des utilisateurs en masse' ]); ?>
+
+ 'userDeleteAll buttonRed', + 'href' => helper::baseUrl() . 'user/usersDelete/' . $this->getUrl(2), + 'value' => template::ico('users'), + 'help' => 'Désinscrire en masse', + ]) ?> +
helper::baseUrl() . 'user/profil', @@ -60,4 +68,4 @@
- 'dataTables']); ?> \ No newline at end of file + 'dataTables']); ?> \ No newline at end of file diff --git a/core/module/user/view/usersDelete/usersDelete.css b/core/module/user/view/usersDelete/usersDelete.css new file mode 100644 index 0000000..0273197 --- /dev/null +++ b/core/module/user/view/usersDelete/usersDelete.css @@ -0,0 +1,26 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2024, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ + +#usersDeleteSubmit { + background-color: rgba(217, 95, 78, 1); +} + +tr { + cursor: pointer; +} diff --git a/core/module/user/view/usersDelete/usersDelete.js.php b/core/module/user/view/usersDelete/usersDelete.js.php new file mode 100644 index 0000000..2a5ce08 --- /dev/null +++ b/core/module/user/view/usersDelete/usersDelete.js.php @@ -0,0 +1,100 @@ +/** + * This file is part of Zwii. + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2024, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.fr/ + */ + +$(document).ready((function () { + + $('tr').click(function () { + // Cochez ou décochez la case à cocher dans cette ligne + $(this).find('input[type="checkbox"]').prop('checked', function (i, val) { + return !val; // Inverse l'état actuel de la case à cocher + }); + }); + + $('#usersDeleteSelectAll').on('click', function () { + $('.checkboxSelect').prop('checked', true); + saveCheckboxState(); + }); + $('#usersDeleteSelectNone').on('click', function () { + $('.checkboxSelect').prop('checked', false); + saveCheckboxState(); + }); + + $("#usersFilterGroup, #usersFilterFirstName, #usersFilterLastName").change(function () { + saveCheckboxState(); + $("#usersDeleteForm").submit(); + }); + + var table = $('#dataTables').DataTable({ + language: { + url: "core/vendor/datatables/french.json" + }, + locale: 'fr', + "columnDefs": [ + { + target: 0, + orderable: false, + searchable: false, + } + ] + }); + + // Handle checkbox change event + $('.checkboxSelect').on('change', function () { + // Save checkbox state to cookies or local storage + saveCheckboxState(); + }); + + // Handle checkbox state on DataTables draw event + table.on('draw', function () { + // Restore checkbox state from cookies or local storage + restoreCheckboxState(); + }); + + // Empty local storage after submit + $("#usersDeleteSubmit").on("click", function () { + localStorage.setItem('checkboxState', JSON.stringify({})); + }); + + // Restore checkbox state on page load + restoreCheckboxState(); + + function saveCheckboxState() { + + // Récupérer d'abord les données existantes dans le localStorage + var existingData = JSON.parse(localStorage.getItem('checkboxState')) || {}; + + // Ajouter ou mettre à jour les données actuelles + $('.checkboxSelect').each(function () { + var checkboxId = $(this).attr('id'); + var checked = $(this).prop('checked'); + existingData[checkboxId] = checked; + }); + + // Sauvegarder les données mises à jour dans le localStorage + localStorage.setItem('checkboxState', JSON.stringify(existingData)); + } + + // Function to restore checkbox state + function restoreCheckboxState() { + var checkboxState = JSON.parse(localStorage.getItem('checkboxState')) || {}; + // console.log(checkboxState); + for (var checkboxId in checkboxState) { + if (checkboxState.hasOwnProperty(checkboxId)) { + var checked = checkboxState[checkboxId]; + // Update checkbox state based on stored information + $('#' + checkboxId).prop('checked', checked); + } + } + } + +})); \ No newline at end of file diff --git a/core/module/user/view/usersDelete/usersDelete.php b/core/module/user/view/usersDelete/usersDelete.php new file mode 100644 index 0000000..723a80e --- /dev/null +++ b/core/module/user/view/usersDelete/usersDelete.php @@ -0,0 +1,55 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . 'user/' . $this->getUrl(2), + 'value' => template::ico('left') + ]); ?> +
+
+ template::ico('square-check'), + 'help' => 'Tout sélectionner' + ]); ?> +
+
+ template::ico('square-check-empty'), + 'help' => 'Tout désélectionner' + ]); ?> +
+
+ 'buttonRed', + 'ico' => '', + 'value' => template::ico('minus'), + ]); ?> +
+
+
+
+ 'Groupes / Profils', + 'selected' => isset($_POST['usersFilterGroup']) ? $_POST['usersFilterGroup'] : 'all', + ]); ?> +
+
+ 'Prénom commence par', + 'selected' => isset($_POST['usersFilterFirstName']) ? $_POST['usersFilterFirstName'] : 'all', + ]); ?> +
+
+ 'Nom commence par', + 'selected' => isset($_POST['usersFilterLastName']) ? $_POST['usersFilterLastName'] : 'all', + ]); ?> +
+
+ + 'dataTables']); ?> + + + + \ No newline at end of file