Compare commits

...

34 Commits

Author SHA1 Message Date
cbc7a1ad19 1.21.04 sécurisation de la méthode de changement de mot de passe. 2025-01-31 18:13:00 +01:00
e7e0fef37e 1.20.03 version 2025-01-31 10:45:45 +01:00
d0f14f0e60 1.20.03 Dépréciation concaténation 2025-01-31 09:52:52 +01:00
cca646b1be revert page edit script 2025-01-31 09:31:49 +01:00
6db9837238 revert page edit script 2025-01-30 16:39:13 +01:00
ca313a2b18 1.20.03 revert page edit 2025-01-30 16:36:36 +01:00
547dea7350 1.20.02 save dataversion 2025-01-30 13:07:37 +01:00
9d6e229e0a 1.20.02
Installe la variable de masquage des pages dans les thèmes où elle n'a pas été définie.
Corrige le décalage du contenu de la page lorsque les pages sont masquées du menu.
Mise à jour du jeu de données 1.20.02
2025-01-30 13:03:40 +01:00
22d69ccafb 1.20.01 bug template table 2025-01-29 20:39:49 +01:00
5e59984211 1.20.01 bug de theme à installation 2025-01-29 20:17:31 +01:00
0301e1f31d 1.20.00 commente 2025-01-29 16:51:02 +01:00
1f0d490688 Bug page Editor 2025-01-28 18:44:40 +01:00
288393778a Bug édition de page 2025-01-28 18:22:28 +01:00
7773bc916f Revert "Revert Optimisation Page Edit"
This reverts commit 5ebbcfcb9d025e53029ed9f252ac5bac686506c4.
2025-01-28 18:10:29 +01:00
5ebbcfcb9d Revert Optimisation Page Edit 2025-01-28 17:29:43 +01:00
f237d0bca1 1.20.00 2025-01-28 12:33:02 +01:00
70fa6efee7 Message d'erreur d'envoi de l'email de réinitialisaiton 2025-01-27 18:52:41 +01:00
30ed4349d9 Formatage du message d'erreur d'erreur de démarrage 2025-01-27 18:43:55 +01:00
ad998c17d1 Liste des users, corrige la colonne date de dernière connexion. 2025-01-26 20:50:19 +01:00
4d6b6f8d4f Bug template table, id des colonnes mal placés 2025-01-26 20:49:37 +01:00
dd3582b9db Supprime des commentaires 2025-01-25 22:25:12 +01:00
0e26e71a50 1.19.05 Script page edit optimisé 2025-01-25 22:22:45 +01:00
9a56fc9572 Revert "1.19.05 Page edit script optimisé"
This reverts commit ac8689b40aeadb0b43a5c90824cd74fc05f2ad75.
2025-01-25 21:58:16 +01:00
ac8689b40a 1.19.05 Page edit script optimisé 2025-01-25 21:50:29 +01:00
0f9a79411d 1.9.05 Tri par date et bug dernière page vue 2025-01-25 19:03:49 +01:00
b944a3bac7 Renforce jsonDB 2025-01-25 14:21:31 +01:00
4bab81c541 1.19.04 Fix bug du formulaire édition de page 2025-01-24 19:40:41 +01:00
2f3dd5926b 1.19..04 Supprime jquery de datatable 2025-01-24 18:47:07 +01:00
959139b239 Miniature des images vectorielles 2025-01-24 18:01:36 +01:00
e958287b9e 1.19.04 largeur de page de l'espace lorsque les pages sont désactivées dans le menu 2025-01-24 17:40:31 +01:00
e110e7b4f9 Bug setup 2025-01-24 17:28:55 +01:00
61ec8c04be Bug descripteur php 8 2025-01-24 17:17:50 +01:00
f0ccf8eb2f 1.19.04 bordure autour du form update et install 2025-01-23 21:22:43 +01:00
b831275901 1.19.04 cadre autour du form update 2025-01-23 21:17:11 +01:00
27 changed files with 388 additions and 238 deletions

View File

@ -1,4 +1,4 @@
# ZwiiCampus 1.19.03 # ZwiiCampus 1.21.00
ZwiiCampus (Learning Management System) est logiciel auteur destiné à mettre en ligne des tutoriels. Il dispose de plusieurs modalités d'ouverture et d'accès des contenus. Basé sur la version 13 du CMS Zwii, la structure logicielle est solide, le framework de Zwii est éprouvé. ZwiiCampus (Learning Management System) est logiciel auteur destiné à mettre en ligne des tutoriels. Il dispose de plusieurs modalités d'ouverture et d'accès des contenus. Basé sur la version 13 du CMS Zwii, la structure logicielle est solide, le framework de Zwii est éprouvé.

View File

@ -170,6 +170,7 @@ class JsonDb extends \Prowebcraft\Dot
if ($this->data === null) { if ($this->data === null) {
throw new \RuntimeException('Tentative de sauvegarde de données nulles'); throw new \RuntimeException('Tentative de sauvegarde de données nulles');
} }
try { try {
$encoded_data = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_THROW_ON_ERROR); $encoded_data = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_THROW_ON_ERROR);
} catch (\JsonException $e) { } catch (\JsonException $e) {
@ -190,8 +191,11 @@ class JsonDb extends \Prowebcraft\Dot
return; return;
} }
} }
error_log("Échec sauvegarde : longueur incorrecte ou renommage échoué (tentative " . ($attempt + 1) . ")");
} catch (\Exception $e) { } catch (\Exception $e) {
// Nettoyer le fichier temporaire en cas d'exception error_log('Erreur de sauvegarde : ' . $e->getMessage());
if (file_exists($temp_file)) { if (file_exists($temp_file)) {
unlink($temp_file); unlink($temp_file);
} }
@ -200,7 +204,6 @@ class JsonDb extends \Prowebcraft\Dot
usleep(pow(2, $attempt) * 250000); usleep(pow(2, $attempt) * 250000);
} }
// Erreur fatale si tous les essais échouent
throw new \RuntimeException('Échec de sauvegarde après ' . $max_attempts . ' tentatives'); throw new \RuntimeException('Échec de sauvegarde après ' . $max_attempts . ' tentatives');
} }
} }

View File

