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