Compare commits

...

87 Commits

Author SHA1 Message Date
Fred Tempez 6c8d9097f6 Readme version 2024-05-20 14:15:03 +02:00
Fred Tempez b0814d50dc 1.10.03 Workshop Tri des espaces par titre 2024-05-18 18:47:06 +02:00
Fred Tempez a7a2424d93 1.10.02 2024-05-16 09:26:23 +02:00
Fred Tempez 43b15987d6 Suivi Zwii 13.3.02 2024-05-16 09:25:40 +02:00
Fred Tempez e100a580ad Mise à jour des modules 1.10.01 2024-05-08 18:47:43 +02:00
Fred Tempez 397bdee655 Merge branch '1902-isole-les-commandes-sur-les-espaces' 2024-04-23 18:13:06 +02:00
Fred Tempez 78b2d87ec1 supprime sync.db ! 2024-04-23 18:09:55 +02:00
Fred Tempez 8dedb39a33 Déplace les boutons de gestion des utilisateurs dans la liste des espaces. 2024-04-23 18:09:28 +02:00
Fred Tempez 7cee16389f commentaire 2024-04-23 17:25:50 +02:00
Fred Tempez 04b2877c48 1.10.00 2024-04-23 14:58:01 +02:00
Fred Tempez f6c7e5f954 Dans router self devient common
Nouveau routage en cas de changement d'espace en évitant une 404
2024-04-23 14:57:10 +02:00
Fred Tempez b5ea22021b redirige vers la page ouverte 2024-04-23 11:54:50 +02:00
Fred Tempez 3ee1398e2f supprime un commentaire 2024-04-23 11:54:32 +02:00
Fred Tempez cfb07b81d5 Id non fourni 2024-04-22 21:46:41 +02:00
Fred Tempez 0da23149db 2.0.0 corrige le warning blog vide + transmet tn paramètre sécurisant l'édition des espaces dans plusieurs onglets 2024-04-22 15:40:35 +02:00
Fred Tempez 1322cb4eb0 Revert "section par main"
This reverts commit 271ee347a8.
2024-04-22 14:19:47 +02:00
Fred Tempez 167ad06dde Revert "section par main"
This reverts commit 271ee347a8.
2024-04-22 14:16:12 +02:00
Fred Tempez 271ee347a8 section par main 2024-04-22 10:56:49 +02:00
Fred Tempez 04a6d86999 1.9.01 supprime la balise section 2024-04-21 15:54:15 +02:00
Fred Tempez 05e6ff8f9b init 2024-04-18 14:52:13 +02:00
Fred Tempez 6e53ca8766 readme 2024-04-18 10:37:56 +02:00
Fred Tempez dda93cf3d3 Merge branch 'master' of https://forge.chapril.org/fredtempez/ZwiiLMS 2024-04-18 10:37:19 +02:00
Fred Tempez 075e4afa1c changes 2024-04-18 10:37:11 +02:00
Fred Tempez fd144d55f0 changes 2024-04-18 10:32:27 +02:00
Fred Tempez b595120227 1.9 Désincription en masse de la plateforme 2024-04-18 10:27:33 +02:00
Fred Tempez b0b3b34bde 1.8.01 alignement de boutons 2024-04-17 16:42:03 +02:00
Fred Tempez 2f592e2818 1.8.01
Corrige :
- Mauvais initialisation d'un profil
Modifie :
- Ajoute des effets de sélection dans la gestion des profils des espaces (add and edit)
2024-04-17 10:53:02 +02:00
Fred Tempez 8c9bc40a02 1.8.01
Corrige :
 - tableau de stats vides affichant une erreur
 - correction relative au rapport d'un participant
Nouvelle fonctionnalité :
- Bouton de réinitialisation d'un espace, efface les historiques et les inscriptions, les désinscriptions des participants et par autorité ne suppriment plus les historiques.
2024-04-17 10:33:00 +02:00
Fred Tempez 37f77b3d50 readme 2024-04-13 10:13:48 +02:00
Fred Tempez a5130e1d9f readme 2024-04-13 10:13:13 +02:00
Fred Tempez 256da35d53 1.8.00 user report in csv 2024-04-13 10:07:47 +02:00
Fred Tempez bb93b1b313 User report ok 2024-04-13 10:05:32 +02:00
Fred Tempez 195ed682f6 Merge branch 'master' into 1.8.00-report-csv 2024-04-12 22:10:38 +02:00
Fred Tempez ae71b9649d Clic dans le TR active la case à cocher. 2024-04-12 22:09:37 +02:00
Fred Tempez 71418548e7 getReport utilisé dans la liste des users d'un courseId 2024-04-12 22:04:24 +02:00
Fred Tempez 03c7e0a7fa update.inc.php mise à jour ok 2024-04-12 21:22:57 +02:00
Fred Tempez 6bc8636692 Update json to csv ok 2024-04-12 09:52:39 +02:00
Fred Tempez c0d14596a7 fonction update à tester 2024-04-11 15:46:42 +02:00
Fred Tempez 6a72676c7c update to test 2024-04-11 07:58:26 +02:00
Fred Tempez 44c4997436 upodaite to 1.8 WIP 2024-04-11 07:55:48 +02:00
Fred Tempez cce73886a2 UsersHistory devient UsersReport 2024-04-11 07:46:27 +02:00
Fred Tempez b9733d7391 User History devient user report 2024-04-11 07:44:43 +02:00
Fred Tempez 56ff0580a1 création du CS sans courseID 2024-04-10 18:59:41 +02:00
Fred Tempez 5b9f86fb38 Code à mettre dans une fonction 2024-04-10 18:58:04 +02:00
Fred Tempez d43a78d307 1.7.09 icones de tout sélectionner ou tout déselectionner 2024-04-10 18:41:39 +02:00
Fred Tempez deedb002e8 1.8.00 report csv 2024-04-10 14:31:29 +02:00
Fred Tempez 6d7c2f725d secure_file_put_contents stocke les données brutes 2024-04-10 11:56:31 +02:00
Fred Tempez 5ede9b71c2 1709 supprime la variable sessionId 2024-04-10 08:33:53 +02:00
Fred Tempez 04f4c7be6d 1.7.09 bug double slash initDB 2024-04-10 08:32:08 +02:00
Fred Tempez 0c94b2f546 erreur secure_file_put_contents 2024-04-09 18:58:22 +02:00
Fred Tempez 8b72ae01dc Revert "DOuble slashs"
This reverts commit 0934bf847d.
2024-04-09 18:51:11 +02:00
Fred Tempez 1ca77b89ce Merge branch 'master' of https://forge.chapril.org/fredtempez/ZwiiLMS 2024-04-09 18:42:06 +02:00
Fred Tempez 0934bf847d DOuble slashs 2024-04-09 18:40:52 +02:00
Fred Tempez 2a152a9a1d version 2024-04-09 18:38:50 +02:00
Fred Tempez bc8fbc17b8 numéro de version² 2024-04-09 18:32:54 +02:00
Fred Tempez a8635f0c8a supprime target new dans course manage 2024-04-09 18:32:05 +02:00
Fred Tempez ca875f9f05 Supprime un echo de test. 2024-04-09 18:29:05 +02:00
Fred Tempez b4258fe496 Supprimer le target blank 2024-04-09 18:20:54 +02:00
Fred Tempez 509c95a680 double fonction 2024-04-09 18:17:13 +02:00
Fred Tempez 2027c5918f Merge commit '0f55df8d31a7093f83c2ee4510a1d27bb9a087ac' 2024-04-09 18:14:16 +02:00
Fred Tempez 3593e853d8 DOuble slashs 2024-04-09 18:07:41 +02:00
Fred Tempez cb13d2b0c9 session_id WIP 2024-04-09 15:09:02 +02:00
Fred Tempez 0f55df8d31 En test 2024-04-09 14:33:01 +02:00
Fred Tempez 939cb8d53f 1.7.09 réintalle la dernière version correcte 2024-04-09 13:32:25 +02:00
Fred Tempez 730e4ac9c4 1.7.09 reformatage 2024-04-07 18:14:43 +02:00
Fred Tempez d3d96f795a formatage 2024-04-06 09:14:37 +02:00
Fred Tempez e68f58fad1 Merge branch 'master' of https://forge.chapril.org/fredtempez/ZwiiLMS 2024-04-06 09:13:07 +02:00
Fred Tempez 6c0f34ae71 1.7.09 flock sur le fichier principal (PB sous win) 2024-04-06 09:10:52 +02:00
Fred Tempez 9373880239 Détruit le fichier de verrouillage créé par secureFilePutContent 2024-04-05 18:21:09 +02:00
Fred Tempez a35036e0fa Double slashs 2024-04-05 17:54:10 +02:00
Fred Tempez 19246a59c9 déplace les constantes 2024-04-05 17:16:25 +02:00
Fred Tempez 15c4d1edd3 annule secureFilePutContents dans les modules. Non justifié dans la configuration du module 2024-04-05 16:51:03 +02:00
Fred Tempez 24f679d531 1.7.09 fonction secureFilePutContents 2024-04-05 16:33:46 +02:00
Fred Tempez 56f8f03581 readme 2024-04-05 09:22:38 +02:00
Fred Tempez ae1f15e8b8 1.7.09 Formatage 2024-04-05 09:07:38 +02:00
Fred Tempez 7544bb9862 1.7.09 ajoute un temps d'attente 2024-04-05 09:06:42 +02:00
Fred Tempez ebd078848a 1.7.09 durcit le contrôle d'enregistrement un verrou 2024-04-05 09:06:26 +02:00
Fred Tempez e8e4f98be0 1.7.09 json db 2024-04-03 12:52:49 +02:00
Fred Tempez c8c74d9be3 1.7.09 supprimer un test dans jsondb 2024-04-03 12:50:42 +02:00
Fred Tempez 63541cf83a 1.7.08 worhsop liend e désinscription dans les options 2024-04-02 18:25:39 +02:00
Fred Tempez 1cb54d46b1 Revert "1.7.08 Le lien de désinscription par l'utilisateur ne supprime plus l'historique."
This reverts commit 84df59c52b.
2024-04-02 18:12:24 +02:00
Fred Tempez cf3936b7c0 Merge branch 'master' of https://forge.chapril.org/fredtempez/ZwiiLMS 2024-04-02 12:54:52 +02:00
Fred Tempez 84df59c52b 1.7.08 Le lien de désinscription par l'utilisateur ne supprime plus l'historique. 2024-04-02 12:54:47 +02:00
Fred Tempez c75b71f217 1.7.07 Le lien de désinscription par l'utilisateur ne supprime plus l'historique. 2024-04-02 12:54:19 +02:00
Fred Tempez 269abc5699 Version 1.7.07 2024-03-30 09:17:06 +01:00
Fred Tempez 638ddadb61 jsondb stoppe après une erreur de chargement 2024-03-30 09:16:27 +01:00
Fred Tempez 10f8340e76 Module search 3.1 2024-03-30 09:12:14 +01:00
116 changed files with 1073 additions and 387 deletions

View File

@ -1,4 +1,4 @@
# ZwiiCampus 1.7.06
# ZwiiCampus 1.10.03
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é.
@ -68,6 +68,7 @@ A l'occasion de l'installation d'une version majeure, il est recommandé de réa
[F] module.json Données des modules de pages
[F] theme.css Thème de ce contenu
[F] theme.json Thème de ce contenu
[F] report.csv Rapport de participation
[R] content Dossier des contenus de page
[F] accueil.html Exemple contenu de la page d'accueil
[R] fonts Dossier contenant les fontes installées
@ -84,7 +85,7 @@ A l'occasion de l'installation d'une version majeure, il est recommandé de réa
[F] core.json Configuration du noyau
[F] course.json Données de contenus
[F] custom.css Feuille de style de la personnalisation avancée
[F] enrolment.json Données des inscriptions et des statistiques par contenu
[F] enrolment.json Inscriptions dans les espaces, dernière page vue et timetamp
[F] font.json Descripteur des fontes personnalisées
[F] journal.log Journalisation des activités
[F] language.json Langues de l'interface

View File