@ -613,8 +613,7 @@ class layout extends common
} }
// Retourne les items du menu // Retourne les items du menu
echo '<ul class="navMain" id="menuLeft">' . $itemsLeft . '</ul><ul class="navMain" id="menuRight">' . $itemsRight; echo '<ul class="navMain" id="menuLeft">' . $itemsLeft . '</ul><ul class="navMain" id="menuRight">' . $itemsRight . '</ul>';
echo '</ul>';
} }
/** /**

View File

@ -254,18 +254,18 @@ class core extends common
// Déterminer la hauteur max du menu pour éviter les débordements // Déterminer la hauteur max du menu pour éviter les débordements
$padding = $this->getData(['theme', 'menu', 'height']); // Par exemple, "10px 20px" // $padding = $this->getData(['theme', 'menu', 'height']); // Par exemple, "10px 20px"
$fontSize = (float) $this->getData(['theme', 'text', 'fontSize']); // Taille de référence en pixels // $fontSize = (float) $this->getData(['theme', 'text', 'fontSize']); // Taille de référence en pixels
$menuFontSize = (float) $this->getData(['theme', 'menu', 'fontSize']); // Taille du menu en em // $menuFontSize = (float) $this->getData(['theme', 'menu', 'fontSize']); // Taille du menu en em
// Extraire la première valeur du padding (par exemple "10px 20px" -> "10px") // Extraire la première valeur du padding (par exemple "10px 20px" -> "10px")
$firstPadding = (float) explode(" ", $padding)[0]; // Nous prenons la première valeur, supposée être en px // $firstPadding = (float) explode(" ", $padding)[0]; // Nous prenons la première valeur, supposée être en px
// Convertir menuFontSize (en em) en pixels // Convertir menuFontSize (en em) en pixels
$menuFontSizeInPx = $menuFontSize * $fontSize; // $menuFontSizeInPx = $menuFontSize * $fontSize;
// Calculer la hauteur totale // Calculer la hauteur totale
$totalHeight = $firstPadding + $fontSize + $menuFontSizeInPx; // $totalHeight = $firstPadding + $fontSize + $menuFontSizeInPx;
// Fixer la hauteur maximale de la barre de menu // Fixer la hauteur maximale de la barre de menu
// $css .= '#menuLeft, nav, a.active {max-height:' . $totalHeight . 'px}'; // $css .= '#menuLeft, nav, a.active {max-height:' . $totalHeight . 'px}';

View File

@ -884,6 +884,10 @@ class template
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="tableWrapper ' . $attributes['classWrapper'] . '">'; $html = '<div id="' . $attributes['id'] . 'Wrapper" class="tableWrapper ' . $attributes['classWrapper'] . '">';
// Début tableau // Début tableau
$html .= '<table id="' . $attributes['id'] . '" class="table ' . $attributes['class'] . '">'; $html .= '<table id="' . $attributes['id'] . '" class="table ' . $attributes['class'] . '">';
// Pas de tableau d'Id transmis, générer une numérotation
if (empty($rowsId)) {
$rowsId = range(0, count($cols));
}
// Entêtes // Entêtes
if ($head) { if ($head) {
// Début des entêtes // Début des entêtes
@ -891,21 +895,17 @@ class template
$html .= '<tr class="nodrag">'; $html .= '<tr class="nodrag">';
$i = 0; $i = 0;
foreach ($head as $th) { foreach ($head as $th) {
$html .= '<th class="col' . $cols[$i++] . '">' . $th . '</th>'; $html .= '<th id="' . $rowsId[$i] . '" class="col' . $cols[$i++] . '">' . $th . '</th>';
} }
// Fin des entêtes // Fin des entêtes
$html .= '</tr>'; $html .= '</tr>';
$html .= '</thead>'; $html .= '</thead>';
} }
// Pas de tableau d'Id transmis, générer une numérotation
if (empty($rowsId)) {
$rowsId = range(0, count($body));
}
// Début contenu // Début contenu
$j = 0; $j = 0;
foreach ($body as $tr) { foreach ($body as $tr) {
// Id de ligne pour les tableaux drag and drop // Id de ligne pour les tableaux drag and drop
$html .= '<tr id="' . $rowsId[$j++] . '">'; $html .= '<tr>';
$i = 0; $i = 0;
foreach ($tr as $td) { foreach ($tr as $td) {
$html .= '<td class="col' . $cols[$i++] . '">' . $td . '</td>'; $html .= '<td class="col' . $cols[$i++] . '">' . $td . '</td>';

View File

@ -374,12 +374,11 @@ core.start = function () {
var totalHeight = firstPadding + fontSize + menuFontSizeInPx; var totalHeight = firstPadding + fontSize + menuFontSizeInPx;
$("#menuLeft").css({ $("#menuLeft").css({
"visibility": "hidden", "visibility": "hidden",
"overflow": "hidden",
"max-width": "10px" "max-width": "10px"
}); });
// Par défaut pour tous les thèmes. // Par défaut pour tous les thèmes.
$("#menuLeft, nav").css("max-height", totalHeight + "px").css("min-height", totalHeight + "px"); $("#menuLeft").css("max-height", totalHeight + "px").css("min-height", totalHeight + "px");
} }
}; };

View File

@ -51,7 +51,7 @@ class common
const ACCESS_TIMER = 1800; const ACCESS_TIMER = 1800;
// Numéro de version // Numéro de version
const ZWII_VERSION = '1.19.03'; const ZWII_VERSION = '1.21.00';
// URL autoupdate // URL autoupdate
const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/campus-update/raw/branch/master/'; const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/campus-update/raw/branch/master/';
@ -1251,66 +1251,94 @@ class common
} }
/* /**
* Création d'une miniature * Crée une miniature à partir d'une image source.
* Fonction utilisée lors de la mise à jour d'une version 9 à une version 10 * Cette fonction prend en charge les formats raster (JPEG, PNG, GIF, WebP, AVIF) et vectoriels (SVG).
* @param string $src image source * Pour les images vectorielles (SVG), aucune redimension n'est effectuée : une copie est réalisée.
* @param string $dets image destination *
* @param integer $desired_width largeur demandée * @param string $src Chemin de l'image source.
*/ * @param string $dest Chemin de l'image destination (avec le nom du fichier et l'extension).
function makeThumb($src, $dest, $desired_width) * @param int $desired_width Largeur demandée pour la miniature (ignorée pour les SVG).
{ * @return bool True si l'opération a réussi, false sinon.
// Vérifier l'existence du dossier de destination. */
$fileInfo = pathinfo($dest); function makeThumb($src, $dest, $desired_width)
if (!is_dir($fileInfo['dirname'])) { {
mkdir($fileInfo['dirname'], 0755, true); // Vérifier l'existence du dossier de destination.
} $fileInfo = pathinfo($dest);
$source_image = ''; if (!is_dir($fileInfo['dirname'])) {
// Type d'image mkdir($fileInfo['dirname'], 0755, true);
switch ($fileInfo['extension']) { }
case 'jpeg':
case 'jpg': $extension = strtolower($fileInfo['extension']);
$source_image = imagecreatefromjpeg($src); $mime_type = mime_content_type($src);
break;
case 'png': // Gestion des fichiers SVG (copie simple sans redimensionnement)
$source_image = imagecreatefrompng($src); if ($extension === 'svg' || $mime_type === 'image/svg+xml') {
break; return copy($src, $dest);
case 'gif': }
$source_image = imagecreatefromgif($src);
break; // Chargement de l'image source selon le type
case 'webp': $source_image = '';
$source_image = imagecreatefromwebp($src); switch ($extension) {
break; case 'jpeg':
case 'avif': case 'jpg':
$source_image = imagecreatefromavif($src); $source_image = imagecreatefromjpeg($src);
} break;
// Image valide case 'png':
if ($source_image) { $source_image = imagecreatefrompng($src);
$width = imagesx($source_image); break;
$height = imagesy($source_image); case 'gif':
/* find the "desired height" of this thumbnail, relative to the desired width */ $source_image = imagecreatefromgif($src);
$desired_height = floor($height * ($desired_width / $width)); break;
/* create a new, "virtual" image */ case 'webp':
$virtual_image = imagecreatetruecolor($desired_width, $desired_height); $source_image = imagecreatefromwebp($src);
/* copy source image at a resized size */ break;
imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height); case 'avif':
switch (mime_content_type($src)) { if (function_exists('imagecreatefromavif')) {
case 'image/jpeg': $source_image = imagecreatefromavif($src);
case 'image/jpg': } else {
return (imagejpeg($virtual_image, $dest)); return false; // AVIF non supporté
case 'image/png': }
return (imagepng($virtual_image, $dest)); break;
case 'image/gif': default:
return (imagegif($virtual_image, $dest)); return false; // Format non pris en charge
case 'image/webp': }
return (imagewebp($virtual_image, $dest));
case 'image/avif': // Image valide (formats raster uniquement)
return (imageavif($virtual_image, $dest)); if (is_resource($source_image) || (is_object($source_image) && $source_image instanceof GdImage)) {
} $width = imagesx($source_image);
} else { $height = imagesy($source_image);
return (false);
} // Calcul de la hauteur proportionnelle à la largeur demandée
} $desired_height = floor($height * ($desired_width / $width));
// Création d'une nouvelle image virtuelle redimensionnée
$virtual_image = imagecreatetruecolor($desired_width, $desired_height);
// Copie de l'image source dans l'image virtuelle avec redimensionnement
imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
// Enregistrement de l'image redimensionnée au format approprié
switch ($mime_type) {
case 'image/jpeg':
case 'image/jpg':
return imagejpeg($virtual_image, $dest);
case 'image/png':
return imagepng($virtual_image, $dest);
case 'image/gif':
return imagegif($virtual_image, $dest);
case 'image/webp':
return imagewebp($virtual_image, $dest);
case 'image/avif':
if (function_exists('imageavif')) {
return imageavif($virtual_image, $dest);
}
}
}
return false; // En cas d'échec
}
/** /**

View File

@ -3,26 +3,23 @@
/** /**
* Vérification de la version de PHP * Vérification de la version de PHP
*/ */
if (version_compare(PHP_VERSION, '7.2.0', '<')) {
if(version_compare(PHP_VERSION, '7.2.0', '<') ) { displayErrorPage('PHP 7.2+ mini requis - PHP 7.2+ mini required');
exit('PHP 7.2+ mini requis - PHP 7.2+ mini required');
} }
if ( version_compare(PHP_VERSION, '8.3.999', '>') ) { if (version_compare(PHP_VERSION, '8.3.999', '>')) {
exit('PHP 8.3 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.3 not yet supported, install PHP 7.n or PHP 8.1.n'); displayErrorPage('PHP 8.3 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.3 not yet supported, install PHP 7.n or PHP 8.1.n');
} }
/** /**
* Check les modules installés * Check les modules installés
*/ */
$e = [ $e = [
'gd', 'gd',
'json', 'json',
'date', 'date',
'mbstring', 'mbstring',
'zip', 'zip',
'intl', 'intl',
'exif', 'exif',
'Phar', 'Phar',
@ -31,26 +28,57 @@ $e = [
]; ];
$m = get_loaded_extensions(); $m = get_loaded_extensions();
$b = false; $b = false;
$missingModules = [];
foreach ($e as $k => $v) { foreach ($e as $k => $v) {
if (array_search($v,$m) === false) { if (array_search($v, $m) === false) {
$b = true; $b = true;
echo '<pre><p>Module PHP : ' . $v . ' manquant - Module PHP ' . $v . ' missing.</p></pre>'; $missingModules[] = $v;
} }
} }
if ($b) if ($b) {
exit('<pre><p>ZwiiCMS ne peut pas démarrer ; activez les extensions requises dans PHP.ini- ZwiiCMS cannot start, enabled PHP missing extensions into PHP.ini</p></pre>'); $errorMessage = 'ZwiiCMS ne peut pas démarrer ; les modules PHP suivants sont manquants : ' . implode(', ', $missingModules) . '<br />';
/** $errorMessage .= 'ZwiiCMS cannot start, the following PHP modules are missing: ' . implode(', ', $missingModules);
* Contrôle les htacess displayErrorPage($errorMessage);
*/ }
/**
* Contrôle les htaccess
*/
$d = [ $d = [
'', '',
'site/data/', 'site/data/',
'site/backup/', 'site/backup/',
'site/tmp/', 'site/tmp/',
// 'site/i18n/', pas contrôler pour éviter les pbs de mise à jour // 'site/i18n/', pas contrôler pour éviter les pbs de mise à jour
]; ];
foreach ($d as $key) { foreach ($d as $key) {
if (file_exists($key . '.htaccess') === false) if (file_exists($key . '.htaccess') === false) {
exit('<pre>ZwiiCMS ne peut pas démarrer, le fichier ' .$key . '.htaccess est manquant.<br />ZwiiCMS cannot start, file ' . $key . '.htaccess is missing.</pre>' ); $errorMessage = 'ZwiiCMS ne peut pas démarrer, le fichier ' . $key . '.htaccess est manquant.<br />';
$errorMessage .= 'ZwiiCMS cannot start, file ' . $key . '.htaccess is missing.';
displayErrorPage($errorMessage);
}
}
/**
* Fonction pour afficher une page d'erreur stylisée
*/
function displayErrorPage($message)
{
echo '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Erreur - ZwiiCMS</title>
<link rel="stylesheet" href="core\layout\error.css">
</head>
<body>
<div class="error-container">
<h1>Erreur</h1>
<p>' . $message . '</p>
</div>
</body>
</html>';
exit;
} }

View File

@ -22,7 +22,6 @@ if (
$this->setData(['core', 'dataVersion', 1700]); $this->setData(['core', 'dataVersion', 1700]);
} }
if ( if (
$this->getData(['core', 'dataVersion']) < 1800 $this->getData(['core', 'dataVersion']) < 1800
) { ) {
@ -45,4 +44,33 @@ if (
fclose($fp); fclose($fp);
} }
$this->setData(['core', 'dataVersion', 1800]); $this->setData(['core', 'dataVersion', 1800]);
} }
if (
$this->getData(['core', 'dataVersion']) < 12002
) {
/**
* Installe dans le thème du menu la variable hidePages
**/
// Tableau à insérer
$a = [
'theme' =>
['menu' => [
'hidePages' => false
]]];
// Parcourir la structure pour écrire dans les fichiers JSON
foreach ($this->getData(['course']) as $courseId => $courseValues) {
$d = json_decode(file_get_contents(self::DATA_DIR . $courseId . '/theme.json'), true);
// Insérer la variable hidePages si elle n'existe pas
if (isset($d['theme']['menu']['hidePages']) === false) {
$result = array_replace_recursive($d, $a);
file_put_contents(self::DATA_DIR . $courseId . '/theme.json', json_encode($result,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
// Forcer la régénération du fichier theme.css
if (file_exists(self::DATA_DIR . $courseId . '/theme.css')) {
unlink(self::DATA_DIR . $courseId . '/theme.css');
}
}
$this->setData(['core', 'dataVersion', 12002]);
}

View File

@ -657,6 +657,7 @@ nav a:hover {
#menuLeft { #menuLeft {
display: inline-flex; display: inline-flex;
float: left;
} }
#menuRight { #menuRight {

22
core/layout/error.css Normal file
View File

@ -0,0 +1,22 @@
body {
color: #000;
font: 75%/1.7em "Helvetica Neue", Helvetica, arial, sans-serif;
margin: 0;
padding: 80px;
background: url('../vendor/zwiico/png/error.png') 30px 30px no-repeat #fff;
}
h1 {
font-weight: bold;
color: #000;
font-size: 300%;
margin: 20px 0;
padding: 0;
}
p {
margin: 10px 0;
color: #777;
font-size: 16px;
line-height: 1.6;
}

View File

@ -44,7 +44,7 @@
<?php echo template::checkbox('configRewrite', true, 'Apache URL intelligentes', [ <?php echo template::checkbox('configRewrite', true, 'Apache URL intelligentes', [
'checked' => helper::checkRewrite(), 'checked' => helper::checkRewrite(),
'help' => 'Supprime le point d\'interrogation dans les URL, l\'option est indisponible avec les autres serveurs Web', 'help' => 'Supprime le point d\'interrogation dans les URL, l\'option est indisponible avec les autres serveurs Web',
'disabled' => helper::checkServerSoftware() === false and config->isModRewriteEnabled() 'disabled' => helper::checkServerSoftware() === false and self::isModRewriteEnabled()
]); ?> ]); ?>
</div> </div>
</div> </div>

View File

@ -339,7 +339,7 @@ class course extends common
// Valeurs en sortie // Valeurs en sortie
$this->addOutput([ $this->addOutput([
'title' => sprintf('%s %s (%s)', helper::translate('Editer l\'espace'), $this->getData(['course', $courseId, 'title' ]), $this->getUrl(2)), 'title' => sprintf('%s %s (%s)', helper::translate('Editer l\'espace'), $this->getData(['course', $courseId, 'title']), $this->getUrl(2)),
'view' => 'edit' 'view' => 'edit'
]); ]);
} }
@ -398,7 +398,7 @@ class course extends common
// Valeurs en sortie // Valeurs en sortie
$this->addOutput([ $this->addOutput([
'title' => sprintf('%s %s (%s)', helper::translate('Gérer l\'espace'), $this->getData(['course', $courseId, 'title' ]), $this->getUrl(2)), 'title' => sprintf('%s %s (%s)', helper::translate('Gérer l\'espace'), $this->getData(['course', $courseId, 'title']), $this->getUrl(2)),
'view' => 'manage' 'view' => 'manage'
]); ]);
} }
@ -736,17 +736,15 @@ class course extends common
} }
self::$courseUsers[] = [ self::$courseUsers[] = [
//$userId, //$userId,
sprintf('%s %s',$this->getData(['user', $userId, 'lastname']), $this->getData(['user', $userId, 'firstname'])), sprintf('%s %s', $this->getData(['user', $userId, 'lastname']), $this->getData(['user', $userId, 'firstname'])),
array_key_exists('lastPageView', $userValue) && isset($pages[$userValue['lastPageView']]['title']) array_key_exists('lastPageView', $userValue) && isset($pages['page'][$userValue['lastPageView']]['title'])
? $pages[$userValue['lastPageView']]['title'] ? $pages['page'][$userValue['lastPageView']]['title']
: '',
array_key_exists('lastPageView', $userValue)
? helper::dateUTF8('%d/%m/%Y', $userValue['datePageView'])
: '',
array_key_exists('datePageView', $userValue)
? helper::dateUTF8('%H:%M', $userValue['datePageView'])
: '', : '',
$this->getData(['user', $userId, 'tags']), $this->getData(['user', $userId, 'tags']),
array_key_exists('lastPageView', $userValue)
// ? helper::dateUTF8('%d/%m/%Y', $userValue['datePageView'])
? $userValue['datePageView']
: '',
$reportButton, $reportButton,
template::button('userDelete' . $userId, [ template::button('userDelete' . $userId, [
'class' => 'userDelete buttonRed', 'class' => 'userDelete buttonRed',
@ -1846,7 +1844,7 @@ class course extends common
// Valeurs en sortie // Valeurs en sortie
$this->addOutput([ $this->addOutput([
'title' => sprintf('%s %s (%s)', helper::translate('Export des pages de l\'espace'), $this->getData(['course', $courseId, 'title' ]), $this->getUrl(2)), 'title' => sprintf('%s %s (%s)', helper::translate('Export des pages de l\'espace'), $this->getData(['course', $courseId, 'title']), $this->getUrl(2)),
'view' => 'export' 'view' => 'export'
]); ]);
} }
@ -2223,4 +2221,4 @@ class course extends common
// Afficher le JSON; // Afficher le JSON;
return $data; return $data;
} }
} }

View File

@ -21,7 +21,6 @@ $(document).ready((function () {
$(location).attr("href", _this.attr("href")) $(location).attr("href", _this.attr("href"))
})) }))
})); }));
$.fn.dataTable.moment( 'DD/MM/YYYY' );
$('#dataTables').DataTable({ $('#dataTables').DataTable({
language: { language: {
url: "core/vendor/datatables/french.json" url: "core/vendor/datatables/french.json"
@ -29,14 +28,20 @@ $(document).ready((function () {
order: [[3, 'desc']], order: [[3, 'desc']],
locale: 'fr', locale: 'fr',
stateSave: true, stateSave: true,
"lengthMenu": [[10, 25, 50, 100, 299, -1], [10, 25, 50, 100, 200, "Tout"]], "lengthMenu": [[10, 25, 50, 100, 299, -1], [10, 25, 50, 100, 200, "Tout"]],
"columnDefs": [ "columnDefs": [
{ {
target: 6, targets: 3,
type: 'numeric',
render: function (data) {
return moment(data * 1000).format('DD/MM/YYYY HH:mm');
}
},
{
targets: 5,
orderable: false, orderable: false,
searchable: false searchable: false
} }]
]
}); });
})); }));

View File

@ -53,7 +53,7 @@
</div> </div>
<?php echo template::formClose(); ?> <?php echo template::formClose(); ?>
<?php if (course::$courseUsers): ?> <?php if (course::$courseUsers): ?>
<?php echo template::table([3, 4, 1, 1, 1, 1, 1], course::$courseUsers, ['Nom Prénom', 'Dernière page vue', 'Date' , 'Heure', 'Étiquettes', 'Progression', ''], ['id' => 'dataTables']); ?> <?php echo template::table([3, 3, 2, 2, 1, 1], course::$courseUsers, ['Nom Prénom', 'Dernière page vue', 'Date' , 'Étiquettes', 'Progression', ''], ['id' => 'dataTables']); ?>
<?php else: ?> <?php else: ?>
<?php echo template::speech('Aucun participant'); ?> <?php echo template::speech('Aucun participant'); ?>
<?php endif; ?> <?php endif; ?>