@ -121,10 +121,10 @@ class JsonDb extends \Prowebcraft\Dot
} else {
if ($this->config['backup']) {
try {
//todo make backup of database
copy($this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'], $this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'] . '.backup');
} catch (\Exception $e) {
error_log('Erreur de chargement : ' . $e);
exit('Erreur de chargement : ' . $e);
}
}
}
@ -142,25 +142,38 @@ class JsonDb extends \Prowebcraft\Dot
*/
public function save()
{
$v = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
// $v = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT);
$l = strlen($v);
$t = 0;
if ($v === false) {
error_log('Erreur d\'encodage JSON : ' . json_last_error_msg());
exit ('Erreur d\'encodage JSON : ' . json_last_error_msg());
}
while ($t < 5) {
$w = file_put_contents($this->db, $v); // Multi user get a locker
if ($w == $l) {
// Encode les données au format JSON avec les options spécifiées
$encoded_data = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
// Vérifie la longueur de la chaîne JSON encodée
$encoded_length = strlen($encoded_data);
// Initialise le compteur de tentatives
$attempt = 0;
// Tente d'encoder les données en JSON et de les sauvegarder jusqu'à 5 fois en cas d'échec
while ($attempt < 5) {
// Essaye d'écrire les données encodées dans le fichier de base de données
$write_result = file_put_contents($this->db, $encoded_data, LOCK_EX); // Les utilisateurs multiples obtiennent un verrou
// Vérifie si l'écriture a réussi
if ($write_result === $encoded_length) {
// Sort de la boucle si l'écriture a réussi
break;
}
$t++;
}
if ($w !== $l) {
error_log('Erreur d\'écriture, les données n\'ont pas été sauvegardées.');
exit('Erreur d\'écriture, les données n\'ont pas été sauvegardées.');
// Incrémente le compteur de tentatives
$attempt++;
}
// Vérifie si l'écriture a échoué même après plusieurs tentatives
if ($write_result !== $encoded_length) {
// Enregistre un message d'erreur dans le journal des erreurs
error_log('Erreur d\'écriture, les données n\'ont pas été sauvegardées.');
// Affiche un message d'erreur et termine le script
exit('Erreur d\'écriture, les données n\'ont pas été sauvegardées.');
}
}
}

View File

@ -151,7 +151,7 @@ class layout extends common
}
echo '</div>';
}
echo '</main></section>';
echo '</section></main>';
}
/**
@ -1001,7 +1001,7 @@ class layout extends common
// Bouton Ajouter une page
if ($this->getUser('permission', 'page', 'add')) {
$leftItems .= '<li>' . template::ico('plus', [
'href' => helper::baseUrl() . 'page/add',
'href' => helper::baseUrl() . 'page/add/' . self::$siteContent,
'help' => 'Nouvelle page ou barre latérale'
]) . '</li>';
}
@ -1020,7 +1020,7 @@ class layout extends common
// Bouton Editer une page
if ($this->getUser('permission', 'page', 'edit')) {
$leftItems .= '<li>' . template::ico('pencil', [
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0),
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0) . '/' . self::$siteContent,
'help' => 'Éditer la page'
]) . '</li>';
}
@ -1039,7 +1039,7 @@ class layout extends common
$this->getUser('permission', 'page', 'duplicate')
) {
$leftItems .= '<li>' . template::ico('clone', [
'href' => helper::baseUrl() . 'page/duplicate/' . $this->getUrl(0),
'href' => helper::baseUrl() . 'page/duplicate/' . $this->getUrl(0) . '/' . self::$siteContent,
'help' => 'Dupliquer la page'
])
. '</li>';
@ -1049,7 +1049,7 @@ class layout extends common
$this->getUser('permission', 'page', 'delete')
) {
$leftItems .= '<li>' . template::ico('trash', [
'href' => helper::baseUrl() . 'page/delete/' . $this->getUrl(0),
'href' => helper::baseUrl() . 'page/delete/' . $this->getUrl(0) . '/' . self::$siteContent,
'help' => 'Supprimer la page',
'id' => 'pageDelete'
])

View File

@ -15,12 +15,12 @@ class core extends common
}
// Fuseau horaire
self::$timezone = $this->getData(['config', 'timezone']); // Utile pour transmettre le timezone à la classe helper
date_default_timezone_set(self::$timezone);
common::$timezone = $this->getData(['config', 'timezone']); // Utile pour transmettre le timezone à la classe helper
date_default_timezone_set(common::$timezone);
// Supprime les fichiers temporaires
$lastClearTmp = mktime(0, 0, 0);
if ($lastClearTmp > $this->getData(['core', 'lastClearTmp']) + 86400) {
$iterator = new DirectoryIterator(self::TEMP_DIR);
$iterator = new DirectoryIterator(common::TEMP_DIR);
foreach ($iterator as $fileInfos) {
if (
$fileInfos->isFile() &&
@ -43,11 +43,11 @@ class core extends common
and $this->getData(['user']) // Pas de backup pendant l'installation
) {
// Copie des fichier de données
helper::autoBackup(self::BACKUP_DIR, ['backup', 'tmp', 'file']);
helper::autoBackup(common::BACKUP_DIR, ['backup', 'tmp', 'file']);
// Date du dernier backup
$this->setData(['core', 'lastBackup', $lastBackup]);
// Supprime les backups de plus de 30 jours
$iterator = new DirectoryIterator(self::BACKUP_DIR);
$iterator = new DirectoryIterator(common::BACKUP_DIR);
foreach ($iterator as $fileInfos) {
if (
$fileInfos->isFile()
@ -60,23 +60,23 @@ class core extends common
}
// Crée le fichier de personnalisation avancée
if (file_exists(self::DATA_DIR . 'custom.css') === false) {
file_put_contents(self::DATA_DIR . 'custom.css', ('core/module/theme/resource/custom.css'));
chmod(self::DATA_DIR . 'custom.css', 0755);
if (file_exists(common::DATA_DIR . 'custom.css') === false) {
file_put_contents(common::DATA_DIR . 'custom.css', ('core/module/theme/resource/custom.css'));
chmod(common::DATA_DIR . 'custom.css', 0755);
}
// Crée le fichier de personnalisation
if (file_exists(self::DATA_DIR . self::$siteContent . '/theme.css') === false) {
file_put_contents(self::DATA_DIR . self::$siteContent . '/theme.css', '');
chmod(self::DATA_DIR . self::$siteContent . '/theme.css', 0755);
if (file_exists(common::DATA_DIR . common::$siteContent . '/theme.css') === false) {
file_put_contents(common::DATA_DIR . common::$siteContent . '/theme.css', '');
chmod(common::DATA_DIR . common::$siteContent . '/theme.css', 0755);
}
// Crée le fichier de personnalisation de l'administration
if (file_exists(self::DATA_DIR . 'admin.css') === false) {
file_put_contents(self::DATA_DIR . 'admin.css', '');
chmod(self::DATA_DIR . 'admin.css', 0755);
if (file_exists(common::DATA_DIR . 'admin.css') === false) {
file_put_contents(common::DATA_DIR . 'admin.css', '');
chmod(common::DATA_DIR . 'admin.css', 0755);
}
// Check la version rafraichissement du theme
$cssVersion = preg_split('/\*+/', file_get_contents(self::DATA_DIR . self::$siteContent . '/theme.css'));
$cssVersion = preg_split('/\*+/', file_get_contents(common::DATA_DIR . common::$siteContent . '/theme.css'));
if (empty($cssVersion[1]) or $cssVersion[1] !== md5(json_encode($this->getData(['theme'])))) {
// Version
$css = '/*' . md5(json_encode($this->getData(['theme']))) . '*/';
@ -92,7 +92,7 @@ class core extends common
// Fonts disponibles
$fontsAvailable['files'] = $this->getData(['font', 'files']);
$fontsAvailable['imported'] = $this->getData(['font', 'imported']);
$fontsAvailable['websafe'] = self::$fontsWebSafe;
$fontsAvailable['websafe'] = common::$fontsWebSafe;
// Fontes installées
$fonts = [
@ -273,7 +273,7 @@ class core extends common
$css .= '#footerCopyright{text-align:' . $this->getData(['theme', 'footer', 'copyrightAlign']) . '}';
// Enregistre la personnalisation
file_put_contents(self::DATA_DIR . self::$siteContent . '/theme.css', $css);
file_put_contents(common::DATA_DIR . common::$siteContent . '/theme.css', $css);
// Effacer le cache pour tenir compte de la couleur de fond TinyMCE
header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
@ -284,7 +284,7 @@ class core extends common
}
// Check la version rafraichissement du theme admin
$cssVersion = preg_split('/\*+/', file_get_contents(self::DATA_DIR . 'admin.css'));
$cssVersion = preg_split('/\*+/', file_get_contents(common::DATA_DIR . 'admin.css'));
if (empty($cssVersion[1]) or $cssVersion[1] !== md5(json_encode($this->getData(['admin'])))) {
// Version
@ -293,7 +293,7 @@ class core extends common
// Fonts disponibles
$fontsAvailable['files'] = $this->getData(['font', 'files']);
$fontsAvailable['imported'] = $this->getData(['font', 'imported']);
$fontsAvailable['websafe'] = self::$fontsWebSafe;
$fontsAvailable['websafe'] = common::$fontsWebSafe;
/**
* Import des polices de caractères
@ -368,7 +368,7 @@ class core extends common
// Bordure du contour TinyMCE
$css .= '.mce-tinymce{border: 1px solid ' . $this->getData(['admin', 'borderBlockColor']) . '!important;}';
// Enregistre la personnalisation
file_put_contents(self::DATA_DIR . 'admin.css', $css);
file_put_contents(common::DATA_DIR . 'admin.css', $css);
}
}
/**
@ -384,8 +384,8 @@ class core extends common
require 'core/module/' . $classPath;
}
// Module
elseif (is_readable(self::MODULE_DIR . $classPath)) {
require self::MODULE_DIR . $classPath;
elseif (is_readable(common::MODULE_DIR . $classPath)) {
require common::MODULE_DIR . $classPath;
}
// Librairie
elseif (is_readable('core/vendor/' . $classPath)) {
@ -414,22 +414,23 @@ class core extends common
// Sauvegarde la dernière page visitée par l'utilisateur connecté et enregistre l'historique des consultations
if (
$this->getUser('id')
&& self::$siteContent !== 'home'
&& common::$siteContent !== 'home'
&& in_array($this->getUrl(0), array_keys($this->getData(['page'])))
// Le userId n'est pas celui d'un admis ni le prof du contenu
&& (
$this->getUser('group') < self::GROUP_ADMIN
|| $this->getUser('id') !== $this->getData(['course', self::$siteContent, 'author'])
$this->getUser('group') < common::GROUP_ADMIN
|| $this->getUser('id') !== $this->getData(['course', common::$siteContent, 'author'])
)
) {
// Stocke l'historique des pages vues
$data = is_array($this->getData(['enrolment', self::$siteContent, $this->getUser('id'), 'history', $this->getUrl(0)]))
? array_merge([time()], $this->getData(['enrolment', self::$siteContent, $this->getUser('id'), 'history', $this->getUrl(0)]))
: [time()];
$this->setData(['enrolment', self::$siteContent, $this->getUser('id'), 'history', $this->getUrl(0), $data]);
// Stocke la dernière page vue et sa date de consultation
$this->setData(['enrolment', self::$siteContent, $this->getUser('id'), 'lastPageView', $this->getUrl(0)]);
$this->setData(['enrolment', self::$siteContent, $this->getUser('id'), 'datePageView', time()]);
$this->setData(['enrolment', common::$siteContent, $this->getUser('id'), 'lastPageView', $this->getUrl(0)]);
$this->setData(['enrolment', common::$siteContent, $this->getUser('id'), 'datePageView', time()]);
// Stocke le rapport en CSV
$file = fopen(common::DATA_DIR . common::$siteContent . '/report.csv', 'a+');
fputcsv($file, [ $this->getUser('id'), $this->getUrl(0) ,time()], ';');
fclose($file);
}
// Journalisation
@ -438,7 +439,7 @@ class core extends common
// Force la déconnexion des membres bannis ou d'une seconde session
if (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
and ($this->getUser('group') === self::GROUP_BANNED
and ($this->getUser('group') === common::GROUP_BANNED
or ($_SESSION['csrf'] !== $this->getData(['user', $this->getUser('id'), 'accessCsrf'])
and $this->getData(['config', 'connect', 'autoDisconnect']) === true)
)
@ -453,7 +454,7 @@ class core extends common
and $this->getUrl(1) !== 'login'
and ($this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
and $this->getUser('group') < self::GROUP_ADMIN
and $this->getUser('group') < common::GROUP_ADMIN
)
)
) {
@ -466,31 +467,11 @@ class core extends common
exit();
}
// Pour éviter une 404 sur une langue étrangère, bascule dans la langue correcte.
if (is_null($this->getData(['page', $this->getUrl(0)]))) {
foreach ($this->getData(['course']) as $key => $value) {;
if (
is_dir(self::DATA_DIR . $key) &&
file_exists(self::DATA_DIR . $key . '/page.json')
) {
$pagesId = json_decode(file_get_contents(self::DATA_DIR . $key . '/page.json'), true);
if (
is_array($pagesId['page']) &&
array_key_exists($this->getUrl(0), $pagesId['page'])
) {
//$_SESSION['ZWII_SITE_CONTENT'] = $key;
header('Refresh:0; url=' . helper::baseUrl() . 'course/swap/' . $key . '/' . $this->getUrl(0));
exit();
}
}
}
}
// Check l'accès à la page
$access = null;
if ($this->getData(['page', $this->getUrl(0)]) !== null) {
if (
$this->getData(['page', $this->getUrl(0), 'group']) === self::GROUP_VISITOR
$this->getData(['page', $this->getUrl(0), 'group']) === common::GROUP_VISITOR
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
// and $this->getUser('group') >= $this->getData(['page', $this->getUrl(0), 'group'])
// Modification qui tient compte du profil de la page
@ -511,7 +492,7 @@ class core extends common
and $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')
) or ($this->getData(['page', $this->getUrl(0), 'disable']) === true
and $this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
and $this->getUser('group') < self::GROUP_EDITOR
and $this->getUser('group') < common::GROUP_EDITOR
)
) {
$access = false;
@ -537,9 +518,9 @@ class core extends common
$this->getUser('id') &&
$userId !== $this->getUser('id') &&
$this->getData(['user', $userId, 'accessUrl']) === $this->getUrl() &&
array_intersect($t, self::$concurrentAccess) &&
//array_intersect($t, self::$accessExclude) !== false &&
time() < $this->getData(['user', $userId, 'accessTimer']) + self::ACCESS_TIMER
array_intersect($t, common::$concurrentAccess) &&
//array_intersect($t, common::$accessExclude) !== false &&
time() < $this->getData(['user', $userId, 'accessTimer']) + common::ACCESS_TIMER
) {
$access = false;
$accessInfo['userName'] = $this->getData(['user', $userId, 'lastname']) . ' ' . $this->getData(['user', $userId, 'firstname']);
@ -576,10 +557,10 @@ class core extends common
$inlineScript[] = $this->getData(['page', $this->getUrl(0), 'js']) === null ? '' : $this->getData(['page', $this->getUrl(0), 'js']);
// Importe le contenu, le CSS et le script des barres
$contentRight = $this->getData(['page', $this->getUrl(0), 'barRight']) ? $this->getPage($this->getData(['page', $this->getUrl(0), 'barRight']), self::$siteContent) : '';
$contentRight = $this->getData(['page', $this->getUrl(0), 'barRight']) ? $this->getPage($this->getData(['page', $this->getUrl(0), 'barRight']), common::$siteContent) : '';
$inlineStyle[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'css']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'css']);
$inlineScript[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'js']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'js']);
$contentLeft = $this->getData(['page', $this->getUrl(0), 'barLeft']) ? $this->getPage($this->getData(['page', $this->getUrl(0), 'barLeft']), self::$siteContent) : '';
$contentLeft = $this->getData(['page', $this->getUrl(0), 'barLeft']) ? $this->getPage($this->getData(['page', $this->getUrl(0), 'barLeft']), common::$siteContent) : '';
$inlineStyle[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'css']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'css']);
$inlineScript[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'js']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'js']);
@ -597,7 +578,7 @@ class core extends common
$this->addOutput([
'title' => $title,
'content' => $this->getPage($this->getUrl(0), self::$siteContent),
'content' => $this->getPage($this->getUrl(0), common::$siteContent),
'metaDescription' => $this->getData(['page', $this->getUrl(0), 'metaDescription']),
'metaTitle' => $this->getData(['page', $this->getUrl(0), 'metaTitle']),
'typeMenu' => $this->getData(['page', $this->getUrl(0), 'typeMenu']),
@ -623,7 +604,7 @@ class core extends common
: $this->getData(['page', $this->getUrl(0), 'metaDescription']);
// Importe le CSS de la page principale
$pageContent = $this->getPage($this->getUrl(0), self::$siteContent);
$pageContent = $this->getPage($this->getUrl(0), common::$siteContent);
$this->addOutput([
'title' => $title,
@ -668,7 +649,7 @@ class core extends common
$output = $module->output;
// Check le groupe de l'utilisateur
if (
($module::$actions[$action] === self::GROUP_VISITOR
($module::$actions[$action] === common::GROUP_VISITOR
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
and $this->getUser('group') >= $module::$actions[$action]
and $this->getUser('permission', $moduleId, $action)
@ -681,10 +662,10 @@ class core extends common
foreach ($_POST as $postId => $postValue) {
if (is_array($postValue)) {
foreach ($postValue as $subPostId => $subPostValue) {
self::$inputBefore[$postId . '_' . $subPostId] = $subPostValue;
common::$inputBefore[$postId . '_' . $subPostId] = $subPostValue;
}
} else {
self::$inputBefore[$postId] = $postValue;
common::$inputBefore[$postId] = $postValue;
}
}
}
@ -724,9 +705,9 @@ class core extends common
// Contenu par vue
elseif ($output['view']) {
// Chemin en fonction d'un module du coeur ou d'un module
$modulePath = in_array($moduleId, self::$coreModuleIds) ? 'core/' : '';
$modulePath = in_array($moduleId, common::$coreModuleIds) ? 'core/' : '';
// CSS
$stylePath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.css';
$stylePath = $modulePath . common::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.css';
if (file_exists($stylePath)) {
$this->addOutput([
'style' => file_get_contents($stylePath)
@ -739,7 +720,7 @@ class core extends common
}
// JS
$scriptPath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.js.php';
$scriptPath = $modulePath . common::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.js.php';
if (file_exists($scriptPath)) {
ob_start();
include $scriptPath;
@ -748,7 +729,7 @@ class core extends common
]);
}
// Vue
$viewPath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.php';
$viewPath = $modulePath . common::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.php';
if (file_exists($viewPath)) {
ob_start();
include $viewPath;
@ -834,14 +815,40 @@ class core extends common
}
}
} elseif ($this->output['content'] === '') {
// Pour éviter une 404, bascule dans l'espace correct si la page existe dans cet espace.
// Parcourir les espaces y compris l'accueil
foreach (array_merge(['home'=> []], $this->getData(['course'])) as $courseId => $value) {;
if (
// l'espace existe
is_dir(common::DATA_DIR . $courseId) &&
file_exists(common::DATA_DIR . $courseId . '/page.json')
) {
// Lire les données des pages
$pagesId = json_decode(file_get_contents(common::DATA_DIR . $courseId . '/page.json'), true);
if (
// La page existe
is_array($pagesId['page']) &&
array_key_exists($this->getUrl(0), $pagesId['page'])
) {
// Basculer
$_SESSION['ZWII_SITE_CONTENT'] = $courseId;
header('Refresh:0; url=' . helper::baseUrl() . $this->getUrl());
exit();
}
}
}
// La page n'existe pas dans les esapces, on génére une erreur 404
http_response_code(404);
if (
// une page est définie dans la configuration mais dans home
$this->getData(['config', 'page404']) !== 'none'
//and $this->getData(['page', $this->getData(['config', 'page404'])])
) {
// Bascule sur l'acccueil et rediriger
$_SESSION['ZWII_SITE_CONTENT'] = 'home';
header('Location:' . helper::baseUrl() . $this->getData(['config', 'page404']));
} else {
// Page par défaut
$this->addOutput([
'title' => 'Page indisponible',
'content' => template::speech('<p>' . helper::translate('La page demandée n\'existe pas ou est introuvable (erreur 404)') . '</p><p><a style="color:inherit" href="javascript:history.back()">'. helper::translate('Retour') . '</a></p>')
@ -867,25 +874,25 @@ class core extends common
}
switch ($this->output['display']) {
// Layout brut
case self::DISPLAY_RAW:
case common::DISPLAY_RAW:
echo $this->output['content'];
break;
// Layout vide
case self::DISPLAY_LAYOUT_BLANK:
case common::DISPLAY_LAYOUT_BLANK:
require 'core/layout/blank.php';
break;
// Affichage en JSON
case self::DISPLAY_JSON:
case common::DISPLAY_JSON:
header('Content-Type: application/json');
echo json_encode($this->output['content']);
break;
// RSS feed
case self::DISPLAY_RSS:
case common::DISPLAY_RSS:
header('Content-type: application/rss+xml; charset=UTF-8');
echo $this->output['content'];
break;
// Layout allégé
case self::DISPLAY_LAYOUT_LIGHT:
case common::DISPLAY_LAYOUT_LIGHT:
ob_start();
require 'core/layout/light.php';
$content = ob_get_clean();
@ -896,7 +903,7 @@ class core extends common
echo $content;
break;
// Layout principal
case self::DISPLAY_LAYOUT_MAIN:
case common::DISPLAY_LAYOUT_MAIN:
ob_start();
require 'core/layout/main.php';
$content = ob_get_clean();

View File

@ -51,7 +51,7 @@ class common
const ACCESS_TIMER = 1800;
// Numéro de version
const ZWII_VERSION = '1.7.06';
const ZWII_VERSION = '1.10.03';
// URL autoupdate
const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/campus-update/raw/branch/master/';
@ -176,6 +176,7 @@ class common
public static $i18nUI = 'fr_FR';
// Langues de contenu
public static $siteContent = 'home';
public static $languages = [
'de' => 'Deutsch',
'en_EN' => 'English',
@ -332,6 +333,7 @@ class common
// Déterminé par la session présente
self::$siteContent = $_SESSION['ZWII_SITE_CONTENT'];
}
// Instanciation de la classe des entrées / sorties
// Les fichiers de configuration
foreach ($this->configFiles as $module => $value) {
@ -342,7 +344,6 @@ class common
$this->initDB($module, self::$siteContent);
}
// Installation fraîche, initialisation de la configuration inexistante
// Nécessaire pour le constructeur
if ($this->user === []) {
@ -447,7 +448,7 @@ class common
}
// Mise à jour des données core
include('core/include/update.inc.php');
include ('core/include/update.inc.php');
}
@ -595,7 +596,7 @@ class common
public function setPage($page, $value, $path)
{
return file_put_contents(self::DATA_DIR . $path . '/content/' . $page . '.html', $value);
return $this->secure_file_put_contents(self::DATA_DIR . $path . '/content/' . $page . '.html', $value);
}
@ -611,13 +612,54 @@ class common
}
/**
* Écrit les données dans un fichier avec plusieurs tentatives d'écriture et verrouillage
*
* @param string $filename Le nom du fichier
* @param array $data Les données à écrire dans le fichier
* @param int $flags Les drapeaux optionnels à passer à la fonction $this->secure_file_put_contents
* @return bool True si l'écriture a réussi, sinon false
*/
function secure_file_put_contents($filename, $data, $flags = 0)
{
// Initialise le compteur de tentatives
$attempts = 0;
// Convertit les données en chaîne de caractères
$serialized_data = serialize($data);
// Vérifie la longueur des données
$data_length = strlen($serialized_data);
// Effectue jusqu'à 5 tentatives d'écriture
while ($attempts < 5) {
// Essaye d'écrire les données dans le fichier avec verrouillage exclusif
$write_result = file_put_contents($filename, $data, LOCK_EX | $flags);
// Vérifie si l'écriture a réussi
if ($write_result !== false && $write_result === $data_length) {
// Sort de la boucle si l'écriture a réussi
return true;
}
// Incrémente le compteur de tentatives
$attempts++;
}
// Échec de l'écriture après plusieurs tentatives
return false;
}
public function initDB($module, $path = '')
{
// Instanciation de la classe des entrées / sorties
// Constructeur JsonDB;
$this->dataFiles[$module] = new \Prowebcraft\JsonDb([
'name' => $module . '.json',
'dir' => self::DATA_DIR . $path . '/',
'dir' => empty($path) ? self::DATA_DIR : self::DATA_DIR . $path . '/',
'backup' => file_exists('site/data/.backup')
]);
@ -634,7 +676,7 @@ class common
{
// Tableau avec les données vierges
require_once('core/module/install/ressource/defaultdata.php');
require_once ('core/module/install/ressource/defaultdata.php');
// L'arborescence
if (!file_exists(self::DATA_DIR . $path)) {
@ -669,7 +711,7 @@ class common
public function saveConfig($module)
{
// Tableau avec les données vierges
require_once('core/module/install/ressource/defaultdata.php');
require_once ('core/module/install/ressource/defaultdata.php');
// Installation des données des autres modules cad theme profil font config, admin et core
$this->setData([$module, init::$defaultData[$module]]);
common::$coreNotices[] = $module;
@ -705,65 +747,65 @@ class common
* Fonction pour construire le tableau des pages
*/
private function buildHierarchy()
{
$pages = helper::arrayColumn($this->getData(['page']), 'position', 'SORT_ASC');
// Parents
foreach ($pages as $pageId => $pagePosition) {
if (
// Page parent
$this->getData(['page', $pageId, 'parentPageId']) === ""
// Ignore les pages dont l'utilisateur n'a pas accès
and ($this->getData(['page', $pageId, 'group']) === self::GROUP_VISITOR
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
//and $this->getUser('group') >= $this->getData(['page', $pageId, 'group'])
// Modification qui tient compte du profil de la page
and ($this->getUser('group') * self::MAX_PROFILS + $this->getUser('profil')) >= ($this->getData(['page', $pageId, 'group']) * self::MAX_PROFILS + $this->getData(['page', $pageId, 'profil']))
)
)
) {
if ($pagePosition !== 0) {
$this->hierarchy['visible'][$pageId] = [];
}
if ($this->getData(['page', $pageId, 'block']) === 'bar') {
$this->hierarchy['bar'][$pageId] = [];
}
$this->hierarchy['all'][$pageId] = [];
}
}
// Enfants
foreach ($pages as $pageId => $pagePosition) {
if (
// Page parent
$parentId = $this->getData(['page', $pageId, 'parentPageId'])
// Ignore les pages dont l'utilisateur n'a pas accès
and (
(
$this->getData(['page', $pageId, 'group']) === self::GROUP_VISITOR
and
$this->getData(['page', $parentId, 'group']) === self::GROUP_VISITOR
)
or (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
and
$this->getUser('group') * self::MAX_PROFILS + $this->getUser('profil')) >= ($this->getData(['page', $pageId, 'group']) * self::MAX_PROFILS + $this->getData(['page', $pageId, 'profil'])
)
)
) {
if ($pagePosition !== 0) {
$this->hierarchy['visible'][$parentId][] = $pageId;
}
if ($this->getData(['page', $pageId, 'block']) === 'bar') {
$this->hierarchy['bar'][$pageId] = [];
}
$this->hierarchy['all'][$parentId][] = $pageId;
}
}
}
private function buildHierarchy()
{
$pages = helper::arrayColumn($this->getData(['page']), 'position', 'SORT_ASC');
// Parents
foreach ($pages as $pageId => $pagePosition) {
if (
// Page parent
$this->getData(['page', $pageId, 'parentPageId']) === ""
// Ignore les pages dont l'utilisateur n'a pas accès
and ($this->getData(['page', $pageId, 'group']) === self::GROUP_VISITOR
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
//and $this->getUser('group') >= $this->getData(['page', $pageId, 'group'])
// Modification qui tient compte du profil de la page
and ($this->getUser('group') * self::MAX_PROFILS + $this->getUser('profil')) >= ($this->getData(['page', $pageId, 'group']) * self::MAX_PROFILS + $this->getData(['page', $pageId, 'profil']))
)
)
) {
if ($pagePosition !== 0) {
$this->hierarchy['visible'][$pageId] = [];
}
if ($this->getData(['page', $pageId, 'block']) === 'bar') {
$this->hierarchy['bar'][$pageId] = [];
}
$this->hierarchy['all'][$pageId] = [];
}
}
// Enfants
foreach ($pages as $pageId => $pagePosition) {
if (
// Page parent
$parentId = $this->getData(['page', $pageId, 'parentPageId'])
// Ignore les pages dont l'utilisateur n'a pas accès
and (
(
$this->getData(['page', $pageId, 'group']) === self::GROUP_VISITOR
and
$this->getData(['page', $parentId, 'group']) === self::GROUP_VISITOR
)
or (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
and
$this->getUser('group') * self::MAX_PROFILS + $this->getUser('profil')) >= ($this->getData(['page', $pageId, 'group']) * self::MAX_PROFILS + $this->getData(['page', $pageId, 'profil'])
)
)
) {
if ($pagePosition !== 0) {
$this->hierarchy['visible'][$parentId][] = $pageId;
}
if ($this->getData(['page', $pageId, 'block']) === 'bar') {
$this->hierarchy['bar'][$pageId] = [];
}
$this->hierarchy['all'][$parentId][] = $pageId;
}
}
}
/**
* Génère un fichier json avec la liste des pages
@ -1063,8 +1105,9 @@ class common
}
// Articles du blog
if (
$this->getData(['page', $parentPageId, 'moduleId']) === 'blog' &&
!empty($this->getData(['module', $parentPageId]))
$this->getData(['page', $parentPageId, 'moduleId']) === 'blog'
&& !empty($this->getData(['module', $parentPageId]))
&& $this->getData(['module', $parentPageId, 'posts'])
) {
foreach ($this->getData(['module', $parentPageId, 'posts']) as $articleId => $article) {
if ($this->getData(['module', $parentPageId, 'posts', $articleId, 'state']) === true) {
@ -1435,8 +1478,8 @@ class common
foreach ($courses as $courseId => $value) {
// Affiche les espaces gérés par l'éditeur, les espaces où il participe et les espaces anonymes
if (
// le membre est inscrit
( $this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])) )
// le membre est inscrit
($this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])))
// Il est l'auteur
|| $this->getUser('id') === $this->getData(['course', $courseId, 'author'])
// Le cours est ouvert
@ -1450,7 +1493,7 @@ class common
foreach ($courses as $courseId => $value) {
// Affiche les espaces du participant et les espaces anonymes
if (
($this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])) )
($this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])))
|| $this->getData(['course', $courseId, 'enrolment']) === self::COURSE_ENROLMENT_GUEST
) {
$filter[$courseId] = $courses[$courseId];

View File

@ -10,7 +10,7 @@ if (
) {
// Supprime la variable path des profils, seul l'accès à l'espace et autorisé.
foreach (['1', '2'] as $group) {
foreach ( array_keys($this->getData(['profil', $group])) as $profil) {
foreach (array_keys($this->getData(['profil', $group])) as $profil) {
if (is_null($this->getData(['profil', $group, $profil, 'folder', 'path'])) === false) {
$path = $this->getData(['profil', $group, $profil, 'folder', 'path']);
$this->setData(['profil', $group, $profil, 'folder', 'homePath', $path]);
@ -20,4 +20,29 @@ if (
}
}
$this->setData(['core', 'dataVersion', 1700]);
}
if (
$this->getData(['core', 'dataVersion']) < 1800
) {
// Parcourir la structure pour écrire dans les fichiers CSV
foreach ($this->getData(['enrolment']) as $courseId => $users) {
$filename = self::DATA_DIR . $courseId . '/report.csv';
$fp = fopen($filename, 'w');
foreach ($users as $userId => $userData) {
$history = array_key_exists('history', $userData) ? $userData['history'] : null;
if (is_array($history)) {
foreach ($history as $pageId => $timestamps) {
foreach ($timestamps as $timestamp) {
fputcsv($fp, [$userId, $pageId, $timestamp], ';');
}
}
}
$this->deleteData(['enrolment', $courseId, $userId, 'history']);
}
fclose($fp);
}
$this->setData(['core', 'dataVersion', 1800]);
}

View File

@ -7,7 +7,7 @@
'value' => template::ico('left')
]); ?>
</div>
<div class="col2 offset8">
<div class="col2 offset9">
<?php echo template::submit('configManageSubmit', [
'value' => 'Valider',
'ico' => 'check'

View File

@ -26,12 +26,13 @@ class course extends common
'users' => self::GROUP_EDITOR, // fait
'usersAdd' => self::GROUP_EDITOR, //Fait
'usersDelete' => self::GROUP_EDITOR, //Fait
'usersHistoryExport' => self::GROUP_EDITOR, //fait
'usersReportExport' => self::GROUP_EDITOR, //fait
'userDelete' => self::GROUP_EDITOR, //Fait
'userHistory' => self::GROUP_EDITOR, //Fait
'userHistoryExport' => self::GROUP_EDITOR, //Fait
'userReport' => self::GROUP_EDITOR, //Fait
'userReportExport' => self::GROUP_EDITOR, //Fait
'backup' => self::GROUP_EDITOR, // Fait
'restore' => self::GROUP_EDITOR, //Fait
'reset' => self::GROUP_EDITOR,
'clone' => self::GROUP_ADMIN,
'add' => self::GROUP_ADMIN,
'delete' => self::GROUP_ADMIN,
@ -74,7 +75,7 @@ class course extends common
public static $pagesList = ['accueil' => 'Accueil'];
public static $userHistory = [];
public static $userReport = [];
public static $userGraph = [];
@ -104,19 +105,26 @@ class course extends common
? sprintf('%s %s', $this->getData(['user', $this->getData(['course', $courseId, 'author']), 'firstname']), $this->getData(['user', $this->getData(['course', $courseId, 'author']), 'lastname']))
: '';
$categorieUrl = helper::baseUrl() . 'course/swap/' . $courseId;
$info = sprintf(' <a href="%s" target="_blank">%s</a><br />Auteur : %s<br />Id : %s<br />', $categorieUrl, $this->getData(['course', $courseId, 'title']), $author, $courseId, );
$info = sprintf(' <a href="%s">%s</a><br />Auteur : %s<br />Id : %s<br />', $categorieUrl, $this->getData(['course', $courseId, 'title']), $author, $courseId, );
$enrolment = sprintf(
'Accès : %s<br />Inscription : %s<br />',
self::$courseAccess[$this->getData(['course', $courseId, 'access'])],
self::$courseEnrolment[$this->getData(['course', $courseId, 'enrolment'])]
);
if ($this->getUser('permission', 'course', 'users') === true) {
$users = template::button('categoryUser' . $this->getUrl(2), [
'href' => helper::baseUrl() . 'course/users/' . $courseId,
'value' => template::ico('users'),
]);
}
self::$courses[] = [
$info,
$this->getData(['course', $courseId, 'description']),
$enrolment,
$users,
template::button('categoryUser' . $courseId, [
'href' => helper::baseUrl() . 'course/manage/' . $courseId,
'value' => template::ico('eye'),
'value' => template::ico('sliders'),
'help' => 'Gérer'
])
];
@ -639,31 +647,19 @@ class course extends common
}
}
// Liste des inscrits dans le contenu sélectionné.
$users = $this->getData(['enrolment', $courseId]);
$reports = $this->getReport($courseId);
if (is_array($users)) {
// Tri du tableau par défaut par $userId
ksort($users);
foreach ($users as $userId => $userValue) {
// Date et heure de la dernière page vue
// Compatibilité anciennes versions
if (
$this->getData(['enrolment', $courseId, $userId, 'lastPageView']) === null
or $this->getData(['enrolment', $courseId, $userId, 'datePageView']) === null
) {
if (!empty ($userValue['history'])) {
$maxTime = max($userValue['history']);
$lastPageId = array_search($maxTime, $userValue['history']);
$this->setData(['enrolment', $courseId, $userId, 'lastPageView', $lastPageId]);
$this->setData(['enrolment', $courseId, $userId, 'datePageView', $maxTime]);
}
}
// Compte les rôles valides
if (isset ($profils[$this->getData(['user', $userId, 'group']) . $this->getData(['user', $userId, 'profil'])])) {
if (isset($profils[$this->getData(['user', $userId, 'group']) . $this->getData(['user', $userId, 'profil'])])) {
$profils[$this->getData(['user', $userId, 'group']) . $this->getData(['user', $userId, 'profil'])]++;
}
@ -694,28 +690,28 @@ class course extends common
}
// Progression
$viewPages = $this->getData(['enrolment', $courseId, $userId, 'history']) !== null ?
count(array_keys($this->getData(['enrolment', $courseId, $userId, 'history']))) :
$viewPages = array_key_exists($userId, $reports) ?
count($reports[$userId]) :
0;
// Construction du tableau
self::$courseUsers[] = [
//$userId,
$this->getData(['user', $userId, 'firstname']) . ' ' . $this->getData(['user', $userId, 'lastname']),
isset ($pages[$this->getData(['enrolment', $courseId, $userId, 'lastPageView'])]['title'])
? $pages[$this->getData(['enrolment', $courseId, $userId, 'lastPageView'])]['title']
array_key_exists('lastPageView', $userValue) && isset($pages[$userValue['lastPageView']]['title'])
? $pages[$userValue['lastPageView']]['title']
: '',
$this->getData(['enrolment', $courseId, $userId, 'datePageView'])
? helper::dateUTF8('%d/%m/%Y', $this->getData(['enrolment', $courseId, $userId, 'datePageView']))
array_key_exists('lastPageView', $userValue)
? helper::dateUTF8('%d/%m/%Y', $userValue['datePageView'])
: '',
$this->getData(['enrolment', $courseId, $userId, 'datePageView'])
? helper::dateUTF8('%H:%M', $this->getData(['enrolment', $courseId, $userId, 'datePageView']))
array_key_exists('datePageView', $userValue)
? helper::dateUTF8('%H:%M', $userValue['datePageView'])
: '',
$this->getData(['user', $userId, 'tags']),
template::button('userHistory' . $userId, [
'href' => helper::baseUrl() . 'course/userHistory/' . $courseId . '/' . $userId,
'value' => !empty ($userValue['history']) ? min(round(($viewPages * 100) / $sumPages, 1), 100) . ' %' : '0%',
'disable' => empty ($userValue['history'])
template::button('userReport' . $userId, [
'href' => helper::baseUrl() . 'course/userReport/' . $courseId . '/' . $userId,
'value' => $viewPages ? min(round(($viewPages * 100) / $sumPages, 1), 100) . ' %' : '0%',
'disable' => empty($viewPages)
]),
template::button('userDelete' . $userId, [
'class' => 'userDelete buttonRed',
@ -765,7 +761,7 @@ class course extends common
// Inscription des utilisateurs cochés
if (
isset ($_POST['courseUsersAddSubmit'])
isset($_POST['courseUsersAddSubmit'])
) {
foreach ($_POST as $keyPost => $valuePost) {
// Exclure les variables post qui ne sont pas des userId et ne traiter que les non inscrits
@ -821,15 +817,15 @@ class course extends common
foreach ($users as $userId => $userValue) {
// Compte les rôles
if (isset ($profils[$this->getData(['user', $userId, 'group']) . $this->getData(['user', $userId, 'profil'])])) {
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['courseFilterGroup'])
|| isset ($_POST['courseFilterFirstName'])
|| isset ($_POST['courseFilterLastName'])
isset($_POST['courseFilterGroup'])
|| isset($_POST['courseFilterFirstName'])
|| isset($_POST['courseFilterLastName'])
) {
// Groupe et profils
@ -915,6 +911,7 @@ class course extends common
/**
* Désinscription de tous les utilisateurs
* Les désinscriptions ne suppriment pas les historiques
*/
public function usersDelete()
{
@ -934,7 +931,7 @@ class course extends common
// Inscription des utilisateurs cochés
if (
isset ($_POST['courseUsersDeleteSubmit'])
isset($_POST['courseUsersDeleteSubmit'])
) {
foreach ($_POST as $keyPost => $valuePost) {
// Exclure les variables post qui ne sont pas des userId et ne traiter que les non inscrits
@ -984,15 +981,15 @@ class course extends common
foreach ($users as $userId => $userValue) {
// Compte les rôles
if (isset ($profils[$this->getData(['user', $userId, 'group']) . $this->getData(['user', $userId, 'profil'])])) {
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['courseFilterGroup'])
|| isset ($_POST['courseFilterFirstName'])
|| isset ($_POST['courseFilterLastName'])
isset($_POST['courseFilterGroup'])
|| isset($_POST['courseFilterFirstName'])
|| isset($_POST['courseFilterLastName'])
) {
// Groupe et profils
@ -1050,6 +1047,47 @@ class course extends common
]);
}
/**
* Désincription de tous les utilisateurs hors les éditeurs
* Effacement des historiques
*/
public function reset()
{
// Contenu sélectionné
$courseId = $this->getUrl(2);
// Accès limité aux admins, à l'auteur ou éditeurs inscrits
if (
$this->permissionControl(__FUNCTION__, $courseId) === false
) {
// Valeurs en sortie
$this->addOutput([
'access' => false
]);
}
// Active l'accueil
$_SESSION['ZWII_SITE_CONTENT'] = 'home';
// Efface les inscriptions
$success = $this->setData(['enrolment', $courseId, []]);
// Efface les rapports
if (file_exists(self::DATA_DIR . $courseId . '/report.csv')) {
unlink(self::DATA_DIR . $courseId . '/report.csv');
}
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'course',
'notification' => helper::translate('Espace réinitialisé'),
'state' => true
]);
}
/*
* Traitement du changement de langue
*/
@ -1164,7 +1202,7 @@ class course extends common
/**
* Liste les pages consultées par un utilisateur
*/
public function userHistory()
public function userReport()
{
// Espace sélectionné
@ -1181,17 +1219,18 @@ class course extends common
}
$userId = $this->getUrl(3);
$h = $this->getData(['enrolment', $courseId, $userId, 'history']);
$h = $this->getReport($courseId, $userId);
$h = $h[$userId];
// Inversion des clés et des valeurs
$history = array();
$report = array();
foreach ($h as $key => $values) {
foreach ($values as $value) {
$history[$value] = $key;
$report[$value] = $key;
}
}
ksort($history);
ksort($report);
// Liste des pages contenues dans cet espace et exclure les barres et les pages masquées
$p = json_decode(file_get_contents(self::DATA_DIR . $courseId . '/page.json'), true);
@ -1207,11 +1246,11 @@ class course extends common
$topTime = 0;
$lastView = 0;
foreach ($history as $time => $pageId) {
if (isset ($pages[$pageId]['title'])) {
foreach ($report as $time => $pageId) {
if (isset($pages[$pageId]['title'])) {
$lastView = ($lastView === 0) ? $time : $lastView;
$diff = $time - $lastView;
self::$userHistory[] = [
self::$userReport[] = [
html_entity_decode($pages[$pageId]['title']),
$time,
($diff < 1800) ? sprintf("%d' %d''", floor($diff / 60), $diff % 60) : "Non significatif",
@ -1224,22 +1263,22 @@ class course extends common
];
}
$lastView = $time;
$floorTime = isset ($floorTime) && $floorTime < $time ? $floorTime : $time;
$topTime = isset ($topTime) && $topTime > $time ? $topTime : $time;
$floorTime = isset($floorTime) && $floorTime < $time ? $floorTime : $time;
$topTime = isset($topTime) && $topTime > $time ? $topTime : $time;
}
}
// Décale les temps de consultation
for ($i = 0; $i < count(self::$userHistory) - 1; $i++) {
self::$userHistory[$i][2] = self::$userHistory[$i + 1][2];
for ($i = 0; $i < count(self::$userReport) - 1; $i++) {
self::$userReport[$i][2] = self::$userReport[$i + 1][2];
}
// Décale les temps de consultation
for ($i = 0; $i < count(self::$userGraph) - 1; $i++) {
self::$userHistory[$i][1] = self::$userHistory[$i + 1][1];
self::$userReport[$i][1] = self::$userReport[$i + 1][1];
}
// Formate le timestamp
array_walk(self::$userHistory, function (&$item) {
array_walk(self::$userReport, function (&$item) {
$item[1] = helper::dateUTF8('%d/%m/%Y %H:%M:%S', $item[1]);
});
@ -1257,7 +1296,7 @@ class course extends common
// Valeurs en sortie
$this->addOutput([
'title' => helper::translate('Historique ') . $this->getData(['user', $userId, 'firstname']) . ' ' . $this->getData(['user', $userId, 'lastname']),
'view' => 'userHistory',
'view' => 'userReport',
'vendor' => [
"plotly"
]
@ -1265,7 +1304,7 @@ class course extends common
}
public function usersHistoryExport()
public function usersReportExport()
{
$courseId = $this->getUrl(2);
@ -1319,7 +1358,7 @@ class course extends common
$this->getData(['enrolment', $courseId, $userId, 'lastPageView']) === null
or $this->getData(['enrolment', $courseId, $userId, 'datePageView']) === null
) {
if (!empty ($userValue['history'])) {
if (!empty($userValue['history'])) {
$maxTime = max($userValue['history']);
$lastPageId = array_search($maxTime, $userValue['history']);
$this->setData(['enrolment', $courseId, $userId, 'lastPageView', $lastPageId]);
@ -1337,7 +1376,7 @@ class course extends common
$userId,
$this->getData(['user', $userId, 'firstname']),
$this->getData(['user', $userId, 'lastname']),
isset ($pages[$this->getData(['enrolment', $courseId, $userId, 'lastPageView'])])
isset($pages[$this->getData(['enrolment', $courseId, $userId, 'lastPageView'])])
? $pages[$this->getData(['enrolment', $courseId, $userId, 'lastPageView'])]
: $this->getData(['enrolment', $courseId, $userId, 'lastPageView']) . ' (supprimée)',
helper::dateUTF8('%d/%d/%Y', $this->getData(['enrolment', $courseId, $userId, 'datePageView'])),
@ -1371,7 +1410,7 @@ class course extends common
}
}
public function userHistoryExport()
public function userReportExport()
{
$courseId = $this->getUrl(2);
@ -1388,17 +1427,18 @@ class course extends common
}
// Traitement de l'historique
$h = $this->getData(['enrolment', $courseId, $userId, 'history']);
$h = $this->getReport($courseId);
$h = $h[$userId];
// Inversion des clés et des valeurs
$history = array();
$report = array();
foreach ($h as $key => $values) {
foreach ($values as $value) {
$history[$value] = $key;
$report[$value] = $key;
}
}
ksort($history);
ksort($report);
// Liste des pages contenues dans cet espace et exclure les barres et les pages masquées
$p = json_decode(file_get_contents(self::DATA_DIR . $courseId . '/page.json'), true);
@ -1412,33 +1452,33 @@ class course extends common
$lastView = 0;
foreach ($history as $time => $pageId) {
if (isset ($pages[$pageId]['title'])) {
foreach ($report as $time => $pageId) {
if (isset($pages[$pageId]['title'])) {
$lastView = ($lastView === 0) ? $time : $lastView;
$diff = $time - $lastView;
self::$userHistory[] = [
self::$userReport[] = [
$pageId,
html_entity_decode($pages[$pageId]['title']),
$time,
($diff < 1800) ? sprintf("%d' %d''", floor($diff / 60), $diff % 60) : "Non significatif",
];
$lastView = $time;
$floorTime = isset ($floorTime) && $floorTime < $time ? $floorTime : $time;
$topTime = isset ($topTime) && $topTime > $time ? $topTime : $time;
$floorTime = isset($floorTime) && $floorTime < $time ? $floorTime : $time;
$topTime = isset($topTime) && $topTime > $time ? $topTime : $time;
}
}
// Décale les temps de consultation
for ($i = 0; $i < count(self::$userHistory) - 1; $i++) {
self::$userHistory[$i][3] = self::$userHistory[$i + 1][3];
for ($i = 0; $i < count(self::$userReport) - 1; $i++) {
self::$userReport[$i][3] = self::$userReport[$i + 1][3];
}
// Formate le timestamp
array_walk(self::$userHistory, function (&$item) {
array_walk(self::$userReport, function (&$item) {
$item[2] = helper::dateUTF8('%d/%m/%Y %H:%M:%S', $item[2]);
});
// Ajoute les entêtes
self::$userHistory = array_merge([0 => ['PageId', 'Page Titre', 'Consultation Date', 'Temps Consultation']], self::$userHistory);
self::$userReport = array_merge([0 => ['PageId', 'Page Titre', 'Consultation Date', 'Temps Consultation']], self::$userReport);
// Dossier d'export
if (is_dir(self::FILE_DIR . 'source/' . $courseId) === false) {
@ -1451,7 +1491,7 @@ class course extends common
$file = fopen($filename, 'w');
foreach (self::$userHistory as $keys => $values) {
foreach (self::$userReport as $keys => $values) {
$data = $values;
// Écrire la ligne dans le fichier CSV
fputcsv($file, $data, ';');
@ -1461,7 +1501,7 @@ class course extends common
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'course/userHistory/' . $courseId . '/' . $userId,
'redirect' => helper::baseUrl() . 'course/userReport/' . $courseId . '/' . $userId,
'notification' => 'Création ' . basename($filename) . ' dans le dossier "Export"',
'state' => true,
]);
@ -1551,6 +1591,7 @@ class course extends common
/**
* Désinscription d'un participant
* La désinscription ne supprime pas les historiques,
*/
public function unsuscribe()
{
@ -1597,17 +1638,17 @@ class course extends common
// Participants avec historiques
$enrolment = $this->getData(['enrolment', $courseId]);
// Générer un fichier dans le dossier de l'espace
file_put_contents(self::DATA_DIR . $courseId . '/enrolment.json', json_encode([$courseId => $enrolment], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$this->secure_file_put_contents(self::DATA_DIR . $courseId . '/enrolment.json', json_encode([$courseId => $enrolment], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
// Idem pour les données du cours
$course = $this->getData(['course', $courseId]);
// Générer un fichier dans le dossier de l'espace
file_put_contents(self::DATA_DIR . $courseId . '/course.json', json_encode([$courseId => $course], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$this->secure_file_put_contents(self::DATA_DIR . $courseId . '/course.json', json_encode([$courseId => $course], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
// Idem pour la catégorie
$category = $this->getData(['category', $this->getData(['course', $courseId, 'category'])]);
// Générer un fichier dans le dossier de l'espace
file_put_contents(self::DATA_DIR . $courseId . '/category.json', json_encode([$this->getData(['course', $courseId, 'category']) => $category], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$this->secure_file_put_contents(self::DATA_DIR . $courseId . '/category.json', json_encode([$this->getData(['course', $courseId, 'category']) => $category], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
// Génère une archive ZIP
@ -1895,4 +1936,50 @@ class course extends common
return $r;
}
/**
* Lit le contenu des fichiers de traces au format CS et renvoie un tableau associatif
*/
private function getReport($courseId, $userId = null)
{
$data = [];
if (file_exists(self::DATA_DIR . $courseId . '/report.csv')) {
// Remplacez 'chemin/vers/votre/fichier.csv' par le chemin réel de votre fichier CSV
$file = fopen(self::DATA_DIR . $courseId . '/report.csv', "r");
$data = array();
// Lire ligne par ligne
while (($line = fgetcsv($file, 1000, ";")) !== false) {
$name = $line[0];
$pageId = $line[1];
$timestamp = $line[2];
// Filtre userId
// if (!is_null($userId) && $name === $userId) {
// Initialiser le tableau si nécessaire
if (!isset($data[$name][$pageId])) {
$data[$name][$pageId] = array();
}
// Ajouter le timestamp
$data[$name][$pageId][] = $timestamp;
//}
}
// Fermer le fichier
fclose($file);
// Trier les timestamps
foreach ($data as &$userData) {
foreach ($userData as &$pageData) {
sort($pageData);
}
}
}
// Afficher le JSON;
return $data;
}
}

View File

@ -23,6 +23,16 @@ $(document).ready(function () {
target: 2,
orderable: false,
searchable: false
},
{
target: 3,
orderable: false,
searchable: false
},
{
target: 4,
orderable: false,
searchable: false
}
]
});

View File

@ -37,7 +37,7 @@
</div>
</div>
<?php if ($module::$courses): ?>
<?php echo template::table([4, 4, 3, 1], $module::$courses, ['Titre court', 'Description', 'Inscription', '',], ['id' => 'dataTables']); ?>
<?php echo template::table([4, 3, 3, 1, 1], $module::$courses, ['Titre court', 'Description', 'Inscription', '', '',], ['id' => 'dataTables']); ?>
<?php else: ?>
<?php echo template::speech('Aucun espace'); ?>
<?php endif; ?>

View File

@ -20,4 +20,15 @@ $(".courseDelete").on("click", function () {
return core.confirm(message, function () {
$(location).attr("href", _this.attr("href"));
});
});
/**
* Confirmation de suppression
*/
$(".courseReset").on("click", function () {
var _this = $(this);
var message = "<?php echo helper::translate('Réinitialiser cet espace ?'); ?>";
return core.confirm(message, function () {
$(location).attr("href", _this.attr("href"));
});
});

View File

@ -18,6 +18,16 @@
]); ?>
</div>
<?php endif; ?>
<?php if ($this->getUser('permission', 'course', 'reset') === true): ?>
<div class="col2 ">
<?php echo template::button('courseManageReset' . $this->getUrl(2), [
'class' => 'courseReset buttonRed',
'href' => helper::baseUrl() . 'course/reset/' . $this->getUrl(2),
'value' => 'Réinitaliser',
'ico' => 'cancel'
]); ?>
</div>
<?php endif; ?>
<?php if ($this->getUser('permission', 'course', 'backup') === true): ?>
<div class="col2">
<?php echo template::button('courseManageDownload' . $this->getUrl(2), [
@ -38,7 +48,6 @@
<?php endif; ?>
<?php if ($this->getUser('permission', 'course', 'edit') === true): ?>
<div class="col2">
<?php echo template::button('courseManageEdit' . $this->getUrl(2), [
'href' => helper::baseUrl() . 'course/edit/' . $this->getUrl(2),
'value' => 'Éditer',
@ -46,18 +55,8 @@
]); ?>
</div>
<?php endif; ?>
<?php if ($this->getUser('permission', 'course', 'users') === true): ?>
<div class="col2">
<?php echo template::button('categoryUser' . $this->getUrl(2), [
'href' => helper::baseUrl() . 'course/users/' . $this->getUrl(2),
'value' => 'Participants',
'ico' => 'users'
]); ?>
</div>
<?php endif; ?>
</div>
<div class="row">
<div class="col12">
<div class="block">

View File

@ -20,7 +20,7 @@
</div>
</div>
</div>
<?php if ($module::$userHistory): ?>
<?php if ($module::$userReport): ?>
<div class="row">
<div class="col4 offset2">
<?php if ($this->getData(['course', $this->getUrl(2), 'access']) === self::COURSE_ACCESS_DATE): ?>
@ -46,7 +46,7 @@
</div>
<div class="row textAlignCenter">
<div class="col8">
<?php echo template::table([6, 3, 3], $module::$userHistory, ['Page', 'Début de Consultation', 'Temps consultation']); ?>
<?php echo template::table([6, 3, 3], $module::$userReport, ['Page', 'Début de Consultation', 'Temps consultation']); ?>
</div>
</div>
<?php else: ?>

View File

@ -2,7 +2,7 @@
<div class="col1">
<?php echo template::button('courseUserBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'course/manage/' . $this->getUrl(2),
'href' => helper::baseUrl() . 'course/' . $this->getUrl(2),
'value' => template::ico('left')
]); ?>
</div>

View File

@ -17,10 +17,6 @@
* admin.css
*/
#courseUserAddSelectAll {
color: lightgreen;
}
#courseUserAddSelectNone {
color: lightcoral;
tr {
cursor: pointer;
}

View File

@ -13,6 +13,13 @@
$(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
});
});
$('#courseUserAddSelectAll').on('click', function() {
$('.checkboxSelect').prop('checked', true);
saveCheckboxState();

View File

@ -9,13 +9,13 @@
</div>
<div class="col1 offset8">
<?php echo template::button('courseUserAddSelectAll', [
'value' => template::ico('check'),
'value' => template::ico('square-check'),
'help' => 'Tout sélectionner'
]); ?>
</div>
<div class="col1">
<?php echo template::button('courseUserAddSelectNone', [
'value' => template::ico('cancel'),
'value' => template::ico('square-check-empty'),
'help' => 'Tout désélectionner'
]); ?>
</div>

View File

@ -21,10 +21,6 @@
background-color: rgba(217, 95, 78, 1);
}
#courseUserDeleteSelectAll {
color: lightgreen;
}
#courseUserDeleteSelectNone {
color: lightcoral;
tr {
cursor: pointer;
}

View File

@ -13,6 +13,13 @@
$(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
});
});
$('#courseUserDeleteSelectAll').on('click', function () {
$('.checkboxSelect').prop('checked', true);
saveCheckboxState();

View File

@ -9,13 +9,13 @@
</div>
<div class="col1 offset8">
<?php echo template::button('courseUserDeleteSelectAll', [
'value' => template::ico('check'),
'value' => template::ico('square-check'),
'help' => 'Tout sélectionner'
]); ?>
</div>
<div class="col1">
<?php echo template::button('courseUserDeleteSelectNone', [
'value' => template::ico('cancel'),
'value' => template::ico('square-check-empty'),
'help' => 'Tout désélectionner'
]); ?>
</div>

View File

@ -387,7 +387,7 @@ class install extends common
'</IfModule>' . PHP_EOL .
'# URL rewriting' . PHP_EOL;
$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
$success = file_put_contents(
$success = $this->secure_file_put_contents(
'.htaccess',
$fileContent
);

View File

@ -252,7 +252,8 @@ class init extends common
'usersDelete' => false,
'edit' => false,
'backup' => false,
'restore' => false
'restore' => false,
'reset' => false,
],
'folder' => [
'create' => false,
@ -348,7 +349,8 @@ class init extends common
'usersDelete' => false,
'edit' => false,
'backup' => false,
'restore' => false
'restore' => false,
'reset' => false,
],
'folder' => [
'create' => false,
@ -449,7 +451,8 @@ class init extends common
'usersDelete' => false,
'edit' => false,
'backup' => false,
'restore' => false
'restore' => false,
'reset' => false,
],
'folder' => [
'create' => false,
@ -546,7 +549,8 @@ class init extends common
'usersDelete' => true,
'edit' => true,
'backup' => true,
'restore' => true
'restore' => true,
'reset' => true,
],
'folder' => [
'create' => true,

View File

@ -99,7 +99,7 @@ class language extends common
is_array($descripteur['language'][$lang])
) {
if ($this->setData(['language', $lang, $descripteur['language'][$lang]])) {
$success = file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($languageData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$success = $this->secure_file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($languageData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$success = is_int($success) ? true : false;
}
}

View File

@ -85,12 +85,23 @@ class page extends common
*/
public function duplicate()
{
// La session ne correspond pas au site ouvert dans cet onglet
if (
// Contrôle la présence de l'id d'espace uniquement si l'id est fourni afin de ne pas bloquer les modules non mis à jour
$this->getUrl(3) && $this->getUrl(3) != self::$siteContent
) {
$_SESSION['ZWII_SITE_CONTENT'] = $this->getUrl(3);
header('Refresh:0; url=' . helper::baseUrl() . $this->getUrl());
exit();
}
// Adresse sans le token
$page = $this->getUrl(2);
// La page n'existe pas
if (
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true ||
$this->getData(['page', $page]) === null
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|| $this->getData(['page', $page]) === null
) {
// Valeurs en sortie
$this->addOutput([
@ -118,7 +129,7 @@ class page extends common
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'page/edit/' . $pageId,
'redirect' => helper::baseUrl() . 'page/edit/' . $pageId . '/' . self::$siteContent,
'notification' => $notification,
'state' => true
]);
@ -131,7 +142,19 @@ class page extends common
*/
public function add()
{
if ($this->getUser('permission', __CLASS__, __FUNCTION__) !== true) {
// La session ne correspond pas au site ouvert dans cet onglet
if (
// Contrôle la présence de l'id d'espace uniquement si l'id est fourni afin de ne pas bloquer les modules non mis à jour
$this->getUrl(3) && $this->getUrl(3) != self::$siteContent
) {
$_SESSION['ZWII_SITE_CONTENT'] = $this->getUrl(3);
header('Refresh:0; url=' . helper::baseUrl() . $this->getUrl());
exit();
}
if (
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
) {
// Valeurs en sortie
$this->addOutput([
'access' => false
@ -198,12 +221,24 @@ class page extends common
*/
public function delete()
{
// La session ne correspond pas au site ouvert dans cet onglet
if (
// Contrôle la présence de l'id d'espace uniquement si l'id est fourni afin de ne pas bloquer les modules non mis à jour
$this->getUrl(3) && $this->getUrl(3) != self::$siteContent
) {
$_SESSION['ZWII_SITE_CONTENT'] = $this->getUrl(3);
header('Refresh:0; url=' . helper::baseUrl() . $this->getUrl());
exit();
}
// $url prend l'adresse sans le token
$page = $this->getUrl(2);
// La page n'existe pas
if (
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true ||
$this->getData(['page', $page]) === null
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|| $this->getData(['page', $page]) === null
) {
// Valeurs en sortie
$this->addOutput([
@ -215,9 +250,9 @@ class page extends common
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . $this->homePageId(),
'notification' => self::$siteContent === 'home'
? helper::translate('Suppression interdite, cette page est définie comme page d\'accueil du site')
: helper::translate('Suppression interdite, cette page est définie comme page d\'accueil d\'un espace')
'notification' => self::$siteContent === 'home'
? helper::translate('Suppression interdite, cette page est définie comme page d\'accueil du site')
: helper::translate('Suppression interdite, cette page est définie comme page d\'accueil d\'un espace')
]);
}
// Impossible de supprimer la page affectée
@ -264,7 +299,7 @@ class page extends common
elseif ($this->getHierarchy($page, null)) {
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'page/edit/' . $page,
'redirect' => helper::baseUrl() . 'page/edit/' . $page . '/' . self::$siteContent,
'notification' => helper::translate('Impossible de supprimer une page contenant des pages enfants')
]);
}
@ -304,10 +339,24 @@ class page extends common
*/
public function edit()
{
// La session ne correspond pas au site ouvert dans cet onglet
if (
// Contrôle la présence de l'id d'espace uniquement si l'id est fourni afin de ne pas bloquer les modules non mis à jour
$this->getUrl(3) && $this->getUrl(3) != self::$siteContent
) {
$_SESSION['ZWII_SITE_CONTENT'] = $this->getUrl(3);
header('Refresh:0; url=' . helper::baseUrl() . $this->getUrl());
exit();
}
// La page n'existe pas
if (
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true ||
$this->getData(['page', $this->getUrl(2)]) === null
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|| $this->getData(['page', $this->getUrl(2)]) === null
// Contrôle la présence de l'id d'espace uniquement si l'id est fourni afin de ne pas bloquer les modules non mis à jour
|| (
$this->getUrl(3)
&& $this->getUrl(3) != self::$siteContent
)
) {
// Valeurs en sortie
$this->addOutput([
@ -634,7 +683,7 @@ class page extends common
// Valeurs en sortie
$this->addOutput([
'notification' => helper::translate('Modifications enregistrées'),
'redirect' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2),
'redirect' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2) . '/' . self::$siteContent,
'state' => true
]);
}
@ -669,7 +718,7 @@ class page extends common
// Valeurs en sortie
$this->addOutput([
'notification' => helper::translate('Modifications enregistrées'),
'redirect' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2),
'redirect' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2) . '/' . self::$siteContent,
'state' => true
]);
}
@ -685,16 +734,16 @@ class page extends common
/**
* Retourne les informations sur les pages en omettant les clés CSS et JS qui occasionnent des bugs d'affichage dans l'éditeur de page
* @return array tableau associatif des pages dans le menu
* @return string tableau associatif des pages dans le menu
*/
public function getPageInfo()
{
$p = $this->getData(['page']);
$d = array_map(function ($d) {
unset($d["css"], $d["js"]);
unset ($d["css"], $d["js"]);
return $d;
}, $p);
return json_encode($d);
}
}

View File

@ -3,7 +3,7 @@
<div class="col1">
<?php echo template::button('pageCssEditorBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2),
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2) . '/' . self::$siteContent,
'value' => template::ico('left')
]); ?>
</div>

View File

@ -19,14 +19,14 @@
<div class="col1 offset6">
<?php echo template::button('pageEditDelete', [
'class' => 'buttonRed',
'href' => helper::baseUrl() . 'page/delete/' . $this->getUrl(2),
'href' => helper::baseUrl() . 'page/delete/' . $this->getUrl(2) . '/' . self::$siteContent,
'value' => template::ico('trash'),
'help' => 'Effacer la page'
]); ?>
</div>
<div class="col1">
<?php echo template::button('pageEditDuplicate', [
'href' => helper::baseUrl() . 'page/duplicate/' . $this->getUrl(2),
'href' => helper::baseUrl() . 'page/duplicate/' . $this->getUrl(2) . '/' . self::$siteContent,
'value' => template::ico('clone'),
'help' => 'Dupliquer la page'
]); ?>

View File

@ -3,7 +3,7 @@
<div class="col1">
<?php echo template::button('pageJsEditorBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2),
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2) . '/' . self::$siteContent,
'value' => template::ico('left')
]); ?>
</div>

View File

@ -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
*/
@ -711,8 +851,28 @@ class user extends common
// Droit d'intervenir sur tous les espaces
'tutor' => $this->getInput('profilEditCourseTutor', helper::FILTER_BOOLEAN),
// Droit d'accéder à la fenêtre de gestion pour tous les éditeurs et plus
'index' => $this->getUser('group') >= self::GROUP_EDITOR,
'manage' => $this->getUser('group') >= self::GROUP_EDITOR,
'index' => $this->getInput('profilEditCourseUsers', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserHistory', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserExport', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserAdd', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUsersAdd', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserDelete', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUsersDelete', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseEdit', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseBackup', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseRestore', helper::FILTER_BOOLEAN),
'manage' => $this->getInput('profilEditCourseUsers', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserHistory', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserExport', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserAdd', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUsersAdd', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUserDelete', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseUsersDelete', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseEdit', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseBackup', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseRestore', helper::FILTER_BOOLEAN)
|| $this->getInput('profilEditCourseReset', helper::FILTER_BOOLEAN),
// Droits spécifiques
'users' => $this->getInput('profilEditCourseUsers', helper::FILTER_BOOLEAN),
'userHistory' => $this->getInput('profilEditCourseUserHistory', helper::FILTER_BOOLEAN),
@ -724,6 +884,7 @@ class user extends common
'edit' => $this->getInput('profilEditCourseEdit', helper::FILTER_BOOLEAN),
'backup' => $this->getInput('profilEditCourseBackup', helper::FILTER_BOOLEAN),
'restore' => $this->getInput('profilEditCourseRestore', helper::FILTER_BOOLEAN),
'reset' => $this->getInput('profilEditCourseReset', helper::FILTER_BOOLEAN),
]
];
@ -905,7 +1066,8 @@ class user extends common
|| $this->getInput('profilAddCourseUsersDelete', helper::FILTER_BOOLEAN)
|| $this->getInput('profilAddCourseEdit', helper::FILTER_BOOLEAN)
|| $this->getInput('profilAddCourseBackup', helper::FILTER_BOOLEAN)
|| $this->getInput('profilAddCourseRestore', helper::FILTER_BOOLEAN),
|| $this->getInput('profilAddCourseRestore', helper::FILTER_BOOLEAN)
|| $this->getInput('profilAddCourseReset', helper::FILTER_BOOLEAN),
// La suite
'users' => $this->getInput('profilAddCourseUsers', helper::FILTER_BOOLEAN),
'userHistory' => $this->getInput('profilAddCourseUserHistory', helper::FILTER_BOOLEAN),
@ -917,6 +1079,7 @@ class user extends common
'edit' => $this->getInput('profilAddCourseEdit', helper::FILTER_BOOLEAN),
'backup' => $this->getInput('profilAddCourseBackup', helper::FILTER_BOOLEAN),
'restore' => $this->getInput('profilAddCourseRestore', helper::FILTER_BOOLEAN),
'reset' => $this->getInput('profilAddCourseReset', helper::FILTER_BOOLEAN),
]
];

View File

@ -8,20 +8,28 @@
</div>
<div class="col1">
<?php /**echo template::button('userHelp', [
'href' => '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'
]);*/ ?>
</div>
<div class="col1 offset7">
<div class="col1 offset6">
<?php echo template::button('userImport', [
'href' => helper::baseUrl() . 'user/import',
'value' => template::ico('upload'),
'value' => template::ico('users'),
'help' => 'Importer des utilisateurs en masse'
]); ?>
</div>
<div class="col1">
<?php echo template::button('userDeleteAll', [
'class' => 'userDeleteAll buttonRed',
'href' => helper::baseUrl() . 'user/usersDelete/' . $this->getUrl(2),
'value' => template::ico('users'),
'help' => 'Désinscrire en masse',
]) ?>
</div>
<div class="col1">
<?php echo template::button('userGroup', [
'href' => helper::baseUrl() . 'user/profil',
@ -60,4 +68,4 @@
</div>
</div>
<?php echo template::formClose(); ?>
<?php echo template::table([3, 2, 2, 2, 2, 1, 1], $module::$users, [ 'Nom', 'Groupe', 'Profil', 'Étiquettes', 'Date dernière vue', '', ''], ['id' => 'dataTables']); ?>
<?php echo template::table([3, 2, 2, 2, 2, 1, 1], $module::$users, ['Nom', 'Groupe', 'Profil', 'Étiquettes', 'Date dernière vue', '', ''], ['id' => 'dataTables']); ?>

View File

@ -205,6 +205,9 @@
<div class="col3">
<?php echo template::checkbox('profilAddCourseUsersDelete', true, 'Désinscrire en masse'); ?>
</div>
<div class="col3">
<?php echo template::checkbox('profilAddCourseReset', true, 'Réinitialiser un espace'); ?>
</div>
</div>
</div>
</div>

View File

@ -54,6 +54,19 @@ $(document).ready(function () {
$(".containerModule").slideDown();
}
if ($('#profilEditCourseUsers').is(':checked')) {
// Activer les autres checkboxes
$('#profilEditCourseUserHistory, #profilEditCourseUserHistoryExport, #profilEditCourseUserDelete, #profilEditCourseUsersAdd, #profilEditCourseUsersDelete, #profilEditCourseReset').prop('disabled', false);
} else {
// Désactiver les autres checkboxes
$('#profilEditCourseUserHistory, #profilEditCourseUserHistoryExport, #profilEditCourseUserDelete, #profilEditCourseUsersAdd, #profilEditCourseUsersDelete, #profilEditCourseReset').prop('checked', false).prop('disabled', true);
// Désactiver les modules et tout décocher
$(".courseContainer").slideUp();
$('.courseContainer input[type="checkbox"]').prop('checked', false);
}
// EVENEMENTS
// À chaque inversion de l'état du checkbox avec l'id "profilEditFileManager", désactive ou active tous les éléments de la classe "filemanager" en fonction de l'état
$("#profilEditFileManager").change(function () {
if (!$(this).is(':checked')) {
@ -118,4 +131,20 @@ $(document).ready(function () {
}
});
// Gérer lévènement de modification de la checkbox #profilEditCourse
$('#profilEditCourseUsers').change(function () {
if ($(this).is(':checked')) {
// Activer les autres checkboxes
$('#profilEditCourseUserHistory, #profilEditCourseUserHistoryExport, #profilEditCourseUserDelete, #profilEditCourseUsersAdd, #profilEditCourseUsersDelete, #profilEditCourseReset').prop('disabled', false);
} else {
// Désactiver les autres checkboxes
$('#profilEditCourseUserHistory, #profilEditCourseUserHistoryExport, #profilEditCourseUserDelete, #profilEditCourseUsersAdd, #profilEditCourseUsersDelete, #profilEditCourseReset').prop('checked', false).prop('disabled', true);
// Désactiver les modules et tout décocher
$(".courseContainer").slideUp();
$('.courseContainer input[type="checkbox"]').prop('checked', false);
}
});
});

View File

@ -307,6 +307,11 @@
'checked' => $this->getData(['profil', $this->getUrl(2), $this->getUrl(3), 'course', 'usersDelete']),
]); ?>
</div>
<div class="col3">
<?php echo template::checkbox('profilEditCourseReset', true, 'Réinitialiser un espace', [
'checked' => $this->getData(['profil', $this->getUrl(2), $this->getUrl(3), 'course', 'reset']),
]); ?>
</div>
</div>
</div>
</div>

View File

@ -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 <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @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;
}

View File

@ -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 <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @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);
}
}
}
}));

View File

@ -0,0 +1,55 @@
<?php echo template::formOpen('usersDeleteForm'); ?>
<div class="row">
<div class="col1">
<?php echo template::button('userDeleteBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'user/' . $this->getUrl(2),
'value' => template::ico('left')
]); ?>
</div>
<div class="col1 offset8">
<?php echo template::button('usersDeleteSelectAll', [
'value' => template::ico('square-check'),
'help' => 'Tout sélectionner'
]); ?>
</div>
<div class="col1">
<?php echo template::button('usersDeleteSelectNone', [
'value' => template::ico('square-check-empty'),
'help' => 'Tout désélectionner'
]); ?>
</div>
<div class="col1">
<?php echo template::submit('usersDeleteSubmit', [
'class' => 'buttonRed',
'ico' => '',
'value' => template::ico('minus'),
]); ?>
</div>
</div>
<div class="row" id="Bfrtip">
<div class="col3">
<?php echo template::select('usersFilterGroup', $module::$usersGroups, [
'label' => 'Groupes / Profils',
'selected' => isset($_POST['usersFilterGroup']) ? $_POST['usersFilterGroup'] : 'all',
]); ?>
</div>
<div class="col3">
<?php echo template::select('usersFilterFirstName', $module::$alphabet, [
'label' => 'Prénom commence par',
'selected' => isset($_POST['usersFilterFirstName']) ? $_POST['usersFilterFirstName'] : 'all',
]); ?>
</div>
<div class="col3">
<?php echo template::select('usersFilterLastName', $module::$alphabet, [
'label' => 'Nom commence par',
'selected' => isset($_POST['usersFilterLastName']) ? $_POST['usersFilterLastName'] : 'all',
]); ?>
</div>
</div>
<?php if ($module::$users): ?>
<?php echo template::table([1, 2, 3, 3, 3], $module::$users, ['', 'Id', 'Prénom', 'Nom', 'Étiquettes'], ['id' => 'dataTables']); ?>
<?php else: ?>
<?php echo template::speech('Aucun inscrit'); ?>
<?php endif; ?>
<?php echo template::formClose(); ?>

View File

@ -1,6 +1,7 @@
@charset "UTF-8";
.zwiico-plus-circled:before { content: '\2191'; } /* '↑' */
.zwiico-square-check:before { content: '\e800'; } /* '' */
.zwiico-plus:before { content: '\e801'; } /* '' */
.zwiico-cancel:before { content: '\e802'; } /* '' */
.zwiico-help:before { content: '\e803'; } /* '' */
@ -48,6 +49,7 @@
.zwiico-right-dir:before { content: '\e82d'; } /* '' */
.zwiico-chart-line:before { content: '\e82e'; } /* '' */
.zwiico-book:before { content: '\e82f'; } /* '' */
.zwiico-square-check-empty:before { content: '\e830'; } /* '' */
.zwiico-spin:before { content: '\e831'; } /* '' */
.zwiico-twitter:before { content: '\f099'; } /* '' */
.zwiico-facebook:before { content: '\f09a'; } /* '' */

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,6 @@
.zwiico-plus-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2191;&nbsp;'); }
.zwiico-square-check { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe800;&nbsp;'); }
.zwiico-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
.zwiico-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
.zwiico-help { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
@ -47,6 +48,7 @@
.zwiico-right-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe82d;&nbsp;'); }
.zwiico-chart-line { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe82e;&nbsp;'); }
.zwiico-book { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe82f;&nbsp;'); }
.zwiico-square-check-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe830;&nbsp;'); }
.zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe831;&nbsp;'); }
.zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf099;&nbsp;'); }
.zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09a;&nbsp;'); }

View File

@ -11,6 +11,7 @@
}
.zwiico-plus-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2191;&nbsp;'); }
.zwiico-square-check { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe800;&nbsp;'); }
.zwiico-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
.zwiico-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
.zwiico-help { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
@ -58,6 +59,7 @@
.zwiico-right-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe82d;&nbsp;'); }
.zwiico-chart-line { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe82e;&nbsp;'); }
.zwiico-book { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe82f;&nbsp;'); }
.zwiico-square-check-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe830;&nbsp;'); }
.zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe831;&nbsp;'); }
.zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf099;&nbsp;'); }
.zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09a;&nbsp;'); }

View File

@ -1,12 +1,12 @@
@charset "UTF-8";
@font-face {
font-family: 'zwiico';
src: url('../font/zwiico.eot?8645815');
src: url('../font/zwiico.eot?8645815#iefix') format('embedded-opentype'),
url('../font/zwiico.woff2?8645815') format('woff2'),
url('../font/zwiico.woff?8645815') format('woff'),
url('../font/zwiico.ttf?8645815') format('truetype'),
url('../font/zwiico.svg?8645815#zwiico') format('svg');
src: url('../font/zwiico.eot?58081754');
src: url('../font/zwiico.eot?58081754#iefix') format('embedded-opentype'),
url('../font/zwiico.woff2?58081754') format('woff2'),
url('../font/zwiico.woff?58081754') format('woff'),
url('../font/zwiico.ttf?58081754') format('truetype'),
url('../font/zwiico.svg?58081754#zwiico') format('svg');
font-weight: normal;
font-style: normal;
}
@ -16,7 +16,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'zwiico';
src: url('../font/zwiico.svg?8645815#zwiico') format('svg');
src: url('../font/zwiico.svg?58081754#zwiico') format('svg');
}
}
*/
@ -56,6 +56,7 @@
}
.zwiico-plus-circled:before { content: '\2191'; } /* '↑' */
.zwiico-square-check:before { content: '\e800'; } /* '' */
.zwiico-plus:before { content: '\e801'; } /* '' */
.zwiico-cancel:before { content: '\e802'; } /* '' */
.zwiico-help:before { content: '\e803'; } /* '' */
@ -103,6 +104,7 @@
.zwiico-right-dir:before { content: '\e82d'; } /* '' */
.zwiico-chart-line:before { content: '\e82e'; } /* '' */
.zwiico-book:before { content: '\e82f'; } /* '' */
.zwiico-square-check-empty:before { content: '\e830'; } /* '' */
.zwiico-spin:before { content: '\e831'; } /* '' */
.zwiico-twitter:before { content: '\f099'; } /* '' */
.zwiico-facebook:before { content: '\f09a'; } /* '' */

Binary file not shown.

View File

@ -8,6 +8,8 @@
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="plus-circled" unicode="&#x2191;" d="M420 770q174 0 297-123t123-297-123-297-297-123-297 123-123 297 123 297 297 123z m52-470l200 0 0 102-200 0 0 202-102 0 0-202-202 0 0-102 202 0 0-202 102 0 0 202z" horiz-adv-x="840" />
<glyph glyph-name="square-check" unicode="&#xe800;" d="M0-150l0 1000 646 0-164-164-318 0 0-672 672 0 0 319 164 164 0-647-1000 0z m234 623l133 131 129-129 361 363 133-132-361-364-133-133z" horiz-adv-x="1000" />
<glyph glyph-name="plus" unicode="&#xe801;" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
<glyph glyph-name="cancel" unicode="&#xe802;" d="M724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
@ -102,6 +104,8 @@
<glyph glyph-name="book" unicode="&#xe82f;" d="M915 583q22-31 10-72l-154-505q-10-36-42-60t-69-25h-515q-43 0-83 30t-55 74q-14 37-1 71 0 2 1 15t3 20q0 5-2 12t-2 11q1 6 5 12t9 13 9 13q13 21 25 51t17 51q2 6 0 17t0 16q2 6 9 15t10 13q12 20 23 51t14 51q1 5-1 17t0 16q2 7 12 17t13 13q10 14 23 47t16 54q0 4-2 14t-1 15q1 4 5 10t10 13 10 11q4 7 9 17t8 20 9 20 11 18 15 13 20 6 26-3l0-1q21 5 28 5h425q41 0 64-32t10-72l-153-506q-20-66-40-85t-72-20h-485q-15 0-21-8-6-9-1-24 14-39 81-39h515q16 0 31 9t20 23l167 550q4 13 3 32 21-8 33-24z m-594-1q-2-7 1-12t11-6h339q8 0 15 6t9 12l12 36q2 7-1 12t-12 6h-339q-7 0-14-6t-9-12z m-46-143q-3-7 1-12t11-6h339q7 0 14 6t10 12l11 36q3 7-1 13t-11 5h-339q-7 0-14-5t-10-13z" horiz-adv-x="928.6" />
<glyph glyph-name="square-check-empty" unicode="&#xe830;" d="M0-150l0 1000 1000 0 0-1000-1000 0z m164 164l672 0 0 672-672 0 0-672z" horiz-adv-x="1000" />
<glyph glyph-name="spin" unicode="&#xe831;" d="M46 144l0 0c0 0-1 0-1 0-8 18-15 37-21 55-6 19-11 38-15 58-19 99-8 203 35 298 3 6 10 8 15 5 1 0 2 0 2-1l0 0 80-59c5-3 6-9 4-14-5-12-9-25-12-37-4-13-7-26-9-40-11-67-3-137 23-201 2-5 0-10-4-13l0 0-80-56c-5-4-12-2-16 3-1 0-1 1-1 2l0 0z m120 574l0 0c0 1 0 1 0 1 15 13 30 25 46 37 16 11 33 22 51 31 89 50 192 72 297 60 6-1 10-6 10-13 0-1-1-1-1-2l0 0-31-94c-2-5-8-8-13-7-13 0-27 0-40 0-14-1-27-2-40-4-68-11-133-40-186-84-4-3-10-3-14 0l0 0-79 58c-5 3-6 11-2 16 0 0 1 1 2 1l0 0z m588 65l0 0c0 0 1 0 1 0 17-10 34-21 50-32 16-12 31-25 46-38 74-69 127-160 148-262 2-6-2-12-9-13-1 0-1 0-2 0l0 0-100 1c-5 0-10 4-11 9-3 13-8 26-12 38-5 12-10 25-17 36-31 61-78 113-137 150-5 3-6 8-5 13l0 0 31 92c2 6 9 9 15 7 1 0 2-1 2-1l0 0z m244-535l0 0c0 0 0 0 0 0-4-20-9-39-15-57-7-19-14-37-22-55-44-92-114-170-205-221-6-3-13-1-16 4 0 1-1 2-1 2l0 0-30 94c-2 6 1 12 6 14 11 7 22 15 32 23 11 9 21 18 30 27 49 48 84 109 101 176 2 5 6 8 11 8l0 0 98-1c6 0 11-5 11-11 0-1 0-2 0-3l0 0z m-438-395l0 0c0 0 0 0 0 0-20-2-40-3-60-3-20 0-40 1-59 4-102 12-198 54-276 125-5 4-5 11 0 16 0 0 1 1 1 1l0 0 81 58c5 3 12 2 16-2 10-8 20-16 32-23 11-7 22-14 34-20 62-31 131-45 200-41 6 0 10-3 12-8l0 0 29-92c2-6-1-12-7-14-1-1-2-1-3-1l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="twitter" unicode="&#xf099;" d="M904 622q-37-54-90-93 0-8 0-23 0-73-21-145t-64-139-103-117-144-82-181-30q-151 0-276 81 19-2 43-2 126 0 224 77-59 1-105 36t-64 89q19-3 34-3 24 0 48 6-63 13-104 62t-41 115v2q38-21 82-23-37 25-59 64t-22 86q0 49 25 91 68-83 164-133t208-55q-5 21-5 41 0 75 53 127t127 53q79 0 132-57 61 12 115 44-21-64-80-100 52 6 104 28z" horiz-adv-x="928.6" />

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,7 +16,7 @@
class blog extends common
{
const VERSION = '7.6';
const VERSION = '7.9';
const REALNAME = 'Blog';
const DELETE = true;
const UPDATE = '0.0';
@ -196,9 +196,11 @@ class blog extends common
$feeds = new \FeedWriter\RSS2();
// En-tête
$feeds->setTitle($this->getData(['page', $this->getUrl(0), 'title']));
$feeds->setTitle($this->getData(['page', $this->getUrl(0), 'title']) ? $this->getData(['page', $this->getUrl(0), 'title']): '');
$feeds->setLink(helper::baseUrl() . $this->getUrl(0));
$feeds->setDescription($this->getData(['page', $this->getUrl(0), 'metaDescription']));
if ($this->getData(['page', $this->getUrl(0), 'metaDescription'])) {
$feeds->setDescription($this->getData(['page', $this->getUrl(0), 'metaDescription']));
}
$feeds->setChannelElement('language', 'fr-FR');
$feeds->setDate(date('r', time()));
$feeds->addGenerator();
@ -361,7 +363,7 @@ class blog extends common
self::$dateFormat = $this->getData(['module', $this->getUrl(0), 'config', 'dateFormat']);
self::$timeFormat = $this->getData(['module', $this->getUrl(0), 'config', 'timeFormat']);
self::$comments[] = [
helper::dateUTF8(self::$dateFormat, $comment['createdOn']) . ' - ' . helper::dateUTF8(self::$timeFormat, $comment['createdOn']),
helper::dateUTF8(self::$dateFormat, $comment['createdOn'], self::$i18nUI) . ' - ' . helper::dateUTF8(self::$timeFormat, $comment['createdOn'], self::$i18nUI),
$comment['content'],
$comment['userId'] ? $this->getData(['user', $comment['userId'], 'firstname']) . ' ' . $this->getData(['user', $comment['userId'], 'lastname']) : $comment['author'],
$buttonApproval,
@ -530,7 +532,7 @@ class blog extends common
'<a href="' . helper::baseurl() . $this->getUrl(0) . '/' . $articleIds[$i] . '" target="_blank" >' .
$this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'title']) .
'</a>',
helper::dateUTF8(self::$dateFormat, $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])) . ' - ' . helper::dateUTF8(self::$timeFormat, $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])),
helper::dateUTF8(self::$dateFormat, $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn']), self::$i18nUI) . ' - ' . helper::dateUTF8(self::$timeFormat, $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn']), self::$i18nUI),
self::$states[$this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'state'])],
// Bouton pour afficher les commentaires de l'article
template::button('blogConfigComment' . $articleIds[$i], [

View File

@ -1,3 +1,8 @@
# Versions 7.8 - 7.9
- Le flux RSS ne fonctionne pas si les méta de la page sont vides.
# Version 7.7
- Contrôle de la variable de session liée au contenu. Evite des erreurs lorsque plusieurs onglets sont ouverts.
# Version 7.6
- Mise à jour RSS Feed
# Version 7.5

0
module/blog/ressource/feed-icon-16.gif Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 652 B

After

Width:  |  Height:  |  Size: 652 B

0
module/blog/vendor/FeedWriter/ATOM.php vendored Normal file → Executable file
View File

0
module/blog/vendor/FeedWriter/Feed.php vendored Normal file → Executable file
View File

0
module/blog/vendor/FeedWriter/InvalidOperationException.php vendored Normal file → Executable file
View File

0
module/blog/vendor/FeedWriter/Item.php vendored Normal file → Executable file
View File

0
module/blog/vendor/FeedWriter/README.md vendored Normal file → Executable file
View File

0
module/blog/vendor/FeedWriter/RSS1.php vendored Normal file → Executable file
View File

0
module/blog/vendor/FeedWriter/RSS2.php vendored Normal file → Executable file
View File

0
module/blog/vendor/furl/LICENSE vendored Normal file → Executable file
View File

0
module/blog/vendor/furl/README.md vendored Normal file → Executable file
View File

0
module/blog/vendor/furl/inc.json vendored Normal file → Executable file
View File

0
module/blog/vendor/furl/jquery.furl.js vendored Normal file → Executable file
View File

0
module/blog/view/add/add.css Normal file → Executable file
View File

0
module/blog/view/add/add.js.php Normal file → Executable file
View File

0
module/blog/view/add/add.php Normal file → Executable file
View File

0
module/blog/view/article/article.css Normal file → Executable file
View File

0
module/blog/view/article/article.js.php Normal file → Executable file
View File

0
module/blog/view/comment/comment.css Normal file → Executable file
View File

0
module/blog/view/comment/comment.js.php Normal file → Executable file
View File

0
module/blog/view/comment/comment.php Normal file → Executable file
View File

0
module/blog/view/config/config.css Normal file → Executable file
View File

0
module/blog/view/config/config.js.php Normal file → Executable file
View File

2
module/blog/view/config/config.php Normal file → Executable file
View File

@ -3,7 +3,7 @@
<div class="col1">
<?php echo template::button('blogConfigBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0), 'posts',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0) . '/' . self::$siteContent,
'value' => template::ico('left')
]); ?>
</div>

0
module/blog/view/edit/edit.css Normal file → Executable file
View File

0
module/blog/view/edit/edit.js.php Normal file → Executable file
View File

0
module/blog/view/edit/edit.php Normal file → Executable file
View File

0
module/blog/view/index/index.css Normal file → Executable file
View File

0
module/blog/view/option/option.css Normal file → Executable file
View File

0
module/blog/view/rss/rss.php Normal file → Executable file
View File

View File

@ -1,3 +1,5 @@
# Version 4.3
- Contrôle de la variable de session liée au contenu. Evite des erreurs lorsque plusieurs onglets sont ouverts.
# Version 4.2
- Termes des commandes de profils
# Version 4.1

View File

@ -17,7 +17,7 @@
class form extends common
{
const VERSION = '4.2';
const VERSION = '4.3';
const REALNAME = 'Formulaire';
const DATADIRECTORY = ''; // Contenu localisé inclus par défaut (page.json et module.json)

0
module/form/vendor/html-sortable/html-sortable.min.js vendored Normal file → Executable file
View File

0
module/form/vendor/html-sortable/inc.json vendored Normal file → Executable file
View File

0
module/form/vendor/html-sortable/lisezmoi.txt vendored Normal file → Executable file
View File

0
module/form/view/config/config.css Normal file → Executable file
View File

View File

@ -53,7 +53,7 @@
<div class="col1">
<?php echo template::button('formConfigBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0),
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0) . '/' . self::$siteContent,
'value' => template::ico('left')
]); ?>
</div>

0
module/form/view/data/data.css Normal file → Executable file
View File

View File

@ -1,3 +1,5 @@
# Version 4.2
- Contrôle de la variable de session liée au contenu. Evite des erreurs lorsque plusieurs onglets sont ouverts.
# Version 4.1
- Termes des commandes de profils
# Version 4.0

View File

@ -18,7 +18,7 @@ class gallery extends common
{
const VERSION = '4.1';
const VERSION = '4.2';
const REALNAME = 'Galerie';
const DATADIRECTORY = self::DATA_DIR . 'gallery/';

0
module/gallery/ressource/theme.css Normal file → Executable file
View File

0
module/gallery/ressource/vartheme.css Normal file → Executable file
View File

0
module/gallery/vendor/tablednd/inc.json vendored Normal file → Executable file
View File

0
module/gallery/vendor/tablednd/lisez-moi.txt vendored Normal file → Executable file
View File

0
module/gallery/vendor/tablednd/tablednd.min.js vendored Normal file → Executable file
View File

0
module/gallery/view/config/config.css Normal file → Executable file
View File

View File

@ -3,7 +3,7 @@
<div class="col1">
<?php echo template::button('galleryConfigBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0),
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0) . '/' . self::$siteContent,
'value' => template::ico('left')
]); ?>
</div>

0
module/gallery/view/edit/edit.css Normal file → Executable file
View File

0
module/gallery/view/theme/theme.css Normal file → Executable file
View File

View File

@ -1,3 +1,7 @@
# Versions 5.7 - 5.8
- Le flux RSS ne fonctionne pas si les méta de la page sont vides.
# Version 5.6
- Contrôle de la variable de session liée au contenu. Evite des erreurs lorsque plusieurs onglets sont ouverts.
# Version 5.5
- Mise à jour RSS Feed
# Version 5.4

View File

@ -16,7 +16,7 @@
class news extends common
{
const VERSION = '5.5';
const VERSION = '5.8';
const REALNAME = 'News';
const DATADIRECTORY = self::DATA_DIR . 'news/';
@ -124,9 +124,11 @@ class news extends common
$feeds = new \FeedWriter\RSS2();
// En-tête
$feeds->setTitle($this->getData(['page', $this->getUrl(0), 'title']));
$feeds->setTitle($this->getData(['page', $this->getUrl(0), 'title']) ? $this->getData(['page', $this->getUrl(0), 'title']): '');
$feeds->setLink(helper::baseUrl() . $this->getUrl(0));
$feeds->setDescription($this->getData(['page', $this->getUrl(0), 'metaDescription']));
if ($this->getData(['page', $this->getUrl(0), 'metaDescription'])) {
$feeds->setDescription($this->getData(['page', $this->getUrl(0), 'metaDescription']));
};
$feeds->setChannelElement('language', 'fr-FR');
$feeds->setDate(date('r', time()));
$feeds->addGenerator();

View File

@ -3,7 +3,7 @@
<div class="col1">
<?php echo template::button('newsConfigBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0),'posts',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0) . '/' . self::$siteContent,
'value' => template::ico('left')
]); ?>
</div>

Some files were not shown because too many files have changed in this diff Show More