View File

@ -64,7 +64,7 @@ class init extends common
] ]
], ],
'core' => [ 'core' => [
'dataVersion' => 1700, 'dataVersion' => 12002,
'lastBackup' => 0, 'lastBackup' => 0,
'lastClearTmp' => 0, 'lastClearTmp' => 0,
'lastAutoUpdate' => 0, 'lastAutoUpdate' => 0,
@ -903,7 +903,8 @@ class init extends common
'selectSpace' => true, 'selectSpace' => true,
'burgerLogo' => '', 'burgerLogo' => '',
'burgerContent' => 'title', 'burgerContent' => 'title',
'width' => 'container' 'width' => 'container',
'hidePages' => false,
], ],
'site' => [ 'site' => [
'backgroundColor' => 'rgba(255, 255, 255, 1)', 'backgroundColor' => 'rgba(255, 255, 255, 1)',

View File

@ -15,4 +15,8 @@
/** NE PAS EFFACER /** NE PAS EFFACER
* admin.css * admin.css
*/ */
.container.light {
filter: drop-shadow(5px 5px 10px rgba(0, 0, 0, 0.2));
}

View File

@ -19,4 +19,8 @@
.title { .title {
font-weight: bold; font-weight: bold;
}
.container.light {
filter: drop-shadow(5px 5px 10px rgba(0, 0, 0, 0.2));
} }

View File

@ -24,7 +24,6 @@ class page extends common
'duplicate' => self::GROUP_EDITOR, 'duplicate' => self::GROUP_EDITOR,
'jsEditor' => self::GROUP_EDITOR, 'jsEditor' => self::GROUP_EDITOR,
'cssEditor' => self::GROUP_EDITOR, 'cssEditor' => self::GROUP_EDITOR,
'register' => self::GROUP_EDITOR,
]; ];
public static $pagesNoParentId = [ public static $pagesNoParentId = [
'' => 'Aucune' '' => 'Aucune'
@ -474,7 +473,7 @@ class page extends common
$this->setData(['config', 'page302', $pageId], false); $this->setData(['config', 'page302', $pageId], false);
} }
// Sauvegarde la base manuellement // Sauvegarde la base manuellement
$this->saveDB(module: 'config'); $this->saveDB('config');
// Si la page est une page enfant, actualise les positions des autres enfants du parent, sinon actualise les pages sans parents // Si la page est une page enfant, actualise les positions des autres enfants du parent, sinon actualise les pages sans parents
$lastPosition = 1; $lastPosition = 1;
$hierarchy = $this->getInput('pageEditParentPageId') ? $this->getHierarchy($this->getInput('pageEditParentPageId')) : array_keys($this->getHierarchy()); $hierarchy = $this->getInput('pageEditParentPageId') ? $this->getHierarchy($this->getInput('pageEditParentPageId')) : array_keys($this->getHierarchy());
@ -594,6 +593,19 @@ class page extends common
] ]
]); ]);
/**
* Sauvegarde l'onglet de l'utilisateur
*/
$this->setData([
'user',
$this->getUser('id'),
'view',
[
'page' => $this->getInput('containerSelected'),
'config' => $this->getData(['user', $this->getUser('id'), 'view', 'config']),
]
]);
// Creation du contenu de la page // Creation du contenu de la page
if (!is_dir(self::DATA_DIR . self::$siteContent . '/content')) { if (!is_dir(self::DATA_DIR . self::$siteContent . '/content')) {
mkdir(self::DATA_DIR . self::$siteContent . '/content', 0755); mkdir(self::DATA_DIR . self::$siteContent . '/content', 0755);
@ -760,25 +772,4 @@ class page extends common
return json_encode($d); return json_encode($d);
} }
/**
* Stocke la variable dans les paramètres de l'utilisateur pour activer la tab à sa prochaine visite
* @return never
*/
public function register(): void
{
$this->setData([
'user',
$this->getUser('id'),
'view',
[
'page' => $this->getUrl(2),
'config' => $this->getData(['user', $this->getUser('id'), 'view', 'config']),
]
]);
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'page/edit/' . $this->getUrl(3) . '/' . self::$siteContent,
]);
}
} }

View File

@ -54,15 +54,15 @@ function protectModule() {
*/ */
$( document ).ready(function() { $( document ).ready(function() {
// Changement de profil // Changement de profil
$(".pageEditGroupProfil").hide();
$("#pageEditGroupProfil" + $("#pageEditGroup").val()).show();
$("#pageEditGroup").on("change", function () {
$(".pageEditGroupProfil").hide(); $(".pageEditGroupProfil").hide();
$("#pageEditGroupProfil" + $("#pageEditGroup").val()).show(); $("#pageEditGroupProfil" + $(this).val()).show();
});
$("#pageEditGroup").on("change", function () {
$(".pageEditGroupProfil").hide();
$("#pageEditGroupProfil" + $(this).val()).show();
});
/** /**
* Sélection des onglets * Sélection des onglets
@ -70,7 +70,7 @@ $( document ).ready(function() {
var pageLayout = "<?php echo $this->getData(['user', $this->getUser('id'), 'view', 'page']);?>"; var pageLayout = "<?php echo $this->getData(['user', $this->getUser('id'), 'view', 'page']);?>";
// Non défini, valeur par défaut // Non défini, valeur par défaut
if (pageLayout == "") { if (pageLayout == "") {
pageLayout = "content"; pageLayout = "content";
} }
// Tout cacher // Tout cacher
$("#pageEditContentContainer").hide(); $("#pageEditContentContainer").hide();
@ -283,10 +283,18 @@ $( document ).ready(function() {
// Gestion des évènements // Gestion des évènements
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
/**
* Transmet le bouton de l'onglet sélectionné avant la soumission
*/
$('#pageEditForm').on('submit', function () {
$('#containerSelected').val(pageLayout);
});
/** /**
* Sélection de la page de configuration à afficher * Sélection de la page de configuration à afficher
*/ */
$("#pageEditContentButton").on("click", function () { $("#pageEditContentButton").on("click", function () {
pageLayout = "locale";
$("#pageEditContentContainer").show(); $("#pageEditContentContainer").show();
$("#pageEditExtensionContainer").hide(); $("#pageEditExtensionContainer").hide();
$("#pageEditPositionContainer").hide(); $("#pageEditPositionContainer").hide();
@ -294,23 +302,12 @@ $( document ).ready(function() {
$("#pageEditPermissionContainer").hide(); $("#pageEditPermissionContainer").hide();
$("#pageEditContentButton").addClass("activeButton"); $("#pageEditContentButton").addClass("activeButton");
$("#pageEditExtensionButton").removeClass("activeButton"); $("#pageEditExtensionButton").removeClass("activeButton");
$("#PageEditPositionButton").removeClass("activeButton"); $("#pageEditPositionButton").removeClass("activeButton");
$("#pageEditLayoutButton").removeClass("activeButton"); $("#pageEditLayoutButton").removeClass("activeButton");
$("#pageEditPermissionButton").removeClass("activeButton"); $("#pageEditPermissionButton").removeClass("activeButton");
}); });
$("#pageEditExtensionButton").on("click", function () { $("#pageEditPositionButton").on("click", function () {
$("#pageEditContentContainer").hide(); pageLayout = "position";
$("#pageEditExtensionContainer").show();
$("#pageEditPositionContainer").hide();
$("#pageEditLayoutContainer").hide();
$("#pageEditPermissionContainer").hide();
$("#pageEditContentButton").removeClass("activeButton");
$("#pageEditExtensionButton").addClass("activeButton");
$("#PageEditPositionButton").removeClass("activeButton");
$("#pageEditLayoutButton").removeClass("activeButton");
$("#pageEditPermissionButton").removeClass("activeButton");
});
$("#PageEditPositionButton").on("click", function () {
$("#pageEditContentContainer").hide(); $("#pageEditContentContainer").hide();
$("#pageEditExtensionContainer").hide(); $("#pageEditExtensionContainer").hide();
$("#pageEditPositionContainer").show(); $("#pageEditPositionContainer").show();
@ -318,11 +315,25 @@ $( document ).ready(function() {
$("#pageEditPermissionContainer").hide(); $("#pageEditPermissionContainer").hide();
$("#pageEditContentButton").removeClass("activeButton"); $("#pageEditContentButton").removeClass("activeButton");
$("#pageEditExtensionButton").removeClass("activeButton"); $("#pageEditExtensionButton").removeClass("activeButton");
$("#PageEditPositionButton").addClass("activeButton"); $("#pageEditPositionButton").addClass("activeButton");
$("#pageEditLayoutButton").removeClass("activeButton");
$("#pageEditPermissionButton").removeClass("activeButton");
});
$("#pageEditExtensionButton").on("click", function () {
pageLayout = "extension";
$("#pageEditContentContainer").hide();
$("#pageEditExtensionContainer").show();
$("#pageEditPositionContainer").hide();
$("#pageEditLayoutContainer").hide();
$("#pageEditPermissionContainer").hide();
$("#pageEditContentButton").removeClass("activeButton");
$("#pageEditExtensionButton").addClass("activeButton");
$("#pageEditPositionButton").removeClass("activeButton");
$("#pageEditLayoutButton").removeClass("activeButton"); $("#pageEditLayoutButton").removeClass("activeButton");
$("#pageEditPermissionButton").removeClass("activeButton"); $("#pageEditPermissionButton").removeClass("activeButton");
}); });
$("#pageEditLayoutButton").on("click", function () { $("#pageEditLayoutButton").on("click", function () {
pageLayout = "layout";
$("#pageEditContentContainer").hide(); $("#pageEditContentContainer").hide();
$("#pageEditExtensionContainer").hide(); $("#pageEditExtensionContainer").hide();
$("#pageEditPositionContainer").hide(); $("#pageEditPositionContainer").hide();
@ -330,11 +341,12 @@ $( document ).ready(function() {
$("#pageEditPermissionContainer").hide(); $("#pageEditPermissionContainer").hide();
$("#pageEditContentButton").removeClass("activeButton"); $("#pageEditContentButton").removeClass("activeButton");
$("#pageEditExtensionButton").removeClass("activeButton"); $("#pageEditExtensionButton").removeClass("activeButton");
$("#PageEditPositionButton").removeClass("activeButton"); $("#pageEditPositionButton").removeClass("activeButton");
$("#pageEditLayoutButton").addClass("activeButton"); $("#pageEditLayoutButton").addClass("activeButton");
$("#pageEditPermissionButton").removeClass("activeButton"); $("#pageEditPermissionButton").removeClass("activeButton");
}); });
$("#pageEditPermissionButton").on("click", function () { $("#pageEditPermissionButton").on("click", function () {
pageLayout = "permission";
$("#pageEditContentContainer").hide(); $("#pageEditContentContainer").hide();
$("#pageEditExtensionContainer").hide(); $("#pageEditExtensionContainer").hide();
$("#pageEditPositionContainer").hide(); $("#pageEditPositionContainer").hide();

View File

@ -35,30 +35,33 @@
<?php echo template::button('pageEditContentButton', [ <?php echo template::button('pageEditContentButton', [
'value' => 'Contenu', 'value' => 'Contenu',
'class' => 'buttonTab', 'class' => 'buttonTab',
'href' => helper::baseUrl() . 'page/register/content/' . $this->geturl(2) //'href' => helper::baseUrl() . 'page/register/content/' . $this->geturl(2)
]); ?> ]); ?>
<?php echo template::button('pageEditPositionButton', [ <?php echo template::button('pageEditPositionButton', [
'value' => 'Menu', 'value' => 'Menu',
'class' => 'buttonTab', 'class' => 'buttonTab',
'href' => helper::baseUrl() . 'page/register/position/' . $this->geturl(2) //'href' => helper::baseUrl() . 'page/register/position/' . $this->geturl(2)
]); ?> ]); ?>
<?php echo template::button('pageEditExtensionButton', [ <?php echo template::button('pageEditExtensionButton', [
'value' => 'Extension', 'value' => 'Extension',
'class' => 'buttonTab', 'class' => 'buttonTab',
'href' => helper::baseUrl() . 'page/register/extension/' . $this->geturl(2) //'href' => helper::baseUrl() . 'page/register/extension/' . $this->geturl(2)
]); ?> ]); ?>
<?php echo template::button('pageEditLayoutButton', [ <?php echo template::button('pageEditLayoutButton', [
'value' => 'Mise en page', 'value' => 'Mise en page',
'class' => 'buttonTab', 'class' => 'buttonTab',
'href' => helper::baseUrl() . 'page/register/layout/' . $this->geturl(2) //'href' => helper::baseUrl() . 'page/register/layout/' . $this->geturl(2)
]); ?> ]); ?>
<?php echo template::button('pageEditPermissionButton', [ <?php echo template::button('pageEditPermissionButton', [
'value' => 'Permission', 'value' => 'Permission',
'class' => 'buttonTab', 'class' => 'buttonTab',
'href' => helper::baseUrl() . 'page/register/permission/' . $this->geturl(2) //'href' => helper::baseUrl() . 'page/register/permission/' . $this->geturl(2)
]); ?> ]); ?>
</div> </div>
<!-- Champ caché pour transmettre l'onglet-->
<?php echo template::hidden('containerSelected'); ?>
<div id="pageEditContentContainer" class="tabContent"> <div id="pageEditContentContainer" class="tabContent">
<div class="row"> <div class="row">
<div class="col12"> <div class="col12">

View File

@ -151,9 +151,9 @@ class user extends common
$userMail, $userMail,
'Compte créé sur ' . $this->getData(['config', 'title']), 'Compte créé sur ' . $this->getData(['config', 'title']),
'Bonjour <strong>' . $userFirstname . ' ' . $userLastname . '</strong>,<br><br>' . 'Bonjour <strong>' . $userFirstname . ' ' . $userLastname . '</strong>,<br><br>' .
'Un administrateur vous a créé un compte sur le site ' . $this->getData(['config', 'title']) . '. Vous trouverez ci-dessous les détails de votre compte.<br><br>' . 'Un administrateur vous a créé un compte sur le site ' . $this->getData(['config', 'title']) . '. Vous trouverez ci-dessous les détails de votre compte.<br><br>' .
'<strong>Identifiant du compte :</strong> ' . $this->getInput('userAddId') . '<br>' . '<strong>Identifiant du compte :</strong> ' . $this->getInput('userAddId') . '<br>' .
'<small>Nous ne conservons pas les mots de passe, en conséquence nous vous conseillons de conserver ce message tant que vous ne vous êtes pas connecté. Vous pourrez modifier votre mot de passe après votre première connexion.</small>', '<small>Nous ne conservons pas les mots de passe, en conséquence nous vous conseillons de conserver ce message tant que vous ne vous êtes pas connecté. Vous pourrez modifier votre mot de passe après votre première connexion.</small>',
null, null,
$this->getData(['config', 'smtp', 'from']) $this->getData(['config', 'smtp', 'from'])
); );
@ -284,7 +284,6 @@ class user extends common
'notification' => sprintf($count > 1 ? $notification . 's' : $notification, $count), 'notification' => sprintf($count > 1 ? $notification . 's' : $notification, $count),
'state' => $success 'state' => $success
]); ]);
} }
// Liste des groupes et des profils // Liste des groupes et des profils
@ -367,7 +366,6 @@ class user extends common
$this->getData(['user', $userId, 'lastname']), $this->getData(['user', $userId, 'lastname']),
$this->getData(['user', $userId, 'tags']), $this->getData(['user', $userId, 'tags']),
]; ];
} }
} }
@ -409,7 +407,7 @@ class user extends common
$this->getData(['user', $this->getUrl(2)]) === null $this->getData(['user', $this->getUrl(2)]) === null
// Droit d'édition // Droit d'édition
and ( and (
// Impossible de s'auto-éditer // Impossible de s'auto-éditer
($this->getUser('id') === $this->getUrl(2) ($this->getUser('id') === $this->getUrl(2)
and $this->getUrl('group') <= self::GROUP_VISITOR and $this->getUrl('group') <= self::GROUP_VISITOR
) )
@ -571,33 +569,34 @@ class user extends common
public function forgot() public function forgot()
{ {
// Soumission du formulaire // Soumission du formulaire
if ( if ($this->isPost()) {
$this->isPost()
) {
$userId = $this->getInput('userForgotId', helper::FILTER_ID, true); $userId = $this->getInput('userForgotId', helper::FILTER_ID, true);
$sent = false; $sent = false;
if ($this->getData(['user', $userId])) { if ($this->getData(['user', $userId])) {
// Enregistre la date de la demande dans le compte utilisateur // Génère une clé unique avec timestamp et partie aléatoire
$this->setData(['user', $userId, 'forgot', time()]); $timestamp = time(); // Timestamp actuel
// Crée un id unique pour la réinitialisation $randomPart = bin2hex(random_bytes(8)); // Partie aléatoire (16 caractères hexadécimaux)
$uniqId = md5(json_encode($this->getData(['user', $userId, 'forgot']))); $uniqId = $timestamp . '_' . $randomPart; // Combine les deux
// Enregistre la clé unique dans le compte utilisateur
$this->setData(['user', $userId, 'forgot', $uniqId]);
// Envoi le mail // Envoi le mail
$sent = $this->sendMail( $sent = $this->sendMail(
$this->getData(['user', $userId, 'mail']), $this->getData(['user', $userId, 'mail']),
'Réinitialisation de votre mot de passe', 'Réinitialisation de votre mot de passe',
'Bonjour <strong>' . $this->getData(['user', $userId, 'firstname']) . ' ' . $this->getData(['user', $userId, 'lastname']) . '</strong>,<br><br>' . 'Bonjour <strong>' . $this->getData(['user', $userId, 'firstname']) . ' ' . $this->getData(['user', $userId, 'lastname']) . '</strong>,<br><br>' .
'Vous avez demandé à changer le mot de passe lié à votre compte. Vous trouverez ci-dessous un lien vous permettant de modifier celui-ci.<br><br>' . 'Vous avez demandé à changer le mot de passe lié à votre compte. Vous trouverez ci-dessous un lien vous permettant de modifier celui-ci.<br><br>' .
'<a href="' . helper::baseUrl() . 'user/reset/' . $userId . '/' . $uniqId . '" target="_blank">' . helper::baseUrl() . 'user/reset/' . $userId . '/' . $uniqId . '</a><br><br>' . '<a href="' . helper::baseUrl() . 'user/reset/' . $userId . '/' . $uniqId . '" target="_blank">' . helper::baseUrl() . 'user/reset/' . $userId . '/' . $uniqId . '</a><br><br>' .
'<small>Si nous n\'avez pas demandé à réinitialiser votre mot de passe, veuillez ignorer ce mail.</small>', '<small>Si nous n\'avez pas demandé à réinitialiser votre mot de passe, veuillez ignorer ce mail.</small>',
null, null,
$this->getData(['config', 'smtp', 'from']) $this->getData(['config', 'smtp', 'from'])
); );
} }
// Valeurs en sortie // Valeurs en sortie
$this->addOutput([ $this->addOutput([
'notification' => $sent ? helper::translate('Un mail a été envoyé pour confirmer la réinitialisation') : helper::translate('Impossible de réinitialiser le mot de passe de ce compte !'), 'notification' => $sent === true ? helper::translate('Un mail a été envoyé pour confirmer la réinitialisation') : helper::translate('Le mail de réinitialisation ne peut pas être envoyé, contactez l\'administrateur'),
'state' => ($sent === true ? true : false), 'state' => ($sent === true ? true : false),
'redirect' => helper::baseUrl() 'redirect' => helper::baseUrl()
]); ]);
@ -680,18 +679,19 @@ class user extends common
continue; continue;
} }
// Formatage de la liste // Formatage de la liste
self::$users[] = [ self::$users[] = [
//$userId, //$userId,
sprintf('%s %s',$userLastNames, $this->getData(['user', $userId, 'firstname'])), sprintf('%s %s', $userLastNames, $this->getData(['user', $userId, 'firstname'])),
helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])]), helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])]),
empty($this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name'])) empty($this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']))
? helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])]) ? helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])])
: $this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']), : $this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']),
$this->getData(['user', $userId, 'tags']), $this->getData(['user', $userId, 'tags']),
helper::dateUTF8('%d/%m/%Y', $this->getData(['user', $userId, 'accessTimer']), self::$i18nUI), is_null($this->getData(['user', $userId, 'accessTimer']))
? 'Jamais'
: $this->getData(['user', $userId, 'accessTimer']),
//helper::dateUTF8('%d/%m/%Y', $this->getData(['user', $userId, 'accessTimer']), self::$i18nUI),
//helper::dateUTF8('%H:%M', $this->getData(['user', $userId, 'accessTimer']), self::$i18nUI), //helper::dateUTF8('%H:%M', $this->getData(['user', $userId, 'accessTimer']), self::$i18nUI),
template::button('userEdit' . $userId, [ template::button('userEdit' . $userId, [
'href' => helper::baseUrl() . 'user/edit/' . $userId, 'href' => helper::baseUrl() . 'user/edit/' . $userId,
@ -705,7 +705,6 @@ class user extends common
'help' => 'Supprimer' 'help' => 'Supprimer'
]) ])
]; ];
} }
} }
@ -1352,7 +1351,7 @@ class user extends common
$this->getData(['user', $userId, 'mail']), $this->getData(['user', $userId, 'mail']),
'Validation de la connexion à votre compte', 'Validation de la connexion à votre compte',
'<p>Clé de validation à saisir dans le formulaire de connexion :</p>' . '<p>Clé de validation à saisir dans le formulaire de connexion :</p>' .
'<h1><center>' . $keyByMail . '</center></h1>', '<h1><center>' . $keyByMail . '</center></h1>',
null, null,
$this->getData(['config', 'smtp', 'from']) $this->getData(['config', 'smtp', 'from'])
); );
@ -1474,7 +1473,7 @@ class user extends common
$inputKey = $this->getInput('userAuthKey', helper::FILTER_INT); $inputKey = $this->getInput('userAuthKey', helper::FILTER_INT);
// Redirection // Redirection
$pageId = $this->getUrl(2); $pageId = $this->getUrl(2);
$redirect = $pageId? helper::baseUrl() . $pageId : helper::baseUrl() ; $redirect = $pageId ? helper::baseUrl() . $pageId : helper::baseUrl();
if ( if (
// La clé est valide ou le message n'ayant pas été expédié, la double authentification est désactivée // La clé est valide ou le message n'ayant pas été expédié, la double authentification est désactivée
$targetKey === $inputKey || $this->getData(['config', 'connect', 'mailAuth', 0]) === 0 $targetKey === $inputKey || $this->getData(['config', 'connect', 'mailAuth', 0]) === 0
@ -1555,44 +1554,44 @@ class user extends common
if ( if (
// L'utilisateur n'existe pas // L'utilisateur n'existe pas
$this->getData(['user', $this->getUrl(2)]) === null $this->getData(['user', $this->getUrl(2)]) === null
// Lien de réinitialisation trop vieux // Lien de réinitialisation trop vieux (24 heures)
or $this->getData(['user', $this->getUrl(2), 'forgot']) + 86400 < time() or $this->getData(['user', $this->getUrl(2), 'forgot']) === null
// Id unique incorrecte or (int) explode('_', $this->getData(['user', $this->getUrl(2), 'forgot']))[0] + 86400 < time()
or $this->getUrl(3) !== md5(json_encode($this->getData(['user', $this->getUrl(2), 'forgot']))) // Clé unique incorrecte
or $this->getUrl(3) !== $this->getData(['user', $this->getUrl(2), 'forgot'])
) { ) {
$this->saveLog( $this->saveLog(
' Erreur de réinitialisation de mot de passe ' . $this->getUrl(2) . ' Erreur de réinitialisation de mot de passe ' . $this->getUrl(2) .
' Compte : ' . $this->getData(['user', $this->getUrl(2)]) . ' Compte : ' . $this->getData(['user', $this->getUrl(2)]) .
' Temps : ' . $this->getData(['user', $this->getUrl(2), 'forgot']) + 86400 < time() . ' Temps : ' . ($this->getData(['user', $this->getUrl(2), 'forgot']) === null ? 'Clé manquante' : ((int) explode('_', $this->getData(['user', $this->getUrl(2), 'forgot']))[0] + 86400 < time() ? 'Temps dépassé' : 'Temps valide')) .
' Clé : ' . $this->getUrl(3) !== md5(json_encode($this->getData(['user', $this->getUrl(2), 'forgot']))) ' Clé : ' . ($this->getUrl(3) !== $this->getData(['user', $this->getUrl(2), 'forgot']) ? 'Clé invalide' : 'Clé valide')
); );
// Message d'erreur en cas de problème de réinitialisation de mot de passe // Message d'erreur en cas de problème de réinitialisation de mot de passe
$message = $this->getData(['user', $this->getUrl(2)]) === null $message = $this->getData(['user', $this->getUrl(2)]) === null
? ' Utilisateur inconnu ' ? ' Utilisateur inconnu '
: ''; : '';
$message = $this->getData(['user', $this->getUrl(2), 'forgot']) + 86400 < time() $message = $this->getData(['user', $this->getUrl(2), 'forgot']) === null
? ' Clé manquante '
: $message;
$message = (int) explode('_', $this->getData(['user', $this->getUrl(2), 'forgot']))[0] + 86400 < time()
? ' Temps dépassé ' ? ' Temps dépassé '
: $message; : $message;
$message = $this->getUrl(3) !== md5(json_encode($this->getData(['user', $this->getUrl(2)]))) $message = $this->getUrl(3) !== $this->getData(['user', $this->getUrl(2), 'forgot'])
? ' Clé invalide ' ? ' Clé invalide '
: $message; : $message;
// Valeurs en sortie // Valeurs en sortie
$this->addOutput([ $this->addOutput([
'redirect' => helper::baseurl(), 'redirect' => helper::baseurl(),
'notification' => helper::translate('Impossible de réinitialiser le mot de passe de ce compte !') . $message, 'notification' => helper::translate('Impossible de réinitialiser le mot de passe de ce compte !') . $message,
'state' => false 'state' => false
//'access' => false
]); ]);
} }
// Accès autorisé // Accès autorisé
else { else {
// Soumission du formulaire // Soumission du formulaire
if ( if ($this->isPost()) {
// Tous les users peuvent réinitialiser
// $this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
$this->isPost()
) {
// Double vérification pour le mot de passe // Double vérification pour le mot de passe
if ($this->getInput('userResetNewPassword')) { if ($this->getInput('userResetNewPassword')) {
// La confirmation ne correspond pas au mot de passe // La confirmation ne correspond pas au mot de passe
@ -1691,8 +1690,8 @@ class user extends common
$item['prenom'], $item['prenom'],
self::$groups[$item['groupe']], self::$groups[$item['groupe']],
empty($this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name'])) empty($this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']))
? helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])]) ? helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])])
: $this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']), : $this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']),
$item['prenom'], $item['prenom'],
helper::filter($item['email'], helper::FILTER_MAIL), helper::filter($item['email'], helper::FILTER_MAIL),
$item['tags'], $item['tags'],
@ -1736,9 +1735,9 @@ class user extends common
$item['email'], $item['email'],
'Compte créé sur ' . $this->getData(['config', 'title']), 'Compte créé sur ' . $this->getData(['config', 'title']),
'Bonjour <strong>' . $item['prenom'] . ' ' . $item['nom'] . '</strong>,<br><br>' . 'Bonjour <strong>' . $item['prenom'] . ' ' . $item['nom'] . '</strong>,<br><br>' .
'Un administrateur vous a créé un compte sur le site ' . $this->getData(['config', 'title']) . '. Vous trouverez ci-dessous les détails de votre compte.<br><br>' . 'Un administrateur vous a créé un compte sur le site ' . $this->getData(['config', 'title']) . '. Vous trouverez ci-dessous les détails de votre compte.<br><br>' .
'<strong>Identifiant du compte :</strong> ' . $userId . '<br>' . '<strong>Identifiant du compte :</strong> ' . $userId . '<br>' .
'<small>Un mot de passe provisoire vous été attribué, à la première connexion cliquez sur Mot de passe Oublié.</small>', '<small>Un mot de passe provisoire vous été attribué, à la première connexion cliquez sur Mot de passe Oublié.</small>',
null, null,
$this->getData(['config', 'smtp', 'from']) $this->getData(['config', 'smtp', 'from'])
); );
@ -1754,8 +1753,8 @@ class user extends common
$item['prenom'], $item['prenom'],
self::$groups[$item['groupe']], self::$groups[$item['groupe']],
empty($this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name'])) empty($this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']))
? helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])]) ? helper::translate(self::$groups[(int) $this->getData(['user', $userId, 'group'])])
: $this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']), : $this->getData(['profil', $this->getData(['user', $userId, 'group']), $this->getData(['user', $userId, 'profil']), 'name']),
$item['prenom'], $item['prenom'],
$item['email'], $item['email'],
$item['tags'], $item['tags'],
@ -1763,7 +1762,6 @@ class user extends common
]; ];
} }
} }
} }
// Sauvegarde la base manuellement // Sauvegarde la base manuellement
$this->saveDB('user'); $this->saveDB('user');
@ -1805,7 +1803,6 @@ class user extends common
readfile($path . $file); readfile($path . $file);
exit(); exit();
} }
} }
public function tag() public function tag()
@ -1848,7 +1845,6 @@ class user extends common
'notification' => sprintf($count > 1 ? $notification . 's' : $notification, $count), 'notification' => sprintf($count > 1 ? $notification . 's' : $notification, $count),
'state' => $success 'state' => $success
]); ]);
} }
@ -1932,7 +1928,6 @@ class user extends common
$this->getData(['user', $userId, 'lastname']), $this->getData(['user', $userId, 'lastname']),
$this->getData(['user', $userId, 'tags']), $this->getData(['user', $userId, 'tags']),
]; ];
} }
} }
@ -1953,7 +1948,6 @@ class user extends common
'datatables' 'datatables'
] ]
]); ]);
} }
/** /**
@ -1987,5 +1981,4 @@ class user extends common
closedir($dh); closedir($dh);
return $subdirs; return $subdirs;
} }
}
}

View File

@ -15,4 +15,14 @@
/** NE PAS EFFACER /** NE PAS EFFACER
* admin.css * admin.css
*/ */
/** Hide the timestamp column in the user list
*/
tbody td:nth-child(5) {
color: transparent; /* Masquer le texte par défaut */
}
tbody td.visible-text {
color: inherit; /* Rétablir la couleur du texte */
}

View File

@ -31,6 +31,20 @@ $(document).ready((function () {
stateSave: true, stateSave: true,
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "Tout"]], "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "Tout"]],
"columnDefs": [ "columnDefs": [
{
target: 4,
type: 'num', // Utilisez 'num' pour le tri
render: function (data) {
// Si data est un nombre, formatez-le en date
if (typeof data === 'number' || !isNaN(data)) {
return moment(Number(data) * 1000).format('DD/MM/YYYY HH:mm');
} else {
return data; // Sinon, affichez le texte tel quel
}
},
orderable: false,
searchable: false
},
{ {
target: 5, target: 5,
orderable: false, orderable: false,
@ -43,4 +57,15 @@ $(document).ready((function () {
} }
] ]
}); });
// Injecter la règle CSS pour la colonne cible
$('<style>')
.prop('type', 'text/css')
.html(`
table.dataTable tbody td:nth-child(5) {
color: inherit !important; /* Rétablir la couleur du texte */
}
`)
.appendTo('head');
})); }));

View File

@ -68,4 +68,4 @@
</div> </div>
</div> </div>
<?php echo template::formClose(); ?> <?php echo template::formClose(); ?>
<?php echo template::table([3, 2, 2, 2, 2, 1, 1], user::$users, ['Nom', 'Groupe', 'Profil', 'Étiquettes', 'Date dernière vue', '', ''], ['id' => 'dataTables']); ?> <?php echo template::table([3, 2, 2, 1, 3, 1, 1], user::$users, ['Nom', 'Groupe', 'Profil', 'Étiquettes', 'Dernière connexion', '', ''], ['id' => 'dataTables'], ['name','group','profile','tag','data-timestamp','edit','delete']); ?>

File diff suppressed because one or more lines are too long

BIN
core/vendor/zwiico/png/error.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB