From 4fb0528ea58eff63c479028bcffcae934c17fec7 Mon Sep 17 00:00:00 2001 From: Prof Langues Date: Tue, 9 Feb 2021 16:12:32 +0100 Subject: [PATCH 01/61] Init fichiers Sylvain --- core/module/config/config.php | 281 +++++++++++++++++- core/module/config/view/advanced/advanced.php | 1 + core/module/config/view/index/index.php | 9 +- core/module/config/view/modules/modules.css | 18 ++ .../module/config/view/modules/modules.js.php | 21 ++ core/module/config/view/modules/modules.php | 48 +++ 6 files changed, 374 insertions(+), 4 deletions(-) create mode 100644 core/module/config/view/modules/modules.css create mode 100644 core/module/config/view/modules/modules.js.php create mode 100644 core/module/config/view/modules/modules.php diff --git a/core/module/config/config.php b/core/module/config/config.php index 85f34738..5036f1de 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -29,9 +29,14 @@ class config extends common { 'logReset' => self::GROUP_ADMIN, 'logDownload'=> self::GROUP_ADMIN, 'blacklistReset' => self::GROUP_ADMIN, - 'blacklistDownload' => self::GROUP_ADMIN + 'blacklistDownload' => self::GROUP_ADMIN, + 'modules' => self::GROUP_ADMIN, + 'moduleDelete' => self::GROUP_ADMIN ]; + + public static $modInstal = []; + public static $str; public static $timezones = [ 'Pacific/Midway' => '(GMT-11:00) Midway Island', @@ -579,9 +584,10 @@ class config extends common { // Générer robots.txt et sitemap $this->generateFiles(); // Valeurs en sortie + $notification = $notification . 'Modifications enregistrées'; $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(), - 'notification' => 'Modifications enregistrées', + 'notification' => $notification, 'state' => $success ]); } @@ -591,7 +597,216 @@ class config extends common { 'view' => 'advanced' ]); } - + + /* + * Installation de modules à partir d'un zip normalisé + * Affichage des modules installés + */ + public function modules() { + + // Préparation du tableau des modules installés + // Liste des modules installés (répertoire de module/) + if ($dh = opendir( 'module/' )) { + $i=0; + while (($dirmodule = readdir($dh)) !== false) { + if( $dirmodule !== '.' && $dirmodule !== '..'){ + self::$modInstal[$i][0] = $dirmodule; + self::$modInstal[$i][1] = page::$moduleNames[$dirmodule]; + // Lecture de la version pour les modules officiels et distribués + $blogversion = blog::BLOG_VERSION; + $formversion = form::FORM_VERSION; + $galleryversion = gallery::GALLERY_VERSION; + $newsversion = news::NEWS_VERSION; + $redirectionversion = redirection::REDIRECTION_VERSION; + $searchversion = search::SEARCH_VERSION; + self::$str = $dirmodule.'version'; + self::$modInstal[$i][2] = '?'; + if( ${self::$str} !== null){ + self::$modInstal[$i][2] = ${self::$str}; + } + // Lecture de la version pour les modules non distribués + elseif($this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]) !== null){ + self::$modInstal[$i][2] = $this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]); + } + self::$modInstal[$i][3] = 'non'; + self::$modInstal[$i][4] = ''; + self::$modInstal[$i][5] = ''; + $i++; + } + } + closedir($dh); + } + // Module utilisé ? + $nb = count(self::$modInstal); + for ($i = 0; $i < $nb; $i++) { + foreach( $this->getData(['page']) as $keyPage=>$valuePage){ + if( $valuePage['moduleId'] === self::$modInstal[$i][0]){ + self::$modInstal[$i][3] = 'oui'; + if(self::$modInstal[$i][4] !==''){ + self::$modInstal[$i][4] = self::$modInstal[$i][4].'
'.$valuePage['title']; + } + else{ + self::$modInstal[$i][4] = $valuePage['title']; + } + } + } + $modulesDistrib = array('blog', 'form', 'gallery', 'news', 'redirection', 'search'); + if( self::$modInstal[$i][4] =='' && array_search( self::$modInstal[$i][0], $modulesDistrib ) === false + && $this->getData(['module', '_gestion_modules_', self::$modInstal[$i][0], 'delete' ]) === true){ + self::$modInstal[$i][5] = template::button('moduleDelete' . self::$modInstal[$i][0], [ + 'class' => 'moduleDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]); + + } + } + + // Retour du formulaire ? + if($this->isPost()) { + // Installation d'un module + $success = true; + $checkValidMaj = $this->getInput('configModulesCheck', helper::FILTER_BOOLEAN); + $zipFilename = $this->getInput('configModulesInstallation', helper::FILTER_STRING_SHORT); + if( $zipFilename !== ''){ + $tempFolder = uniqid(); + $zip = new ZipArchive(); + if ($zip->open(self::FILE_DIR.'source/'.$zipFilename) === TRUE) { + $notification = 'Archive ouverte'; + mkdir (self::TEMP_DIR . $tempFolder); + $zip->extractTo(self::TEMP_DIR . $tempFolder ); + // Archive de module ? + $success = false; + $notification = 'Ce n\'est pas l\'archive d\'un module !'; + $moduleDir = self::TEMP_DIR . $tempFolder . '/module'; + $moduleName = ''; + if ( is_dir( $moduleDir )) { + // Lire le nom du module + if ($dh = opendir( $moduleDir )) { + while (($file = readdir($dh)) !== false) { + $moduleName = $file; + } + closedir($dh); + } + // Module normalisé ? + if( is_file( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php' ) AND is_file( $moduleDir.'/'.$moduleName.'/view/index/index.php' ) ){ + + // Lecture de info.json et mémorisation des 3 paramètres version, update et delete + $version = '?'; + $update = '?'; + $delete = false; + if( is_file( $moduleDir.'/'.$moduleName.'/info/info.json' )){ + $json = file_get_contents( $moduleDir.'/'.$moduleName.'/info/info.json' ); + $param = json_decode( $json, true); + if( $param['module'] === $moduleName && is_bool($param['update']) && is_bool($param['update'])){ + $version = $param['version']; + $update = $param['update']; + $delete = $param['delete']; + } + } + $this->setData(['module','_gestion_modules_',$moduleName, 'version', $version]); + $this->setData(['module','_gestion_modules_',$moduleName, 'update', $update]); + $this->setData(['module','_gestion_modules_',$moduleName, 'delete', $delete]); + + // Module déjà installé ? + $moduleInstal = false; + foreach( self::$modInstal as $key=>$value){ + if($moduleName === $value[0]){ + if( $value[3] !== 'non'){ + $notification = 'Module déjà installé et utilisé page '.$value[4]; + } + else{ + $notification = 'Module déjà installé et non utilisé'; + } + $moduleInstal = true; + } + } + $validMaj = $checkValidMaj; + if(is_bool($update)){ + $validMaj = $checkValidMaj && $update; + } + + // Nouvelle installation ou mise à jour du module avec validation du concepteur et validation de l'utilisateur + if( ! $moduleInstal || ( $moduleInstal && $validMaj )){ + // Copie récursive des dossiers + $this -> custom_copy( self::TEMP_DIR . $tempFolder, './' ); + $success = true; + if( ! $moduleInstal ){ + $notification = 'Module '.$moduleName.' installé'; + } + else{ + $notification = 'Module '.$moduleName.' mis à jour'; + } + } + else{ + $success = false; + $notification = ' Vous devez cocher la case "Valider la mise à jour d\'un module déjà installé"'; + if( $update === false){ + $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; + } + } + } + } + // Supprimer le dossier temporaire même si le module est invalide + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + } else { + // erreur à l'ouverture + $success = false; + $notification = 'Impossible d\'ouvrir l\'archive'; + } + } + + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(), + 'notification' => $notification, + 'state' => $success + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Gestion des modules', + 'view' => 'modules' + ]); + } + + /* + * + * Effacement d'un module installé et non utilisé + */ + public function moduleDelete() { + + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'config/modules', + 'state' => false, + 'notification' => 'Action non autorisée' + ]); + } + else{ + // suppression de la clef version du module + $this->deleteData(['module', '_gestion_modules_', $this->getUrl(2)]); + // Suppression des dossiers + if( $this->delete_directory('./module/'.$this->getUrl(2)) === true){ + $success = true; + $notification = 'Module '.$this->getUrl(2) .' effacé du dossier /module/, il peut rester des données dans d\'autres dossiers'; + } + else{ + $success = false; + $notification = 'La suppression a échouée'; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'config/modules', + 'notification' => $notification, + 'state' => $success + ]); + } + } + + public function script() { // Soumission du formulaire if($this->isPost()) { @@ -812,5 +1027,65 @@ class config extends common { } return $newArray; } + + + /* + * Copie récursive de dossiers + * + */ + private function custom_copy($src, $dst) { + // open the source directory + $dir = opendir($src); + // Make the destination directory if not exist + @mkdir($dst); + // Loop through the files in source directory + while( $file = readdir($dir) ) { + if (( $file != '.' ) && ( $file != '..' )) { + if ( is_dir($src . '/' . $file) ){ + // Recursively calling custom copy function + // for sub directory + $this -> custom_copy($src . '/' . $file, $dst . '/' . $file); + } + else { + copy($src . '/' . $file, $dst . '/' . $file); + } + } + } + closedir($dir); + } + + /* + * + * Suppression d'un dossier et de ses sous-dossiers + */ + private function delete_directory($directory, $empty = false) { + if(substr($directory,-1) == "/") { + $directory = substr($directory,0,-1); + } + if(!file_exists($directory) || !is_dir($directory)) { + return false; + } elseif(!is_readable($directory)) { + return false; + } else { + $directoryHandle = opendir($directory); + while ($contents = readdir($directoryHandle)) { + if($contents != '.' && $contents != '..') { + $path = $directory . "/" . $contents; + if(is_dir($path)) { + $this->delete_directory($path); + } else { + unlink($path); + } + } + } + closedir($directoryHandle); + if($empty == false) { + if(!rmdir($directory)) { + return false; + } + } + return true; + } + } } diff --git a/core/module/config/view/advanced/advanced.php b/core/module/config/view/advanced/advanced.php index 06718e43..0d11fe06 100644 --- a/core/module/config/view/advanced/advanced.php +++ b/core/module/config/view/advanced/advanced.php @@ -504,4 +504,5 @@ + diff --git a/core/module/config/view/index/index.php b/core/module/config/view/index/index.php index 42b8b8ae..0985a251 100755 --- a/core/module/config/view/index/index.php +++ b/core/module/config/view/index/index.php @@ -8,7 +8,14 @@ 'value' => 'Accueil' ]); ?> -
+
+ helper::baseUrl() . 'config/modules', + 'value' => 'Modules', + 'ico' => 'download', + ]); ?> +
+
helper::baseUrl() . 'config/advanced', 'value' => 'Avancée', diff --git a/core/module/config/view/modules/modules.css b/core/module/config/view/modules/modules.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/core/module/config/view/modules/modules.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/core/module/config/view/modules/modules.js.php b/core/module/config/view/modules/modules.js.php new file mode 100644 index 00000000..222b85a1 --- /dev/null +++ b/core/module/config/view/modules/modules.js.php @@ -0,0 +1,21 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Confirmation de suppression + */ +$(".moduleDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer, effacer ce module ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/core/module/config/view/modules/modules.php b/core/module/config/view/modules/modules.php new file mode 100644 index 00000000..9ffe9b65 --- /dev/null +++ b/core/module/config/view/modules/modules.php @@ -0,0 +1,48 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . 'config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ 'Valider', + 'ico' => 'check' + ]); ?> +
+
+
+
+
+

Installer un module

+
+
+ 'Archive ZIP :', + 'type' => 2 + ]); ?> +
+
+
+
+ false, + 'help' => 'Vérifier sur le forum que ce module supporte la mise à jour par réinstallation des fichiers.', + ]); ?> +
+
+
+
+
+ + + + + + + + \ No newline at end of file From dde3a1c6a2a2d5f3523005b6adedbc1d173da05a Mon Sep 17 00:00:00 2001 From: Prof Langues Date: Tue, 9 Feb 2021 18:04:24 +0100 Subject: [PATCH 02/61] fonction getModules --- core/class/helper.class.php | 35 +++++++++++++++++++++++ core/module/config/config.php | 13 +++++---- core/module/page/page.php | 28 ++---------------- core/module/page/view/edit/edit.php | 2 +- module/blog/blog.php | 3 +- module/blog/view/config/config.php | 2 +- module/form/form.php | 3 +- module/form/view/config/config.php | 2 +- module/form/view/data/data.php | 2 +- module/gallery/gallery.php | 4 ++- module/gallery/view/config/config.php | 2 +- module/gallery/view/edit/edit.php | 2 +- module/gallery/view/theme/theme.php | 2 +- module/news/news.php | 4 ++- module/news/view/config/config.php | 2 +- module/redirection/redirection.php | 3 +- module/redirection/view/config/config.php | 2 +- module/search/search.php | 3 +- module/search/view/config/config.php | 2 +- 19 files changed, 69 insertions(+), 47 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 396208ec..4ce97ef5 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -127,6 +127,41 @@ class helper { return ($fileName); } + + + /** + * Retourne la liste des modules installés dans un tableau composé + * du nom réel + * du numéro de version + */ + public static function getModules() { + $dirs = array_diff(scandir('module'), array('..', '.')); + foreach ($dirs as $key => $value) { + // Lire les constantes + $class_reflex = new \ReflectionClass($value); + $class_constants = $class_reflex->getConstants(); + // Constante REALNAME + if (array_key_exists('REALNAME', $class_constants)) { + $realName = $value::REALNAME; + } else { + $realName = ucfirst($value); + } + // Constante VERSION + if (array_key_exists('VERSION', $class_constants)) { + $version = $value::VERSION; + } else { + $version = '0.0'; + } + // Affection + $modules [$value] = [ + 'realName' => $realName, + 'version' => $version + ]; + } + return($modules); + } + + /** * Retourne true si le protocole est en TLS * @return bool diff --git a/core/module/config/config.php b/core/module/config/config.php index 5036f1de..79c03d23 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -604,6 +604,7 @@ class config extends common { */ public function modules() { + helper::getModules(); // Préparation du tableau des modules installés // Liste des modules installés (répertoire de module/) if ($dh = opendir( 'module/' )) { @@ -613,12 +614,12 @@ class config extends common { self::$modInstal[$i][0] = $dirmodule; self::$modInstal[$i][1] = page::$moduleNames[$dirmodule]; // Lecture de la version pour les modules officiels et distribués - $blogversion = blog::BLOG_VERSION; - $formversion = form::FORM_VERSION; - $galleryversion = gallery::GALLERY_VERSION; - $newsversion = news::NEWS_VERSION; - $redirectionversion = redirection::REDIRECTION_VERSION; - $searchversion = search::SEARCH_VERSION; + $blogversion = blog::VERSION; + $formversion = form::VERSION; + $galleryversion = gallery::VERSION; + $newsversion = news::VERSION; + $redirectionversion = redirection::VERSION; + $searchversion = search::VERSION; self::$str = $dirmodule.'version'; self::$modInstal[$i][2] = '?'; if( ${self::$str} !== null){ diff --git a/core/module/page/page.php b/core/module/page/page.php index 88e6b37f..f59c79b5 100755 --- a/core/module/page/page.php +++ b/core/module/page/page.php @@ -29,15 +29,7 @@ class page extends common { '' => 'Aucune' ]; public static $moduleIds = []; - // Nom des modules - public static $moduleNames = [ - 'news' => 'Nouvelles', - 'blog' => 'Blog', - 'form' => 'Formulaire', - 'gallery' => 'Galerie', - 'redirection' => 'Redirection', - 'search' => 'Recherche' - ]; + public static $typeMenu = [ 'text' => 'Texte', 'icon' => 'Icône', @@ -448,22 +440,8 @@ class page extends common { 'state' => true ]); } - } - // Liste des modules - $moduleIds = []; - $iterator = new DirectoryIterator('module/'); - foreach($iterator as $fileInfos) { - if(is_file($fileInfos->getPathname() . '/' . $fileInfos->getFilename() . '.php')) { - if (array_key_exists($fileInfos->getBasename(),self::$moduleNames)) { - $moduleIds[$fileInfos->getBasename()] = self::$moduleNames[$fileInfos->getBasename()]; - } else { - $moduleIds[$fileInfos->getBasename()] = ucfirst($fileInfos->getBasename()); - } - } - } - self::$moduleIds = $moduleIds; - asort(self::$moduleIds); - self::$moduleIds = array_merge( ['' => 'Aucun'] , self::$moduleIds); + } + self::$moduleIds = array_merge( ['' => 'Aucun'] , helper::arrayCollumn(helper::getModules(),'realName','SORT_ASC')); // Pages sans parent foreach($this->getHierarchy() as $parentPageId => $childrenPageIds) { if($parentPageId !== $this->getUrl(2)) { diff --git a/core/module/page/view/edit/edit.php b/core/module/page/view/edit/edit.php index cac97d04..be3941f2 100755 --- a/core/module/page/view/edit/edit.php +++ b/core/module/page/view/edit/edit.php @@ -54,7 +54,7 @@ echo template::formOpen('pageEditForm'); ]); ?> $this->getData(['page', $this->getUrl(2), 'moduleId'])]); ?> array_key_exists($this->getData(['page', $this->getUrl(2), 'moduleId']),$module::$moduleNames)? $module::$moduleNames[$this->getData(['page', $this->getUrl(2), 'moduleId'])] : ucfirst($this->getData(['page', $this->getUrl(2), 'moduleId'])) + 'value' => array_key_exists($this->getData(['page', $this->getUrl(2), 'moduleId']),$module::$moduleIds)? $module::$moduleIds[$this->getData(['page', $this->getUrl(2), 'moduleId'])] : ucfirst($this->getData(['page', $this->getUrl(2), 'moduleId'])) ]); ?>
diff --git a/module/blog/blog.php b/module/blog/blog.php index 110d92f0..6b83a8db 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -87,7 +87,8 @@ class blog extends common { public static $users = []; - const BLOG_VERSION = '4.2'; + const VERSION = '4.2'; + const REALNAME = 'Blog'; /** * Flux RSS diff --git a/module/blog/view/config/config.php b/module/blog/view/config/config.php index 7830d8fd..fee5671a 100755 --- a/module/blog/view/config/config.php +++ b/module/blog/view/config/config.php @@ -47,6 +47,6 @@
Version n° - +
diff --git a/module/form/form.php b/module/form/form.php index a47a0ec7..fd66b16a 100755 --- a/module/form/form.php +++ b/module/form/form.php @@ -32,7 +32,8 @@ class form extends common { public static $pagination; - const FORM_VERSION = '2.7'; + const VERSION = '2.7'; + const REALNAME = 'Formulaire'; // Objets const TYPE_MAIL = 'mail'; diff --git a/module/form/view/config/config.php b/module/form/view/config/config.php index 5d2e8946..fea6d9ff 100755 --- a/module/form/view/config/config.php +++ b/module/form/view/config/config.php @@ -164,5 +164,5 @@
Version n° - +
diff --git a/module/form/view/data/data.php b/module/form/view/data/data.php index c60511b4..947e20db 100755 --- a/module/form/view/data/data.php +++ b/module/form/view/data/data.php @@ -26,5 +26,5 @@
Version n° - +
\ No newline at end of file diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 77d0f2c3..e8526b7c 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -19,7 +19,9 @@ class gallery extends common { const SORT_ASC = 'SORT_ASC'; const SORT_DSC = 'SORT_DSC'; const SORT_HAND = 'SORT_HAND'; - const GALLERY_VERSION = '2.5'; + + const VERSION = '2.5'; + const REALNAME = 'Galerie'; public static $directories = []; diff --git a/module/gallery/view/config/config.php b/module/gallery/view/config/config.php index 0c41378b..91400a98 100755 --- a/module/gallery/view/config/config.php +++ b/module/gallery/view/config/config.php @@ -58,6 +58,6 @@
Version n° - +
diff --git a/module/gallery/view/edit/edit.php b/module/gallery/view/edit/edit.php index 9b243d32..c745d1e5 100755 --- a/module/gallery/view/edit/edit.php +++ b/module/gallery/view/edit/edit.php @@ -64,6 +64,6 @@
Version n° - +
diff --git a/module/gallery/view/theme/theme.php b/module/gallery/view/theme/theme.php index 8ada32ed..694ecaf9 100755 --- a/module/gallery/view/theme/theme.php +++ b/module/gallery/view/theme/theme.php @@ -139,7 +139,7 @@
Version n° - +
\ No newline at end of file diff --git a/module/news/news.php b/module/news/news.php index 13fcb2fa..d65c2860 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -33,10 +33,12 @@ class news extends common { false => 'Brouillon', true => 'Publié' ]; - const NEWS_VERSION = '2.0'; public static $users = []; + const VERSION = '2.0'; + const REALNAME = 'Nouvelles'; + /** * Flux RSS */ diff --git a/module/news/view/config/config.php b/module/news/view/config/config.php index f25fe3d0..73929b9d 100755 --- a/module/news/view/config/config.php +++ b/module/news/view/config/config.php @@ -48,5 +48,5 @@
Version n° - +
\ No newline at end of file diff --git a/module/redirection/redirection.php b/module/redirection/redirection.php index 5c92521c..97a5e6ea 100755 --- a/module/redirection/redirection.php +++ b/module/redirection/redirection.php @@ -19,7 +19,8 @@ class redirection extends common { 'index' => self::GROUP_VISITOR ]; - const REDIRECTION_VERSION = '1.4'; + const VERSION = '1.4'; + const REALNAME = 'Redirection'; /** * Configuration diff --git a/module/redirection/view/config/config.php b/module/redirection/view/config/config.php index 72071f4c..ff421b39 100755 --- a/module/redirection/view/config/config.php +++ b/module/redirection/view/config/config.php @@ -37,5 +37,5 @@
Version n° - +
\ No newline at end of file diff --git a/module/search/search.php b/module/search/search.php index f84dfdeb..7952edd8 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -38,7 +38,8 @@ class search extends common { 400 => '400 caractères', ]; - const SEARCH_VERSION = '1.2'; + const VERSION = '1.2'; + const REALNAME = 'Recherche'; // Configuration vide public function config() { diff --git a/module/search/view/config/config.php b/module/search/view/config/config.php index 37a60653..f54674d7 100755 --- a/module/search/view/config/config.php +++ b/module/search/view/config/config.php @@ -68,5 +68,5 @@
Version n° - +
\ No newline at end of file From c648d328d6c10bf722e98449e96a7c4f27ca61d4 Mon Sep 17 00:00:00 2001 From: Prof Langues Date: Tue, 9 Feb 2021 18:20:53 +0100 Subject: [PATCH 03/61] appel en trop --- core/module/config/config.php | 1 - 1 file changed, 1 deletion(-) diff --git a/core/module/config/config.php b/core/module/config/config.php index 79c03d23..9faf5392 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -604,7 +604,6 @@ class config extends common { */ public function modules() { - helper::getModules(); // Préparation du tableau des modules installés // Liste des modules installés (répertoire de module/) if ($dh = opendir( 'module/' )) { From 3f6889763923787f1738fe7fdb20618001fcffb9 Mon Sep 17 00:00:00 2001 From: Prof Langues Date: Wed, 10 Feb 2021 16:59:17 +0100 Subject: [PATCH 04/61] scanSubDir and check empty folder --- core/class/helper.class.php | 59 +++++++++++++++++++++++++------------ module/gallery/gallery.php | 22 +------------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 4ce97ef5..3505241e 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -137,30 +137,51 @@ class helper { public static function getModules() { $dirs = array_diff(scandir('module'), array('..', '.')); foreach ($dirs as $key => $value) { - // Lire les constantes - $class_reflex = new \ReflectionClass($value); - $class_constants = $class_reflex->getConstants(); - // Constante REALNAME - if (array_key_exists('REALNAME', $class_constants)) { - $realName = $value::REALNAME; - } else { - $realName = ucfirst($value); + // Dossier non vide + if (file_exists('module/' . $value . '/' . $value . '.php')) { + // Lire les constantes + $class_reflex = new \ReflectionClass($value); + $class_constants = $class_reflex->getConstants(); + // Constante REALNAME + if (array_key_exists('REALNAME', $class_constants)) { + $realName = $value::REALNAME; + } else { + $realName = ucfirst($value); + } + // Constante VERSION + if (array_key_exists('VERSION', $class_constants)) { + $version = $value::VERSION; + } else { + $version = '0.0'; + } + // Affection + $modules [$value] = [ + 'realName' => $realName, + 'version' => $version + ]; } - // Constante VERSION - if (array_key_exists('VERSION', $class_constants)) { - $version = $value::VERSION; - } else { - $version = '0.0'; - } - // Affection - $modules [$value] = [ - 'realName' => $realName, - 'version' => $version - ]; } return($modules); } + + /** + * Scanne le contenu d'un dossier et de ses sous-dossiers + * @param string $dir Dossier à scanner + * @return array + */ + public static function scanSubDir($dir) { + $dirContent = []; + $iterator = new DirectoryIterator($dir); + foreach($iterator as $fileInfos) { + if($fileInfos->isDot() === false AND $fileInfos->isDir()) { + $dirContent[] = $dir . '/' . $fileInfos->getBasename(); + $dirContent = array_merge($dirContent, self::scanSubDir($dir . '/' . $fileInfos->getBasename())); + } + } + return $dirContent; + } + /** * Retourne true si le protocole est en TLS diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index e8526b7c..7156931c 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -324,7 +324,7 @@ class gallery extends common { // Valeurs en sortie $this->addOutput([ 'display' => self::DISPLAY_JSON, - 'content' => galleriesHelper::scanDir(self::FILE_DIR.'source') + 'content' => helper::scanSubDir(self::FILE_DIR.'source') ]); } @@ -673,24 +673,4 @@ class gallery extends common { ]); } -} - -class galleriesHelper extends helper { - - /** - * Scan le contenu d'un dossier et de ses sous-dossiers - * @param string $dir Dossier à scanner - * @return array - */ - public static function scanDir($dir) { - $dirContent = []; - $iterator = new DirectoryIterator($dir); - foreach($iterator as $fileInfos) { - if($fileInfos->isDot() === false AND $fileInfos->isDir()) { - $dirContent[] = $dir . '/' . $fileInfos->getBasename(); - $dirContent = array_merge($dirContent, self::scanDir($dir . '/' . $fileInfos->getBasename())); - } - } - return $dirContent; - } } \ No newline at end of file From 1cad66691c899a754cd433c569bff76e66a44dd1 Mon Sep 17 00:00:00 2001 From: Prof Langues Date: Wed, 10 Feb 2021 17:04:41 +0100 Subject: [PATCH 05/61] Commentaire --- core/class/helper.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 3505241e..ae3fd0bb 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -168,7 +168,7 @@ class helper { /** * Scanne le contenu d'un dossier et de ses sous-dossiers * @param string $dir Dossier à scanner - * @return array + * @return array liste de dossiers contenus dans le répertoire cible. */ public static function scanSubDir($dir) { $dirContent = []; From 8dff1cd069d33920fa8fcf8ebd4fd532bf676aa3 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Wed, 10 Feb 2021 17:58:08 +0100 Subject: [PATCH 06/61] scandir original --- core/class/helper.class.php | 17 ----------------- core/core.php | 2 +- module/gallery/gallery.php | 22 +++++++++++++++++++++- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index ae3fd0bb..562d3897 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -164,23 +164,6 @@ class helper { return($modules); } - - /** - * Scanne le contenu d'un dossier et de ses sous-dossiers - * @param string $dir Dossier à scanner - * @return array liste de dossiers contenus dans le répertoire cible. - */ - public static function scanSubDir($dir) { - $dirContent = []; - $iterator = new DirectoryIterator($dir); - foreach($iterator as $fileInfos) { - if($fileInfos->isDot() === false AND $fileInfos->isDir()) { - $dirContent[] = $dir . '/' . $fileInfos->getBasename(); - $dirContent = array_merge($dirContent, self::scanSubDir($dir . '/' . $fileInfos->getBasename())); - } - } - return $dirContent; - } /** diff --git a/core/core.php b/core/core.php index 7246dac0..d21b9ccf 100755 --- a/core/core.php +++ b/core/core.php @@ -44,7 +44,7 @@ class common { const ACCESS_TIMER = 1800; // Numéro de version - const ZWII_VERSION = '10.4.01'; + const ZWII_VERSION = '10.4.02.modules'; const ZWII_UPDATE_CHANNEL = "v10"; public static $actions = []; diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 7156931c..e8526b7c 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -324,7 +324,7 @@ class gallery extends common { // Valeurs en sortie $this->addOutput([ 'display' => self::DISPLAY_JSON, - 'content' => helper::scanSubDir(self::FILE_DIR.'source') + 'content' => galleriesHelper::scanDir(self::FILE_DIR.'source') ]); } @@ -673,4 +673,24 @@ class gallery extends common { ]); } +} + +class galleriesHelper extends helper { + + /** + * Scan le contenu d'un dossier et de ses sous-dossiers + * @param string $dir Dossier à scanner + * @return array + */ + public static function scanDir($dir) { + $dirContent = []; + $iterator = new DirectoryIterator($dir); + foreach($iterator as $fileInfos) { + if($fileInfos->isDot() === false AND $fileInfos->isDir()) { + $dirContent[] = $dir . '/' . $fileInfos->getBasename(); + $dirContent = array_merge($dirContent, self::scanDir($dir . '/' . $fileInfos->getBasename())); + } + } + return $dirContent; + } } \ No newline at end of file From fed10aa71daf5f45e9a8f909f9344b0e921fe8bb Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Thu, 11 Feb 2021 10:31:58 +0100 Subject: [PATCH 07/61] getmodules gestion des erreurs --- core/class/helper.class.php | 49 ++++++++++++++++++++----------------- module/gps/gps.php | 0 2 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 module/gps/gps.php diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 562d3897..2ef6ab81 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -134,31 +134,36 @@ class helper { * du nom réel * du numéro de version */ - public static function getModules() { - $dirs = array_diff(scandir('module'), array('..', '.')); + public static function getModules($folder = 'module') { + + $dirs = array_diff(scandir($folder), array('..', '.')); foreach ($dirs as $key => $value) { // Dossier non vide - if (file_exists('module/' . $value . '/' . $value . '.php')) { + if (file_exists($folder . '/' . $value . '/' . $value . '.php')) { // Lire les constantes - $class_reflex = new \ReflectionClass($value); - $class_constants = $class_reflex->getConstants(); - // Constante REALNAME - if (array_key_exists('REALNAME', $class_constants)) { - $realName = $value::REALNAME; - } else { - $realName = ucfirst($value); - } - // Constante VERSION - if (array_key_exists('VERSION', $class_constants)) { - $version = $value::VERSION; - } else { - $version = '0.0'; - } - // Affection - $modules [$value] = [ - 'realName' => $realName, - 'version' => $version - ]; + try { + $class_reflex = new \ReflectionClass($value); + $class_constants = $class_reflex->getConstants(); + // Constante REALNAME + if (array_key_exists('REALNAME', $class_constants)) { + $realName = $value::REALNAME; + } else { + $realName = ucfirst($value); + } + // Constante VERSION + if (array_key_exists('VERSION', $class_constants)) { + $version = $value::VERSION; + } else { + $version = '0.0'; + } + // Affection + $modules [$value] = [ + 'realName' => $realName, + 'version' => $version + ]; + } catch (Exception $e){ + // on ne fait rien + } } } return($modules); diff --git a/module/gps/gps.php b/module/gps/gps.php new file mode 100644 index 00000000..e69de29b From 696d38b1f456e5bff70ee28a4d849903adfc68df Mon Sep 17 00:00:00 2001 From: fredtempez Date: Sun, 14 Feb 2021 11:53:11 +0100 Subject: [PATCH 08/61] getModules --- core/class/helper.class.php | 70 +++++++++++++++++------------- core/core.php | 2 +- core/module/config/config.php | 82 +++++++++++++++++------------------ core/module/page/page.php | 5 +-- 4 files changed, 85 insertions(+), 74 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 2ef6ab81..ae41d8a9 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -1,4 +1,5 @@ $value) { + // Dossier non vide + if (file_exists($folder . '/' . $value . '/' . $value . '.php')) { + // Lire les constantes en gérant les erreurs de nom de classe + try { + // Chargement des classes externes + if ($folder !== 'module') { + include_once ($folder . '/' . $value . '/' . $value . '.php'); + if ( class_exists($value) ) { + $e = new $value; + } + } + $class_reflex = new \ReflectionClass($value); + $class_constants = $class_reflex->getConstants(); + // Constante REALNAME + if (array_key_exists('REALNAME', $class_constants)) { + $realName = $value::REALNAME; + } else { + $realName = ucfirst($value); + } + // Constante VERSION + if (array_key_exists('VERSION', $class_constants)) { + $version = $value::VERSION; + } else { + $version = '0.0'; + } + // Affection + $modules [$value] = [ + 'realName' => $realName, + 'version' => $version + ]; - $dirs = array_diff(scandir($folder), array('..', '.')); - foreach ($dirs as $key => $value) { - // Dossier non vide - if (file_exists($folder . '/' . $value . '/' . $value . '.php')) { - // Lire les constantes - try { - $class_reflex = new \ReflectionClass($value); - $class_constants = $class_reflex->getConstants(); - // Constante REALNAME - if (array_key_exists('REALNAME', $class_constants)) { - $realName = $value::REALNAME; - } else { - $realName = ucfirst($value); + } catch (Exception $e){ + // on ne fait rien } - // Constante VERSION - if (array_key_exists('VERSION', $class_constants)) { - $version = $value::VERSION; - } else { - $version = '0.0'; - } - // Affection - $modules [$value] = [ - 'realName' => $realName, - 'version' => $version - ]; - } catch (Exception $e){ - // on ne fait rien - } + } } } return($modules); diff --git a/core/core.php b/core/core.php index d21b9ccf..72203ed1 100755 --- a/core/core.php +++ b/core/core.php @@ -44,7 +44,7 @@ class common { const ACCESS_TIMER = 1800; // Numéro de version - const ZWII_VERSION = '10.4.02.modules'; + const ZWII_VERSION = '10.5.00'; const ZWII_UPDATE_CHANNEL = "v10"; public static $actions = []; diff --git a/core/module/config/config.php b/core/module/config/config.php index 9faf5392..99af0760 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -34,7 +34,7 @@ class config extends common { 'moduleDelete' => self::GROUP_ADMIN ]; - + public static $modInstal = []; public static $str; @@ -597,13 +597,13 @@ class config extends common { 'view' => 'advanced' ]); } - + /* * Installation de modules à partir d'un zip normalisé * Affichage des modules installés */ public function modules() { - + var_dump(helper::getModules ()); // Préparation du tableau des modules installés // Liste des modules installés (répertoire de module/) if ($dh = opendir( 'module/' )) { @@ -611,11 +611,11 @@ class config extends common { while (($dirmodule = readdir($dh)) !== false) { if( $dirmodule !== '.' && $dirmodule !== '..'){ self::$modInstal[$i][0] = $dirmodule; - self::$modInstal[$i][1] = page::$moduleNames[$dirmodule]; + self::$modInstal[$i][1] = page::$moduleNames[$dirmodule]; // Lecture de la version pour les modules officiels et distribués $blogversion = blog::VERSION; $formversion = form::VERSION; - $galleryversion = gallery::VERSION; + $galleryversion = gallery::VERSION; $newsversion = news::VERSION; $redirectionversion = redirection::VERSION; $searchversion = search::VERSION; @@ -627,7 +627,7 @@ class config extends common { // Lecture de la version pour les modules non distribués elseif($this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]) !== null){ self::$modInstal[$i][2] = $this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]); - } + } self::$modInstal[$i][3] = 'non'; self::$modInstal[$i][4] = ''; self::$modInstal[$i][5] = ''; @@ -652,16 +652,16 @@ class config extends common { } $modulesDistrib = array('blog', 'form', 'gallery', 'news', 'redirection', 'search'); if( self::$modInstal[$i][4] =='' && array_search( self::$modInstal[$i][0], $modulesDistrib ) === false - && $this->getData(['module', '_gestion_modules_', self::$modInstal[$i][0], 'delete' ]) === true){ + && $this->getData(['module', '_gestion_modules_', self::$modInstal[$i][0], 'delete' ]) === true){ self::$modInstal[$i][5] = template::button('moduleDelete' . self::$modInstal[$i][0], [ 'class' => 'moduleDelete buttonRed', 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], 'value' => template::ico('cancel') ]); - + } } - + // Retour du formulaire ? if($this->isPost()) { // Installation d'un module @@ -681,7 +681,7 @@ class config extends common { $moduleDir = self::TEMP_DIR . $tempFolder . '/module'; $moduleName = ''; if ( is_dir( $moduleDir )) { - // Lire le nom du module + // Lire le nom du module if ($dh = opendir( $moduleDir )) { while (($file = readdir($dh)) !== false) { $moduleName = $file; @@ -690,7 +690,7 @@ class config extends common { } // Module normalisé ? if( is_file( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php' ) AND is_file( $moduleDir.'/'.$moduleName.'/view/index/index.php' ) ){ - + // Lecture de info.json et mémorisation des 3 paramètres version, update et delete $version = '?'; $update = '?'; @@ -707,7 +707,7 @@ class config extends common { $this->setData(['module','_gestion_modules_',$moduleName, 'version', $version]); $this->setData(['module','_gestion_modules_',$moduleName, 'update', $update]); $this->setData(['module','_gestion_modules_',$moduleName, 'delete', $delete]); - + // Module déjà installé ? $moduleInstal = false; foreach( self::$modInstal as $key=>$value){ @@ -725,7 +725,7 @@ class config extends common { if(is_bool($update)){ $validMaj = $checkValidMaj && $update; } - + // Nouvelle installation ou mise à jour du module avec validation du concepteur et validation de l'utilisateur if( ! $moduleInstal || ( $moduleInstal && $validMaj )){ // Copie récursive des dossiers @@ -756,7 +756,7 @@ class config extends common { $notification = 'Impossible d\'ouvrir l\'archive'; } } - + $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(), 'notification' => $notification, @@ -769,13 +769,13 @@ class config extends common { 'view' => 'modules' ]); } - + /* * * Effacement d'un module installé et non utilisé */ public function moduleDelete() { - + // Jeton incorrect if ($this->getUrl(3) !== $_SESSION['csrf']) { // Valeurs en sortie @@ -805,8 +805,8 @@ class config extends common { ]); } } - - + + public function script() { // Soumission du formulaire if($this->isPost()) { @@ -1027,31 +1027,31 @@ class config extends common { } return $newArray; } - - + + /* - * Copie récursive de dossiers + * Copie récursive de dossiers * */ - private function custom_copy($src, $dst) { - // open the source directory - $dir = opendir($src); - // Make the destination directory if not exist - @mkdir($dst); - // Loop through the files in source directory - while( $file = readdir($dir) ) { - if (( $file != '.' ) && ( $file != '..' )) { - if ( is_dir($src . '/' . $file) ){ - // Recursively calling custom copy function - // for sub directory - $this -> custom_copy($src . '/' . $file, $dst . '/' . $file); - } - else { - copy($src . '/' . $file, $dst . '/' . $file); - } - } - } - closedir($dir); + private function custom_copy($src, $dst) { + // open the source directory + $dir = opendir($src); + // Make the destination directory if not exist + @mkdir($dst); + // Loop through the files in source directory + while( $file = readdir($dir) ) { + if (( $file != '.' ) && ( $file != '..' )) { + if ( is_dir($src . '/' . $file) ){ + // Recursively calling custom copy function + // for sub directory + $this -> custom_copy($src . '/' . $file, $dst . '/' . $file); + } + else { + copy($src . '/' . $file, $dst . '/' . $file); + } + } + } + closedir($dir); } /* @@ -1086,6 +1086,6 @@ class config extends common { } return true; } - } + } } diff --git a/core/module/page/page.php b/core/module/page/page.php index f59c79b5..c8f57db4 100755 --- a/core/module/page/page.php +++ b/core/module/page/page.php @@ -440,9 +440,8 @@ class page extends common { 'state' => true ]); } - } - self::$moduleIds = array_merge( ['' => 'Aucun'] , helper::arrayCollumn(helper::getModules(),'realName','SORT_ASC')); - // Pages sans parent + } + self::$moduleIds = array_merge( ['' => 'Aucun'] , helper::arrayCollumn(helper::getModules(),'realName','SORT_ASC')); // Pages sans parent foreach($this->getHierarchy() as $parentPageId => $childrenPageIds) { if($parentPageId !== $this->getUrl(2)) { self::$pagesNoParentId[$parentPageId] = $this->getData(['page', $parentPageId, 'title']); From af496ab23ac6a8ef934c9a65bbf1af83c56d2c1c Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Mon, 15 Feb 2021 07:59:48 +0100 Subject: [PATCH 09/61] Barre d'administration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout d'un lien 'Gérer les modules', icône provisoire --- core/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/core/core.php b/core/core.php index 72203ed1..7dfef703 100755 --- a/core/core.php +++ b/core/core.php @@ -2902,6 +2902,7 @@ class layout extends common { $rightItems .= '
  • ' . template::ico('brush') . '
  • '; //$rightItems .= '
  • ' . template::ico('flag') . '
  • '; $rightItems .= '
  • ' . template::ico('cog-alt') . '
  • '; + $rightItems .= '
  • ' . template::ico('upload') . '
  • '; // Mise à jour automatique $today = mktime(0, 0, 0); // Une mise à jour est disponible + recherche auto activée + 1 jour de délais From cc22f5ac1a31e16165ca9988b42d09163c2af240 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 15 Feb 2021 11:15:52 +0100 Subject: [PATCH 10/61] =?UTF-8?q?Zwiico=20=20+=20getmodule=20simplifi?= =?UTF-8?q?=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/class/helper.class.php | 66 +++++++++----------- core/core.php | 2 +- core/vendor/zwiico/css/zwiico-codes.css | 7 ++- core/vendor/zwiico/css/zwiico-embedded.css | 19 +++--- core/vendor/zwiico/css/zwiico-ie7-codes.css | 7 ++- core/vendor/zwiico/css/zwiico-ie7.css | 7 ++- core/vendor/zwiico/css/zwiico.css | 21 ++++--- core/vendor/zwiico/font/zwiico.eot | Bin 20632 -> 21304 bytes core/vendor/zwiico/font/zwiico.svg | 16 ++--- core/vendor/zwiico/font/zwiico.ttf | Bin 20472 -> 21144 bytes core/vendor/zwiico/font/zwiico.woff | Bin 13020 -> 13360 bytes core/vendor/zwiico/font/zwiico.woff2 | Bin 11132 -> 11444 bytes 12 files changed, 71 insertions(+), 74 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index ae41d8a9..8b94d698 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -135,46 +135,36 @@ class helper { * du nom réel * du numéro de version */ - public static function getModules($folder = 'module') { + public static function getModules() { $modules = array(); - // Le dossier existe-t-il ? - if (is_dir($folder)) { - $dirs = array_diff(scandir($folder), array('..', '.')); - foreach ($dirs as $key => $value) { - // Dossier non vide - if (file_exists($folder . '/' . $value . '/' . $value . '.php')) { - // Lire les constantes en gérant les erreurs de nom de classe - try { - // Chargement des classes externes - if ($folder !== 'module') { - include_once ($folder . '/' . $value . '/' . $value . '.php'); - if ( class_exists($value) ) { - $e = new $value; - } - } - $class_reflex = new \ReflectionClass($value); - $class_constants = $class_reflex->getConstants(); - // Constante REALNAME - if (array_key_exists('REALNAME', $class_constants)) { - $realName = $value::REALNAME; - } else { - $realName = ucfirst($value); - } - // Constante VERSION - if (array_key_exists('VERSION', $class_constants)) { - $version = $value::VERSION; - } else { - $version = '0.0'; - } - // Affection - $modules [$value] = [ - 'realName' => $realName, - 'version' => $version - ]; - - } catch (Exception $e){ - // on ne fait rien + $dirs = array_diff(scandir($folder), array('..', '.')); + foreach ($dirs as $key => $value) { + // Dossier non vide + if (file_exists($folder . '/' . $value . '/' . $value . '.php')) { + // Lire les constantes en gérant les erreurs de nom de classe + try { + $class_reflex = new \ReflectionClass($value); + $class_constants = $class_reflex->getConstants(); + // Constante REALNAME + if (array_key_exists('REALNAME', $class_constants)) { + $realName = $value::REALNAME; + } else { + $realName = ucfirst($value); } + // Constante VERSION + if (array_key_exists('VERSION', $class_constants)) { + $version = $value::VERSION; + } else { + $version = '0.0'; + } + // Affection + $modules [$value] = [ + 'realName' => $realName, + 'version' => $version + ]; + + } catch (Exception $e){ + // on ne fait rien } } } diff --git a/core/core.php b/core/core.php index 7dfef703..88048e39 100755 --- a/core/core.php +++ b/core/core.php @@ -2901,8 +2901,8 @@ class layout extends common { $rightItems .= '
  • ' . template::ico('users') . '
  • '; $rightItems .= '
  • ' . template::ico('brush') . '
  • '; //$rightItems .= '
  • ' . template::ico('flag') . '
  • '; + $rightItems .= '
  • ' . template::ico('puzzle') . '
  • '; $rightItems .= '
  • ' . template::ico('cog-alt') . '
  • '; - $rightItems .= '
  • ' . template::ico('upload') . '
  • '; // Mise à jour automatique $today = mktime(0, 0, 0); // Une mise à jour est disponible + recherche auto activée + 1 jour de délais diff --git a/core/vendor/zwiico/css/zwiico-codes.css b/core/vendor/zwiico/css/zwiico-codes.css index aab2b686..9c7b0e02 100755 --- a/core/vendor/zwiico/css/zwiico-codes.css +++ b/core/vendor/zwiico/css/zwiico-codes.css @@ -1,8 +1,5 @@ .zwiico-plus-circled:before { content: '\2191'; } /* '↑' */ -.zwiico-flag:before { content: '\2691'; } /* '⚑' */ -.zwiico-mail:before { content: '\2709'; } /* '✉' */ -.zwiico-divide:before { content: '\e05b'; } /* '' */ .zwiico-logout:before { content: '\e800'; } /* '' */ .zwiico-plus:before { content: '\e801'; } /* '' */ .zwiico-cancel:before { content: '\e802'; } /* '' */ @@ -16,6 +13,7 @@ .zwiico-folder:before { content: '\e80a'; } /* '' */ .zwiico-users:before { content: '\e80b'; } /* '' */ .zwiico-left:before { content: '\e80c'; } /* '' */ +.zwiico-mail:before { content: '\e80d'; } /* '' */ .zwiico-user:before { content: '\e80e'; } /* '' */ .zwiico-update:before { content: '\e80f'; } /* '' */ .zwiico-home:before { content: '\e810'; } /* '' */ @@ -38,6 +36,8 @@ .zwiico-login:before { content: '\e821'; } /* '' */ .zwiico-lock:before { content: '\e822'; } /* '' */ .zwiico-mimi:before { content: '\e823'; } /* '' */ +.zwiico-divide:before { content: '\e824'; } /* '' */ +.zwiico-flag:before { content: '\e825'; } /* '' */ .zwiico-spin:before { content: '\e831'; } /* '' */ .zwiico-twitter:before { content: '\f099'; } /* '' */ .zwiico-facebook:before { content: '\f09a'; } /* '' */ @@ -48,6 +48,7 @@ .zwiico-download-cloud:before { content: '\f0ed'; } /* '' */ .zwiico-upload-cloud:before { content: '\f0ee'; } /* '' */ .zwiico-code:before { content: '\f121'; } /* '' */ +.zwiico-puzzle:before { content: '\f12e'; } /* '' */ .zwiico-youtube:before { content: '\f167'; } /* '' */ .zwiico-instagram:before { content: '\f16d'; } /* '' */ .zwiico-brush:before { content: '\f1fc'; } /* '' */ diff --git a/core/vendor/zwiico/css/zwiico-embedded.css b/core/vendor/zwiico/css/zwiico-embedded.css index 6bec0fe3..36707b09 100755 --- a/core/vendor/zwiico/css/zwiico-embedded.css +++ b/core/vendor/zwiico/css/zwiico-embedded.css @@ -1,15 +1,15 @@ @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.eot?63980596'); - src: url('../font/zwiico.eot?63980596#iefix') format('embedded-opentype'), - url('../font/zwiico.svg?63980596#zwiico') format('svg'); + src: url('../font/zwiico.eot?55150548'); + src: url('../font/zwiico.eot?55150548#iefix') format('embedded-opentype'), + url('../font/zwiico.svg?55150548#zwiico') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'zwiico'; - src: url('data:application/octet-stream;base64,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') format('woff'), - url('data:application/octet-stream;base64,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OC2wPSywABawFyNCILAKI0IgICBGI0ewASsjYTgtsD4ssAAWsBcjQrADJbACJUcjRyNhsABUWC4gPCMhG7ACJbACJUcjRyNhILAFJbAEJUcjRyNhsAYlsAUlSbACJWG5CAAIAGNjIyBYYhshWWO4BABiILAAUFiwQGBZZrABY2AjLiMgIDyKOCMhWS2wPyywABawFyNCILAKQyAuRyNHI2EgYLAgYGawAmIgsABQWLBAYFlmsAFjIyAgPIo4LbBALCMgLkawAiVGsBdDWFAbUllYIDxZLrEwARQrLbBBLCMgLkawAiVGsBdDWFIbUFlYIDxZLrEwARQrLbBCLCMgLkawAiVGsBdDWFAbUllYIDxZIyAuRrACJUawF0NYUhtQWVggPFkusTABFCstsEMssDorIyAuRrACJUawF0NYUBtSWVggPFkusTABFCstsEQssDsriiAgPLAGI0KKOCMgLkawAiVGsBdDWFAbUllYIDxZLrEwARQrsAZDLrAwKy2wRSywABawBCWwBCYgICBGI0dhsAwjQi5HI0cjYbALQysjIDwgLiM4sTABFCstsEYssQoEJUKwABawBCWwBCUgLkcjRyNhILAGI0KxDABCsAtDKyCwYFBYILBAUVizBCAFIBuzBCYFGllCQiMgR7AGQ7ACYiCwAFBYsEBgWWawAWNgILABKyCKimEgsARDYGQjsAVDYWRQWLAEQ2EbsAVDYFmwAyWwAmIgsABQWLBAYFlmsAFjYbACJUZhOCMgPCM4GyEgIEYjR7ABKyNhOCFZsTABFCstsEcssQA6Ky6xMAEUKy2wSCyxADsrISMgIDywBiNCIzixMAEUK7AGQy6wMCstsEkssAAVIEewACNCsgABARUUEy6wNiotsEossAAVIEewACNCsgABARUUEy6wNiotsEsssQABFBOwNyotsEwssDkqLbBNLLAAFkUjIC4gRoojYTixMAEUKy2wTiywCiNCsE0rLbBPLLIAAEYrLbBQLLIAAUYrLbBRLLIBAEYrLbBSLLIBAUYrLbBTLLIAAEcrLbBULLIAAUcrLbBVLLIBAEcrLbBWLLIBAUcrLbBXLLMAAABDKy2wWCyzAAEAQystsFksswEAAEMrLbBaLLMBAQBDKy2wWyyzAAABQystsFwsswABAUMrLbBdLLMBAAFDKy2wXiyzAQEBQystsF8ssgAARSstsGAssgABRSstsGEssgEARSstsGIssgEBRSstsGMssgAASCstsGQssgABSCstsGUssgEASCstsGYssgEBSCstsGcsswAAAEQrLbBoLLMAAQBEKy2waSyzAQAARCstsGosswEBAEQrLbBrLLMAAAFEKy2wbCyzAAEBRCstsG0sswEAAUQrLbBuLLMBAQFEKy2wbyyxADwrLrEwARQrLbBwLLEAPCuwQCstsHEssQA8K7BBKy2wciywABaxADwrsEIrLbBzLLEBPCuwQCstsHQssQE8K7BBKy2wdSywABaxATwrsEIrLbB2LLEAPSsusTABFCstsHcssQA9K7BAKy2weCyxAD0rsEErLbB5LLEAPSuwQistsHossQE9K7BAKy2weyyxAT0rsEErLbB8LLEBPSuwQistsH0ssQA+Ky6xMAEUKy2wfiyxAD4rsEArLbB/LLEAPiuwQSstsIAssQA+K7BCKy2wgSyxAT4rsEArLbCCLLEBPiuwQSstsIMssQE+K7BCKy2whCyxAD8rLrEwARQrLbCFLLEAPyuwQCstsIYssQA/K7BBKy2whyyxAD8rsEIrLbCILLEBPyuwQCstsIkssQE/K7BBKy2wiiyxAT8rsEIrLbCLLLILAANFUFiwBhuyBAIDRVgjIRshWVlCK7AIZbADJFB4sQUBFUVYMFktAEu4AMhSWLEBAY5ZsAG5CAAIAGNwsQAHQrEAACqxAAdCsQAKKrEAB0KxAAoqsQAHQrkAAAALKrEAB0K5AAAACyq5AAMAAESxJAGIUViwQIhYuQADAGREsSgBiFFYuAgAiFi5AAMAAERZG7EnAYhRWLoIgAABBECIY1RYuQADAABEWVlZWVmxAA4quAH/hbAEjbECAESzBWQGAERE') format('truetype'); + src: url('data:application/octet-stream;base64,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') format('woff'), + url('data:application/octet-stream;base64,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AiVGsBdDWFIbUFlYIDxZLrEwARQrLbBCLCMgLkawAiVGsBdDWFAbUllYIDxZIyAuRrACJUawF0NYUhtQWVggPFkusTABFCstsEMssDorIyAuRrACJUawF0NYUBtSWVggPFkusTABFCstsEQssDsriiAgPLAGI0KKOCMgLkawAiVGsBdDWFAbUllYIDxZLrEwARQrsAZDLrAwKy2wRSywABawBCWwBCYgICBGI0dhsAwjQi5HI0cjYbALQysjIDwgLiM4sTABFCstsEYssQoEJUKwABawBCWwBCUgLkcjRyNhILAGI0KxDABCsAtDKyCwYFBYILBAUVizBCAFIBuzBCYFGllCQiMgR7AGQ7ACYiCwAFBYsEBgWWawAWNgILABKyCKimEgsARDYGQjsAVDYWRQWLAEQ2EbsAVDYFmwAyWwAmIgsABQWLBAYFlmsAFjYbACJUZhOCMgPCM4GyEgIEYjR7ABKyNhOCFZsTABFCstsEcssQA6Ky6xMAEUKy2wSCyxADsrISMgIDywBiNCIzixMAEUK7AGQy6wMCstsEkssAAVIEewACNCsgABARUUEy6wNiotsEossAAVIEewACNCsgABARUUEy6wNiotsEsssQABFBOwNyotsEwssDkqLbBNLLAAFkUjIC4gRoojYTixMAEUKy2wTiywCiNCsE0rLbBPLLIAAEYrLbBQLLIAAUYrLbBRLLIBAEYrLbBSLLIBAUYrLbBTLLIAAEcrLbBULLIAAUcrLbBVLLIBAEcrLbBWLLIBAUcrLbBXLLMAAABDKy2wWCyzAAEAQystsFksswEAAEMrLbBaLLMBAQBDKy2wWyyzAAABQystsFwsswABAUMrLbBdLLMBAAFDKy2wXiyzAQEBQystsF8ssgAARSstsGAssgABRSstsGEssgEARSstsGIssgEBRSstsGMssgAASCstsGQssgABSCstsGUssgEASCstsGYssgEBSCstsGcsswAAAEQrLbBoLLMAAQBEKy2waSyzAQAARCstsGosswEBAEQrLbBrLLMAAAFEKy2wbCyzAAEBRCstsG0sswEAAUQrLbBuLLMBAQFEKy2wbyyxADwrLrEwARQrLbBwLLEAPCuwQCstsHEssQA8K7BBKy2wciywABaxADwrsEIrLbBzLLEBPCuwQCstsHQssQE8K7BBKy2wdSywABaxATwrsEIrLbB2LLEAPSsusTABFCstsHcssQA9K7BAKy2weCyxAD0rsEErLbB5LLEAPSuwQistsHossQE9K7BAKy2weyyxAT0rsEErLbB8LLEBPSuwQistsH0ssQA+Ky6xMAEUKy2wfiyxAD4rsEArLbB/LLEAPiuwQSstsIAssQA+K7BCKy2wgSyxAT4rsEArLbCCLLEBPiuwQSstsIMssQE+K7BCKy2whCyxAD8rLrEwARQrLbCFLLEAPyuwQCstsIYssQA/K7BBKy2whyyxAD8rsEIrLbCILLEBPyuwQCstsIkssQE/K7BBKy2wiiyxAT8rsEIrLbCLLLILAANFUFiwBhuyBAIDRVgjIRshWVlCK7AIZbADJFB4sQUBFUVYMFktAEu4AMhSWLEBAY5ZsAG5CAAIAGNwsQAHQrEAACqxAAdCsQAKKrEAB0KxAAoqsQAHQrkAAAALKrEAB0K5AAAACyq5AAMAAESxJAGIUViwQIhYuQADAGREsSgBiFFYuAgAiFi5AAMAAERZG7EnAYhRWLoIgAABBECIY1RYuQADAABEWVlZWVmxAA4quAH/hbAEjbECAESzBWQGAERE') format('truetype'); } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ @@ -17,7 +17,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.svg?63980596#zwiico') format('svg'); + src: url('../font/zwiico.svg?55150548#zwiico') format('svg'); } } */ @@ -57,9 +57,6 @@ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } .zwiico-plus-circled:before { content: '\2191'; } /* '↑' */ -.zwiico-flag:before { content: '\2691'; } /* '⚑' */ -.zwiico-mail:before { content: '\2709'; } /* '✉' */ -.zwiico-divide:before { content: '\e05b'; } /* '' */ .zwiico-logout:before { content: '\e800'; } /* '' */ .zwiico-plus:before { content: '\e801'; } /* '' */ .zwiico-cancel:before { content: '\e802'; } /* '' */ @@ -73,6 +70,7 @@ .zwiico-folder:before { content: '\e80a'; } /* '' */ .zwiico-users:before { content: '\e80b'; } /* '' */ .zwiico-left:before { content: '\e80c'; } /* '' */ +.zwiico-mail:before { content: '\e80d'; } /* '' */ .zwiico-user:before { content: '\e80e'; } /* '' */ .zwiico-update:before { content: '\e80f'; } /* '' */ .zwiico-home:before { content: '\e810'; } /* '' */ @@ -95,6 +93,8 @@ .zwiico-login:before { content: '\e821'; } /* '' */ .zwiico-lock:before { content: '\e822'; } /* '' */ .zwiico-mimi:before { content: '\e823'; } /* '' */ +.zwiico-divide:before { content: '\e824'; } /* '' */ +.zwiico-flag:before { content: '\e825'; } /* '' */ .zwiico-spin:before { content: '\e831'; } /* '' */ .zwiico-twitter:before { content: '\f099'; } /* '' */ .zwiico-facebook:before { content: '\f09a'; } /* '' */ @@ -105,6 +105,7 @@ .zwiico-download-cloud:before { content: '\f0ed'; } /* '' */ .zwiico-upload-cloud:before { content: '\f0ee'; } /* '' */ .zwiico-code:before { content: '\f121'; } /* '' */ +.zwiico-puzzle:before { content: '\f12e'; } /* '' */ .zwiico-youtube:before { content: '\f167'; } /* '' */ .zwiico-instagram:before { content: '\f16d'; } /* '' */ .zwiico-brush:before { content: '\f1fc'; } /* '' */ diff --git a/core/vendor/zwiico/css/zwiico-ie7-codes.css b/core/vendor/zwiico/css/zwiico-ie7-codes.css index 82ebb1ca..6e732fc0 100755 --- a/core/vendor/zwiico/css/zwiico-ie7-codes.css +++ b/core/vendor/zwiico/css/zwiico-ie7-codes.css @@ -1,8 +1,5 @@ .zwiico-plus-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '↑ '); } -.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '⚑ '); } -.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '✉ '); } -.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -16,6 +13,7 @@ .zwiico-folder { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-users { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-left { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-user { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-update { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -38,6 +36,8 @@ .zwiico-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-lock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-mimi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -48,6 +48,7 @@ .zwiico-download-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-upload-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-code { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-puzzle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-youtube { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-instagram { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/core/vendor/zwiico/css/zwiico-ie7.css b/core/vendor/zwiico/css/zwiico-ie7.css index 7b6be3da..f7920c99 100755 --- a/core/vendor/zwiico/css/zwiico-ie7.css +++ b/core/vendor/zwiico/css/zwiico-ie7.css @@ -11,9 +11,6 @@ } .zwiico-plus-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '↑ '); } -.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '⚑ '); } -.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '✉ '); } -.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -27,6 +24,7 @@ .zwiico-folder { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-users { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-left { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-user { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-update { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -49,6 +47,8 @@ .zwiico-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-lock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-mimi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -59,6 +59,7 @@ .zwiico-download-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-upload-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-code { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-puzzle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-youtube { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-instagram { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/core/vendor/zwiico/css/zwiico.css b/core/vendor/zwiico/css/zwiico.css index 0f92db3e..c2b405f7 100755 --- a/core/vendor/zwiico/css/zwiico.css +++ b/core/vendor/zwiico/css/zwiico.css @@ -1,11 +1,11 @@ @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.eot?96515118'); - src: url('../font/zwiico.eot?96515118#iefix') format('embedded-opentype'), - url('../font/zwiico.woff2?96515118') format('woff2'), - url('../font/zwiico.woff?96515118') format('woff'), - url('../font/zwiico.ttf?96515118') format('truetype'), - url('../font/zwiico.svg?96515118#zwiico') format('svg'); + src: url('../font/zwiico.eot?44489499'); + src: url('../font/zwiico.eot?44489499#iefix') format('embedded-opentype'), + url('../font/zwiico.woff2?44489499') format('woff2'), + url('../font/zwiico.woff?44489499') format('woff'), + url('../font/zwiico.ttf?44489499') format('truetype'), + url('../font/zwiico.svg?44489499#zwiico') format('svg'); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.svg?96515118#zwiico') format('svg'); + src: url('../font/zwiico.svg?44489499#zwiico') format('svg'); } } */ @@ -56,9 +56,6 @@ } .zwiico-plus-circled:before { content: '\2191'; } /* '↑' */ -.zwiico-flag:before { content: '\2691'; } /* '⚑' */ -.zwiico-mail:before { content: '\2709'; } /* '✉' */ -.zwiico-divide:before { content: '\e05b'; } /* '' */ .zwiico-logout:before { content: '\e800'; } /* '' */ .zwiico-plus:before { content: '\e801'; } /* '' */ .zwiico-cancel:before { content: '\e802'; } /* '' */ @@ -72,6 +69,7 @@ .zwiico-folder:before { content: '\e80a'; } /* '' */ .zwiico-users:before { content: '\e80b'; } /* '' */ .zwiico-left:before { content: '\e80c'; } /* '' */ +.zwiico-mail:before { content: '\e80d'; } /* '' */ .zwiico-user:before { content: '\e80e'; } /* '' */ .zwiico-update:before { content: '\e80f'; } /* '' */ .zwiico-home:before { content: '\e810'; } /* '' */ @@ -94,6 +92,8 @@ .zwiico-login:before { content: '\e821'; } /* '' */ .zwiico-lock:before { content: '\e822'; } /* '' */ .zwiico-mimi:before { content: '\e823'; } /* '' */ +.zwiico-divide:before { content: '\e824'; } /* '' */ +.zwiico-flag:before { content: '\e825'; } /* '' */ .zwiico-spin:before { content: '\e831'; } /* '' */ .zwiico-twitter:before { content: '\f099'; } /* '' */ .zwiico-facebook:before { content: '\f09a'; } /* '' */ @@ -104,6 +104,7 @@ .zwiico-download-cloud:before { content: '\f0ed'; } /* '' */ .zwiico-upload-cloud:before { content: '\f0ee'; } /* '' */ .zwiico-code:before { content: '\f121'; } /* '' */ +.zwiico-puzzle:before { content: '\f12e'; } /* '' */ .zwiico-youtube:before { content: '\f167'; } /* '' */ .zwiico-instagram:before { content: '\f16d'; } /* '' */ .zwiico-brush:before { content: '\f1fc'; } /* '' */ diff --git a/core/vendor/zwiico/font/zwiico.eot b/core/vendor/zwiico/font/zwiico.eot index 7772760acf582bbc0b574debf861d04d40ab7bc1..66efe7e20071a21e00bd114e4e6a4e35ba9edb1d 100755 GIT binary patch delta 1935 zcmb7_U2Icj7{{OYoYQl9+OF-|)6=yZTj^NGM^{|ebqgD18y``o2+T|h1gz`6ObZPR z1Y#&66)yB*oSR9w*whfO%(Rhs1zu<}!5j4klO+xlO)rGBWF~6R`F}T!a-qR<^6UTn zp7*>T=cDb^4Ey*RlRF29ruI(CacPb&$0vJU%iknoyNPIUD4WU^4!!v@{5>M+#?Z-$ z0P5JbF5tsHk{ivw82RN4ybQICrjF-Ocf#)=&7+yqBVX^IKTjl&5yj`nhEwU~6L|be`!biEI$0xqK`|Wk2-cRA~+_B-@+3Q{KJr9j3c7UBW7TM@c6h>NbeuyMmL_<9;K_vU?$x>6PwS1-gd3nBkw|u{{x)Q03RK7)hdRu>S+x7OUrwPj{LnFE-}mE#j|1+%THlizQy^lEAXY2P~wn) z*xRoXDfK()RkmuK5;srofBzHi#uO;q)s*v0P z*^%45`UL&>AFnKut*Q zfI>*_O-5SIcSVRQfTGCJ6{roFU4dfAhbvG!(Sz0%_zPh;mC1M3S**oZ%>h z8TFDeqbwAkTK}^-&xn@37iYu)O0!G-vzFcadh}ge1y!kK#9EuHM1jPoV@zfJwf(bJ zw7Pa}jftj5nrr{9OETF%tD;XYDXLN+)ua~4B%2CmCR^nKi58Z(i0m9*P>BTT97)mz zvRcTR#2dxP!p6yJr4)as_F#6tw(b8M$!sc+SvD8wuhIU;VEj@xlae$H*s>$sX5G>d?V~y}tE9|Auv)jX|5-u%Stl8-o#{G3e2B#nWgPlwhbmmJm8( zp~j$$Vgu6^O~Fac5w?*9+pE2L)T_5eJL2uJh|nC1d!xEnvkP8LPp}S;>|p4{Pe=%D zQC*yghP`Y3p}dxGF_(KscTHo&<#!5+@Wwuu>b3|zPdGkc(j}EyR81I&hdn;0ZWsEV z2zN70*M-QA^M1xmRc@cp7N`r?M56avx;0(ft`B-d!6LExfEMzv^@gLdmYT4=-f8ps z+*M2v7!$e#L9lBzzN&z~AyU&4W6Nt`OJ0k%QSb` z(ft!S#N{8f`DZJG_&N|zW1_1=>ELzoN#jOWToOx5OU7bX($t4i$=KPwAwP|yTcjsUGt}|~lr_GD%HFe(dg7sbN z9a~-1Cw9sHw*4!I#WCyLzRj;qU>Y8>t-8Fy=xr{3(|gnY2k%6gjQ{`u delta 1277 zcmY+CZ)jUp7{;G-b90llF-eD`i_ZB_?TFP1e}P zQI#1%m?8s>#}BOxQG~HiItY%6F#OU*bn4N#oKSTdK$zd7@JiuGl{ypcRxh;W`q ze;-f2iF_va(v$b!V9mVGn@P;(IUiuXmv(2euTQ+v9{wJ%IKQWFGMz}ZRsOsV?7PDI z(Me9YijF1LHtVj*Tw(6p(_^(&V853WKWC?tiJ{(SkF&nb`b;h{mp4NGcY)X_>&Tfz zF8xB~tCOq?fbn&HdbV(Mb*mdVu!D6&ekPrN>+1fiz~NJRUX80ceNSbIF(`IJMd4V# z+CeukAA_lAbRhy0W=E;Jw9T_JZhP%cyQlI=<%i0zm0Ok7YDYCw%~c=V?Wxs(|5C7h zOf9UZRw{S?pOW=94qbGFI~7;i7%@z6OsjFC)i4Xz5oSf9qw#si#e=c;Vk) z>6Ml1$TM{FT7Us;^VH!}VP(7yp9iwX0-Q8^1XwhC1h{DS2;d&t(nG-Cv!#a=Wut6q zB50(giGVN6mL`ISXlWww(b6Lu>!+oM$X8-Z4?zhhAlaQt+eC_x@pOE>Jh8BGXqo!o}zPg@HG9P4)y?dd+MN9yIm!n zczmV2&>T_v=Jxl#Sa3C#zX?Xd<^Ctu+~uEoH@mkC?{c1d(I5K*e#iRj|K-PwoLqu%XYK{Rt6p!k+<0tg3`1axn&I-I^EJ-JiAuOsx>V3m&j2fRhx*Q{B z!2H-;at=6eSP|>C%j-Jg`prG!UUsi}T0EBg-f1t&PE9Jvz9c?++f+#}0Ov J=MH}7`v<7aJj4J1 diff --git a/core/vendor/zwiico/font/zwiico.svg b/core/vendor/zwiico/font/zwiico.svg index c3c30fef..947f4d93 100755 --- a/core/vendor/zwiico/font/zwiico.svg +++ b/core/vendor/zwiico/font/zwiico.svg @@ -1,19 +1,13 @@ -Copyright (C) 2020 by original authors @ fontello.com +Copyright (C) 2021 by original authors @ fontello.com - - - - - - @@ -40,6 +34,8 @@ + + @@ -84,6 +80,10 @@ + + + + @@ -104,6 +104,8 @@ + + diff --git a/core/vendor/zwiico/font/zwiico.ttf b/core/vendor/zwiico/font/zwiico.ttf index 56e48ab1a001a8d2ab2d59d65ce4e2bf200e4905..1cd9d571690fc563ecafed29f49d1c7698fad0b9 100755 GIT binary patch delta 1918 zcmb7_U2Icj7{{OYJ?%L?{a$-|x^`nLE$jH`iYr}*Y>aJu#4ts0WKtk#UAJzgg@!MI z7)uCMNi-494H6QDA4I({i;Y}@7hE8CrCwmt=rGarLP$q2!33TEche{r8ayYz{?G4u z&ikJCw5RR;^X$wA?5#-Y3K82%L?fexOtHM@&6nUG5}7WK9zGaC9ozaDyg0{;xxx$a zUys4-PK=@R#9B zCJG0ST>foj?hXo5C{*+NMl+jlJZmB96DJf4nIlE+bG-)t86Mi3DU9u@PwygHXD8yH z755!D_`|L5FA)t~g?o$p$BM69>Va>2aQgl(cGTF;a$`|q7)&fg()>{jX~pSLGSNLW zT5tyvITxRLwa$2yb$>yq5w!o3J2sz3J27P6b>kW6b>ke6b`5fDI8EUQaGSR zNZ|k<3)O@JYTbB%Hh*-+Eav<+R)mi0-={7}2;--e{q zL(?k843MHKWm3&*nar}eY+NnER@RbIGAm`3J-ntzp5;I8>rv+@rPJwt&uC`P z?%`(w%frDH%T`CicDZ#$n-WOXr=uy2^9`MCd!)D#2GOMcb;Z)2QaO+M!_*kr$X}Zqin@$87GdsM2 zfIZY4Ym6sucl2tywoxDPN!)5;Eg>x$T!IxL=UwvH)G7wy1lDI3%YgpAXUyM0+!~~+jQ+YSMM+6lIDNVs!z|3;Ojsl zjc?X;E8U_lJz=!;q)bw6ZqC@=lQs{cR5L#ASy7t8QTk8N<=4evY@6sBuDFxUa4Y{( z+A6&&{cbvGs+yP59`ectxI?WVoi@wwCFeAoGv%j%kT zuW_Gn*BX{Lobyb1-QLaKY41HPt6lf4_FdE){o{d8gKt=aKQ-;0|Fh_>?Cez;>ol@! zKVh8}Z{Hfmx{WRC@@}@8?8W?{10AE2`$zL*S>xMvPnimt$-L3lf7UK%Cl60%$4uk- aOwPE{KP=0|L&uKgjfR2t%Hso9oPPlCSCd=- delta 1260 zcmY+CeP|nH9LK+Rxm=Pq=4DB?woaRxuB)(Vt4rKV+Vus-5H^RFvbIynk~FF2w$R2= z70rJtGH~Vbk4?lE#4#9bgXkCtLqTEdKimGBC>UXkL$D-8rG>KW`)jP=J$&wSzvsTc zJh|uY?AO}L=h~TA`8uE-0WhAnQpLAt|H!bu02nvYr%F-I^B5lD$v0ihS;wDReTy~o zK5s5HSLA$v^={goE4(@VdS~QEz~ua{p?o%#>8Snl6R`IR?XNg(GY8ZOo}sNKc$Qvkf?dFJe-p%2-ds>W^j0gY!KkM8^nUQws@Ym; z4@D!DFP~g-SK{$4?yZNOcE0nfKlwNOj`i37%blM;;sOw>{J?Xegv>h*60zNAI7Za@ zfrP3KOsL_(-tq)z1>VsYrIW`2T+@ysjgz z`|iW;+wK)lo99ByWXqY>u=l9@fif{Ea#o4yDILeGb;g#HR= z!i$mJk@K6|+A{5f?Poip@`-9(Fi}|^^k`b2THAj~>#JNG+N)^^b$__f32(9R#@x>I t%xt=l%^1^#RL-zcGX*m-3ZEmsE-EQ&qdGk$jW#(K*nM@{= z%sE@;byk?3iV_lF;9y^aof!=Ef3r$@0;UkqYie)o1O^7a_Juw$FsPmogBVX!4>wXU zFv#>TE5t9Ld;!eD$Qy%={()FMyNGq$ZrbvDep{IsZ#0{U0E(P{SOI?ajZqzORi0fPq0Y z8{F3EIyt(!edPpwagJXc#=-t>i<67_moHn>m)}pYBxP`EaI>T=a2`M#i3Q9n`*>+m zK}Q)kbl(&50RGNb!>n?R?T3JqET{aRZa0l?iktp`nU4sIABS^8zoKe`N+2EculS*! zWQ-CXKfqLlRd-|%@oCh4iZ8Ej+qm?OZyo)Lg6+Pk|IN4kYKdf$%(!6QA;Wdfxays* zc(47di$p*mU}gUG#q1s6-TvtOm?~QEeE6^8a`WhQCa$-pVP_6SXTv+o+9G}VLYY|AoNSsheAO9CSxRVP8aY8=X0uhb~= z#Tb$$ClRKq??Zi(?68>{i=g-!`9_frW_kGY1$L(2^z@&E=Ns%|zX=xE6CC7S#XH#K zaoahk@x84wdH-Zd(>6JNhy9=8~zQfa4}4Yy$G{u*jAp*q@Mi-nIxi^!1~_!ib>YzdLuP>#uL zCn{>>Z(b%3!wO?F&`+XE!e1PZc!ztT37|fj*>)GMwyFIE>&K((pwuE&BZ=A zx5F$7(7Ba)UwmUnM2!-2x|u5^uf(3G9#@iCR@{r>Pa!KUe@w&L{;Amok9@7PE)SR9NJF$B@HdJhs{sN_2YfKwQeZ$^&abYElcYNlljt*yh;>FPt+ z192j0f)4YErxbqy^Ef!w1N+|b;ZLbmZx;WBmLgm}VUsL1Ysla0B`Q_{bep(d>$Ya21jHWc=x zfD?8$p(qW!B9Gdh`T%?~hDJDumT7(vB)pGc7U54jfC52!O+g;cmMhh{DOG&XfNQOo zDqHRm9$`F(oUA*nKT)J0Mefm~RffX+D1vUg_sCw8Mn_=ee}92L^cRy!66{ye7}r>2 zI}cl3<>ih%_9i!zPOwx1pDom(pOL{|pj}i3)cSEY*2>u9mgF_M3fwQJtT%6B{^zu+ z_u-MHb6l*(eDD{l>Z$*CERG(_G8v3$#=0pJvB2vA(|YJMYDEa*2bTGMrT1Dr53dE1 za7${G+5^W@QFA$FHL`kJlMx;G`_#q**NMPJ)1YM=baJg+>bR8s?cUpwMDA@jfPm1J z4A1L@(k4xQJ7A4|`)2(_x1@rifD!9b3ST_xso!aDaj)gWiS6D=xe}s6R}!FHMp@5P zMw7VD;f86B?=GHv8|0#xviQAe6W2kN3e%Hg8Qj|_M}nh*QxRJ^g--pAd3Yq^uF%Ch z3pME$1Z8z|6`|ene&zu;zVH|cT+D%M_U4e=>VXh_a=s=I|3!7z>C4KtF6 z{!#*hwZ4rJR;jIhy9mtp@NaK<}McfP2}q3#21OuJ+U;5+$ao%(Z~ z8X@{cg@;f6YU=T^;TBMXBghQCy^<8cKmm`qO~O#@Eb&}f0OdnWLy$_>vhFzfv}PS*L4u6inX*2#3e;uF*9Uhd^t?}&j_ z?fdTNy(OC4`)JaA$nl@qTI0WFed5_|2@F)_-n`NxIRp+dFc`rj)+aA_9Gch7Bsp7# zIWXcYMeu&zQ^8i*7}`gYRiG+#X}bbJ@qo+0VJ(DnMdLG}uBIO_CJO_x3&g8~_Eu?jL{;*- z8;8?$6Oy80u)qU_ujkSOI7-TU3+F4Y{go)#UdZKk^}MC+fcAb7=)rZ|zQd2Yw7FBXWH zi+GBa@bwNew!{dItTrgB1INY0LoQ7)fw6zB3JiEv&&PQPSMUSh9epT^!YA9cTJpN* zqc#KQn(yd#|He)6+I8?#EP~dN`$yz+bV1HM689mW5trld4nO--A%5GA7R#73GfaT& z(7mgm!jZcR$mN=QFFcf(^0};T{Wbd!{a){P%#n?~6#X1)dK%;resK1{OX*uIJ!I_j z5WTqwQVU!6D(MdXBxDC9?LpZ>?n=5<>A707G~a+-RoCt#$L`ZoapN@_cklIP?r)#1 z1jiM=Ny!64$wJ7(Vauq)Ic5AHWQBJUF}xoZ4xfvnK=~gM9_jogO+pf;j*$%M@U>m@ z9>~)fX@uW6-FqIvZ&|in4$DgN#tZP+%PyH^4L>))SyL1@1J*l(8PSwPG^@jp$zMg) zjEI2*^}AB`B$FxIXp<{b8AS_hPo^oyysVsD+}$o~E2lx>*`K|V&zgtV8exc*c=*9Z z!3+o$KnPt0`&M?AD1#u#Ly;p3p!$Vi6 z-HFA@ha*?dzB%DvChr5hj2U)BGq)63nX5SMz`ovfZ8X>#e{A_{bC9ZPP{MWpwaUb8 z2*i>T6sFB@ne8C5pCtjekA}0gb9}i%WVx>*KE$EzF{&tW)2Bfv$1sBZ-vp%XhIAM4 z)Wv)UeiYITByGC&D)_~GtM4aTDoW+TJVxd?D&o7;m{xMe`IPHAbTY^jLHY^K0tl?j z0XEGa`G_>Z9nwMDq^gpGy81yR;Biot{nTEEoi74Novo?=R$m(Jqw%S8rn+q~@t9s! z+zPFKcS}LgU9);b%tI(I%m+w#v3G-`2+(I%G#XdP`DF0ATI%OYo{B~EkRl@u4e*iN zw^fmAiU>*Z#NzCB`TJ}-a8F3;E9a$D00H5|=&?Jv-|gwBcDv$*+hko*%%nqRFJm`H z`~u*RLD6@cgg^aI^b18TIpl?FEU<96X8s(AX2#MW+Xi1}-cP48<#4QXZYMFMthB** z_i0CjfutI+O|5+J_roP4O!r(i9+2gp9BLQOf25OJotd=<>rK<=-zhTZwwwU5C}`IAYy? z9EbPy@Cu`K_mK^c(%K|ynW0k@sQ- zul%zt$)*HPLM$XCRmRPzGUzVhfzaZ7A9n04W(PAES|sIo5KC64T*ww&ZL}DfrcC`_ ziFA2|xkQFss+ki;#OG5)2F>dTvysT0sq$#*RKUf5`quNKx(PpRI*ObJlY&#|hw z4xy+%jxpHs%(!0S%?3>kiL``DGFwgC8mSUO?!b#TEkbJ9XYH&BqkJ2W0Uf<(w0HUg zQhiE8+u71YLDZ2LRwoU1EZ*@VvHdCTQ+9I)fvkv8otzH;njE}1v(N-uuu|ygiXq`J zZ=c^`KP6ilV4wuo9;(M7( z<4#JIiXwF$__knv0=kVV{g;80fxPm!s++XH@jb{P zy|!FIvwxZBmRo!5fU{6tp=hc_nS|M?e=MsUP81noh#u?S-^M5mAlG>&x;^KkbGyxz zR6th!@8IA<@sjD?&7H;8?V7H=%C!@sMl7^}Uo$HNv8d?LKXuZ=75~&FW;8i>eVv$! z^ZEh_O3+Vrsh)MMPhca=IqZqJO>;$l%N8cM942zkpcvi_{|!dq(a@Ieen1Y7!1-oy zOS}ddUcC()4U97jXi6?R!;51JlLVC}jh3e7RL^J>OzBsZUhZzme!i+a`s~`Ctu0bJ zP>(~cD_w39ifTIui`klza+L2SD`5INI6Ng#FlZE%EYJHzBhDhNz`P#RbH`EQxLG(^ z&#N`7;lV2H2-B;$`)erAQL!!EUqnxlt=sQU35SYQhI17FY^J!GjKvgv?WuX41&z!< zV`#$Va1K>-55Y2eM&ji9|GL)lx4un0)ET7&VH@=2N7AWC?F#Cg`M#x=x$bZ6jZv3{9RHEjVe8C%B0&A(M+Wu2q1ALhD zi*{<`)S7#@p3veRkqMH&h_xYu7;>lN6x!}Tf{9accM9VxqA&4p$UD@xDO8pak}(cg zFf7>0#Qflz5b|tIb%4 zYzW)qC9}(mDw3KhwBF%0_PmRZMZu%B$u}>F zEzd3-=bM`-oWuG7tb^PID=6vBjn>lfGbae3dl;^+3zp(M+o}YMl5I6OOQK}di)816 z-j?bYwMP9rf_LYzr$lR>$dv~Rok)eRm$l~t&DaA4iPTWwFU-}69Fo_)dEG;BJae9QoHN#j(}@0Jol2A~zh$4|cn5#zWluF1`hSkYs)RHyAq0|Dgh}|LZ2t3nCY4Y#6 zx$0nvi0%9y_W#{OG61_YDcCwWDq_+={ulH`tQUB?KR5TtNl0#vC^wSs5 zAC77VQchoqaKTs+4^eX3w~UrdKdJau`*m#D&8kPGZF=vN>Z?Z^!6liTD?g`fi?8o+ z@e{*M{!4Z;@@<w~jG9J`*u=Vm%;BxpLQStfrZZBuuh&}x$QBI# zt*a{TK6QLE^5+8 z#Vf`rs6766J|0u*%_EQSE-vnYi+4eY^*S!ykAPq}mZ9M~HWqrIdmQ11ocrJHUF}O) zA*(0Ie<$5raU#yuosSuTgBv@UK(ck|92H$Z=T&&Km1FkBx2UyN&a0YTjQyA{#fSdI z{;F)cW2-9Tf4jdGod&J`ouTd%Is2!*h#_*w#ict?e^1|EguM_7Swr^X$Ii*(|09!-M&=dYz zlYb++p-*-U1F~mp=||ao5J6lia__7;Mb^Oj{m|_*A&kiV{@KXY>?R%U>Ujj=*K3qTj;@>Xw($=YVhdT(0|N$F;}0 zc4Aj@WW*E}Je>Vmk8_-9DS5cn!e(RQO-3?<;kYy>-papIN`a0S0F;^t`aLv?XGdT; z8(Yi~j~_QAxwm+0!QUsDsh5*c{sOi_a=QFXK5X>-5zso|m}z{IciQ0^|7Tp}{@*C8 zi%ex_$Z7Q;O2G*WD56!LiH@_?Grl!qu`52_et{#90dbS6d0qj1ICGOmhR_yn&85f) z!@?_1wIyPe)SSBskXI9R!-Z1RYOYX;9kk-9lG<#MmPx1Q@t>VgupFCQB*SmmJGZ#3 zvTHfnZN1a!d9>UooNfwk)aH%L+Od1`kzK=?{)0>{PJcsqgjlhL(=@(DW*cxya}`K> zS|#W<+~C&j)Ly*Tmm0Z+!>n7OUq!_v!QYa~x;^|hLEqvd} zf8HN~ERGKV!cH$*!!Y6z`u(g%v=x~;hlKm4_!x>va;Q9_t$&WcbNCQyoAD_nXn|3p z6cNx%a1jOLa0dtlS}@%<)C~oanT5#0!G&{J#rreHQjz0!f^~3cUD|E+^B<9TO!`ji zILM!0y9^Vwl2V{&7h|%b%@1CXvW!YI_fJ2Wm2X!TMu?*UdgX}-nwruD%ZoqTc@greCvQ6|Ba2XpbtVJyN)^#i zqhhX{0KC8BSPtcE4lfFQj@)?HT}8z1M}&`toVGSjN!n^fp#eBo9?bY0E%#1r^bOU{ zveCs=LyD1R0dh+tCzhq0cWN#BW8A#f;L;K*ZP|hcr z?OtAm_^!=iTh#qSYjm^7q^+2YH{Q;nrqp8%z)}eDK7KoGu!%wB@e9nxJ_$MDKsJu? z8i<>_Z1^ucy*mgI9Y@b|xqqfSX6H{v_qnZaP*Qx^RO~6v{bA#FeM&luU~5zSLH?sw$L!JraXU zgd55O~Iwjv~Vw9*G{lO2F_aSwT8ySe};Z9}8|4uT7n|X!I2_;0U##a^~GGn#7#Fdqh zet=KSC04WT8B<>?Xl$XRj=8p`%CG)lzfYous6*$nff;E;v)Dl~h{aDcU^7KI1t@m? zqC1?P-(tF5-8w$)-U%$egTb&=wB5~7#1VF|n4Gw#w#Sh@c}oXYQC!+$wUqgvW<~(Q z6J%iYWcOXnv(zReS>brSOsl!ltsq}`fc%W5GJ8s$3nAT(l`dw3^7S(vhWBqYIPJ0a zL4Lx?i6G}(Yt!2+a@Z>@C$e2OuyeN+TTKAVx$Gkm8xu{~`MGv`%TmOzJz^NX_3O4H zcV{Q}5@o07_K!UuVv3CMX^W$nF>V&e#)|41+I~3OJ*ikWR(l4trydhr2Vx)Nf$A+b5r;Kb_MN(A5r;oRijz-k zw}9t&Oi#F@gmCG<@1^n{NaDKcdDwLqcF_a6j`=fPBY!~1*J8o^BDthlHiMI-PNZK_+M=PGQp~* zANY31k?As{6W28^!&8eCv!)rPZC0G&EEYQQ9$3h#r(IGP3$$FRROSfQI$fQWjgwWd zM*q}cId+X@W}}S3>!R+ocz5;M`*VZx=h8Qg5TfiQO!Dv;LX*2TWXeAu zb#`F2h$x%WFgIO5HxKUA>Bg~aQgC4qj4pHhq#@%&I|5`*0{FDsY~Q88AZpt<;u_Yb zbv^dG^g3|iCAy1ROSHy46Vl4RHQ5^^ieO$ya_=-0OlkjTfRHV=FodGK6Y?X!fA<5& zlj(H=rJmd@) zN*)9=Qxn`sm92<8mw7ozm7Ca^HJ-zOS%KTWdB4W3p}~x)zb~%}UKejft0dZ$gG~9e zW_nFQYPQ8l6RH;LQXn+9urV6En4xu};@VawZ|RgfRrX6kP4(<)b0*CnL3f;Shngf` zUp!oZJ-{nEW6iba7mH%Y>N)*`djw6*t+O549zz$QC1TsigzWD{Z;{{F4aYa?JDsMC z@4Y&ZnIb;lA6v}T$|Xt{El9Mj+Y=0ZB){pmu2#btX|RQryeW1Ls9eZEbv`C)$FiVi zy?cfFOjpr+B)K;;Ok%j)oJpx-5x7*Pszl_H?*dhZoD%`m4N4L-a!X~bv@Jo}dhCZL zFdPgbJ9|4gS;s=aWXQOc4Y!n7P)4eNVeBiNJ)ldcYl=?LERl__E9dJ~OTPpA;!zVg z-K$Q*!o%zP!)iI-d%dw za$6$|!T&=j>rpebn^perPcg}S%WShc9nhE})2#u3vvvoS*RiR6&IoM-g4}-)Kty#7 zE!YJ~rXQVSD^I7Rwek~}8T&iTz)Glu;UL_`HQ<9OSA<%^<_483-}M2%C;JK>PLK7=MvKGsv5yK(6Ar<{Yi*vzzm}R zglf?3(j5_Mi^W8@>rTCRdU6Vm_R>S)Kqfp>oHTK7lCgXlU3Sq&CO>68FyXNk{kK7`j&nWJ)S>T*H3KqnC;!66zyk zsD`No5L4{^Zp2vWowv_1>b6V^d`|CglXFR!8xkDT?6`W#!F~pEooS-eW0(o(GG%yX zzO+l&%rMxe%4RgJ4o^+!HMyzN#s7#~3RvuWIJ^co$|!0Umrv7FZAg)?ORC1M>>Wqo z2n<4vIH;_RWPW2^9!h5zcrI6uq*(1i*R?W{LNoAFM-y#}s+PP(g9`WqP=F4mg}l|5 z&X$T%q)!;K)k~NTAu%hKXO})b4@)$G!0J1!M=of|L6Wy@zDauu*u9;I(v^b|=6p2X;c!tV)#5gNK7+G!*z%3%CT=CzhV1ucx4d0! z8<8zLtXLH{is8*x;h zuEsWJiWpVhmPuND`!XGo^pI{l+#N3Z>^`oM9^Mnd{va?^OE&m`C`+B#z9#CPrdj}U zNf_)1(ur8Ld}M4CsB{#%)AnnW&*^TwI{;<3Nbo0U%wBAE7-4vARuI@>_j^PkINrd% z9J&Rbzp4~r+z>zTjcj~73H(Lz-%Zz;LkcwfE|vEx3gxcgL6YxOQ`4u=Kn>B$^A0>c zaFsU01_==RJ(4;T zdc@s)LP5-B<*`cr-1>a#*M0{2!HSj@(&&k0S&N?YJr&cm1*55i5ywqd})aHBsTYW=NGUs!ctl#?Mc((*sQCch(nZkKER{LnWb^anz!e+3?-c zjZK!K=@KRn|7l5S+p%2Y*IVF0pchAC_P$&fhILoSQG`z0G~<1?YqdSx_b@$Z%wi)b zbV4Yh{Z={ZMU;uFRl0?xh`fCyzpd#5?_@DvBN|DLy)$~B<>T8w%+w1fuDCIb#HQ@j zrvpG~d*fo&(9)d`L62hFE`5h*vY#va{hhZOafi0UQe#Z_;uUK-fD6C1-$dr$f2yv< zD(}7iACR>&`nxY-@zWUeyGtd_AVDpFbZx=pCVn6=_d+M{K3Ft&YbTqAuznNzLMT;% zM0QniTi zx#Y2mKXFSwYa!!IqvLo-nikci8+)6tlk+c+lHOWN0eS`4)56WIj(-(_Y3(OHz=ocS zwmpLnJ?^*`pR9B}-bxwSfuyAw}Nf zheBznUxtzf7FO=N5%Xtm+6BK>$73M~*zX>d+djr4MWu;4Af*{4hIxM0LdI(? zS<X1~4%P5>5&!n=Pmg#osjfpPz9S2JUTRuJ27!jMJ&Ws+GjbgC-vXggX zA>(&A=JI%|95(r!6zDgwkVw7OKV|RWFYyGv-Zb*TXW?&1L4ZCnaN(9a8GF-RZh49k z_0!VcQPGC5+F*sSCSCR$gCMZB+{l=E5iD9*oD9beYCG)6B3UHN9JGKx_0^zz_@Vd= zGI|SmnJDNk^3JqcpF6qa z?-+o|I^>^zg3YT}I(lWB8krdxftfT)r#c?I*!QsBvh{*RGH=~|;=&Yte!k`noAeQa zAGt6y2Y|qxdXTNazS`pc&j;m8*VkA0`MLUO$N+;RjE-r90+wn6qx_}+)!)~51wMr6 zuZ0##@dXmFC;{yT}Roui;AzBnqM-Yant$Qa^nP ztvRIQ=kv(P3wPjz=NP?yenMo~Bd4^&T!5cPf!d%Qh_|}YJi)=nl-a+!1OIPGfQ^Bp zf$MIe$#>KI~Yrv1jKOt}c z1OH0Nm88Q&3{1;FvS5ZNUXkcH7wqvm{3ch}1jkv4(X!J2?xu`}!y3Dok$nE!Y$5d( zt|tg}AMu4DcLu6F5F_#Bx}AoL3*0H32`+h;%5ogSU4rT+Kfrbr>!LNb@`!JggWdV2 zZRYOG3-#2?V`~U~M_WYA6HoqbU(3jlo$zK)n2@JN2@rDDqcY^K+1JwJsZj--y29$c zT(*YF|GT<;*(l?#Z&(&e`Zanpk=DGFtcLxYRcj5DrMEK{F=LlpvVr(`WnZjTCaK&d z1*r;i%o{6L<3`LC&5gn*(h@ID23v-KAci4tcPisQ+IWvKcB`4Y*K*n0M}nJ3C5+XWgY`Wc0Y z5&d}|lsCQO^5wxx-3M3<%fuUmpIfH{O{so}z}G=|W!o#QyDTxIxj7!u+kGS5@|5y- zN+%e&8CzJ>sAgz)i49()DQds!~tq(P;PvFxCwaUN8NBgwJ!Fq*DdPUQCMOu2r;&?@9a`)S2A0Rp2V&6E$KL6(*_g^qd-W{~z9rErS z04a2b*y|i1H2iaZ-cyvPKw4uXmJ=q`Gi6UA-U8#iI6EaGH)cq`IUZf6_Mkyhb4kj_ zy6Lz9zbf@;;%wZz#2U`-M5ZyivQ3IOT;8LEmHV0|)w;RvUXGfX%aAuq z?i)QKo3Z4sMgJcU+qFj z4Z6mB!vw=kUR)dm6y&?HY=9vD*UP`eVF&=bjBE_-K|nxPzA*v<0x{y{cxG(m>P!Rz z0-pOF1^*4CZ-AKEo7sGGl^`Hcm){hEA;UjUGXtk@EnMce8|ME5#mw5n^qVUL0U`AO z0r@Ft^#gOj+{C~b1cZU;JBH;O?6@~igXZ5P2ndit<(v4=K?V&3A2YXccK;4^{UGx`o>IQX`0|AROimxhgj`}e?%|Enbe!$1zPHLx-H=DxL{KoAhHM%|lg zO?x}1Z=31io3r@l;FPY&VeB1EzO^j+-?=dLGG0cC`SvkR!T z#x&s??2TfTsWhZ&vYn__#do1D%6|re%ft=m7szW(XcAZ08>KE%%gJ43KhV62-sHCiM~ zauk=5Y^EPYw6VzIK9*S=l}^jdOZeEOi(Eks-B3#6H7C}mg2O-qy`1sQl8)WFJzZVg z9xKY*78x5~tCBb3U#X?*HkQWg7Lv(-*U}Fr|ER6fVD{i_G72CSwLT;>2ou?=VFjJ8 z<>Cr7Kt~gX(g>~}6&&hGV`B18V=`MYFtg`0GkB&mCdPAn@?E6Y@~{pTILcI&UVMBh zKYP1!yT1Os>db)wk{@JMI~CxQv&@btm?VJU%X>sKLtWY**^I-%kR4 z50m;+7zmC^Js{e*D@|5z$%SFg$LlvtrlhnBWnO8{s}jS3V90>aHw1k zLH3DS#EB)eft2rXTRtpTza)&PbBH5$*<&bLe=3HHB~Yu^X;2*^_!C6bnkNtCU-0~P z#T+Ygq|RaO5dYhNy0YcuAQmkRH^9PosV(G^xrRzGDqC#pDO_6$)nXl25AVYfeZoiT z&miJz{!r8a^fdu*Y7ToK=OdUhhO*>QEom6VdXj}r2j@So8=vZxj94srwZV0bx4-V_ zAClA~ku~O96{bl-1m&>De?)(`?fFiNvg5Jx3*@CU5ZYJEp}(zI zrh*D;9gP7$xo{2x2~p|Sd&|#)jd)s*aDrG2WqL)R;#@~C$3)6~t1nW>2C@l71V9<0 z$Xj}9XR7^C!tBp&7s%tYgh)H#{3d%G?QRd%@a^7uioM;N?C`%(p1pd-3W3U?pnZw{ zpvjdWt?@y-3kf_@AEKM8nI)C93RaF!!GxTGQ$%~_a@?c6t zt<)=E_N^>db*4Nvh-29a5RoK{#&gSzG|-3>(ajwpO07C?anKZ`uk z@huG?b9hgG1;9#x#BfZqR|Kr!M}F#lQ{-G9+~bI{}Itm=$WV^N>lUEZhk zg=7QexH)X%Kgl`0rbOg>2X{lCQVdra5i|i7Kw;!ciPGfqGobqyfHe<92JAZ&+po>2 z0aiep6YTL<$AfDpL)pk#!V<}X*U-{;K`>Lf0g4Bm=EQBwyg~I8`Ng>s z%mR!G8{-Fh^W#AMy-BKXJk&`b`BFX73SS%W9D3Qv3UdyGmH&LH6d-KT1~0yqx@4kp+0I0&aB;ZTl_N0 z6MT5833%|a7&vX&R;C6cqMtdOjemnT9MYPPdnt+|4O9@bXyVvH`qv9?#(MzAh+`Sh z8}#HfNYL_=L}PMwNt00<%oTsqYi`JkqLes8(37S`GCxRRz>l(rh7->qBx;Q+kAR8L zUwHF}JVl)SAyMnCSgyuG>3Zd=E(Ytv(?tS*SBtZY$8>V~3v^rV%%Fc_)@^{<6?Gee z8F=mKIBW>r?v7=a zK|H`$%UN4ok#MfD7Lx<^W88G4%F;Q;NSFje)VQ2M36pIzqv17xjo{dozF&abiEc|;- z>cCO7B4j3t9QTb0Rm%qOVU(>iu^DMnns1q4n3q-Y|(*Pd!fDXj+zc5A+!9LyW+neDb8#TtN6RcjAJhm;Cf6BVtUk^ z<4^df*XuH3czSPIgw3&scJ12d?%@1*bI%>MTFcYeh`gd7 zzW&in)G7#|*e|gaEBlKZnJWv)`kF@m+&B6_N0=?#=LcIWjk1r1CuOUdwqeU4%3C}R zj!SVotEvxC#T6HKB}Gf<%HCk)cW}qR_E>1KU)hl=P;s!p+l6TJc7QszqJ}0p97$h9 z=nYr^NIjLKfdHyt>K(3w>@&^;yb#NvJt_R4@bAQ#ff)zNBC0W@Nzf#o99mc^O@1^p zTwP1(t%!-8w!;&VYJLozF5CCxo-e0ME4lL#p^{zvvj*nild?d8wBr#ILN7cgVV z0A7Qj?D`C#ClnT89x@@$#j5kuO6PMQz}m}x<;+==CnR(G*`5D(b=tQtVIf&SI!Al% zjQa`tikBnG^-4IWJYbF3Eek{Jj5Hu_S`+1)$PH)JIN+3cGrYJ^9(6(p3 zGZM*my@fcNDgSD~Ge-+GV;v19%lz7WK;7+u`=0^uDbr5qsu>j<1IMK#&KSz(wKCKH zHK`z_p+?-tce|t^Gy_*?TXMkt&5Obqlw+%|pa?D#)kDakyC^WJSsO6uHKj03{G0cf z=Y+|wFx|-ISb*28t?4*Yk}aS+_KADDPIKGQ^Rap6BY$6fLd5q4x(k+hT2@o`=?}QB zfm0+fHKZ~&bMRlu`;--U^y7e(m=Hn(bEi7!sT^R20EE<)n&33&Pq9q#upiC9&=^N+ z_wIUJhvODH#4?8u51Ml|<@=?k*{#M!hNQDT-Ium60ykVi&1}(!5mS};|?!lBI}IZuugZX`c9leR$Wk11NWN}itnLirDD=i|N(EJo1;IwBBLxQ_)O z3bx6w;u$cd6P>r-3~3!37XD?{uD@XY-lno8X&4g}d;tWxEfw3z7g}8+5>fHo>k{cbZPVTbI2Q?^{6=9fCs!MP}RP z@t>hXZvI{{KG}-_tyyeU5%0b#99$2+;y1Ci?Oai7`;dmvLwYffaomSl9kvWh4F{~R zNL8eFy3RmeZAydqQc;}r%G}o57f}Qhb(ssJ=_hv`2D>Q)u`?D%Kx_myS0X!bco)82 zK^W*@QCI=E##QuA`*hJ_h%$kS7y5?}7ux+MZ5Hz8dUzQKfWH0y?blOU8Re^ZTx@|Nt6C?UPYtiDo7BTCd!btSQDsh6mkYkU zC*(T)Ny7fuYg*ZKU52+L$!=}+bM=qL^k&kmZQSV|jqW*{=H7@XR;_d3Fv+%gD{eEd z=vO%BFRW3uwYt$j`QaCBsHxy`!3th53bVTx%&`qM3WA8HmY<+HSgE%x@XNm^tU(Lt zmHx9WcdXPwZ_G@TO{eK-qVXomFB>$rh3=rQ>x%Z&m!{+j;n&(~a-s zQ0E%A4d$11Syk-)wBPuE16nw~$O~OTvRY!Qey}0?O$CuYpLxx;`CW9 zNPoQ1n6+)*n(>aXE}{O~@i@hf&hQY7?BAi=B9Y9j@pF##C-c3101+8I6(k>DgGYOf z7B~xD4PQK*YHj~$8<(NNj$MbNjZ$uW|32ykj*xx&D%aJ3IH>jd3y`v!Xx!{)-=~7r}p7|sp$vj z7&HPWx7UxHZmvCT+|qTnOA*~FUq2lzw)ww!pz?Kulk>Vo1|u}@0KQqh3biAXRF|X%m`Vma8xhmn z3u$<*a>zsp{Vx&6oPrb;cm3!!FYi{A3NpIzEl` zjt#v4{o_mi_IHaiY-t|vxz1B4_~41>dB`$MnY)+oUUUFTLq0d=8^I+PV$HRlcQ^`( zZ4lR7wRW{Hp^T4!;iBHni<)oL*-clb#vO!Tna6b$95&>bLqicnVHFz-B${f*0Pepi z3ArqWZTEjdPlLNO_yLnTq{Y9Ig5we^ea{hrLjmX~lOg_tkCB0n`8ezuWirVMWo9gq z$h$?|O-Y8w`Q&faaVeVK$3KU;1~#2^W5x?huTVS*-3BJ#Y$|x3`G(`^TKtck+qe+s z#s5S%wPOp|r|}{m-hk}|hrV|tTnOj9{<_2VsJ&Y>2%!lJ5OmdU_9^FX8a%{s{~3b^ zL?-AkxPG5FXmThtgecpI3*v*#A)1%>CL=`rnb(qh^|~SvvkkZ(ry4)w&y5&C8ir<9 zWw$*!zhp=WR~uhBRd(C(l@au-Ln({}>$gPkGNw`btxb_HDrONTDM+rdr%1^u)j|rv z<)4Nh*m-iJzg~d64ZNo3&=Y9(Aj>%ijx?F1_xnQnn}O#F$R~A%ZhJ(ojq3vH&dp(U zse=dwhR{H$O_9@QwfxrT`8A=*SPr8A-_Ubd?V?EWjA zCvq2CS=`2hphGaL-Fe<-%unnZRwsbk%#$QnQq{;saYtZ?RShxE%)4l!zDmtK@ir$k zdkxSL;`qU6@*=5lHwO ze;(nl=X+`U*>9MuNL{amlisMm&3n&5GVV@PPKxJjnl3Fom5YS4E}WKxXIML33Q%i* z8hIFMhKe@{`d=*J_hK?2MzRhd?*vA3RQT`DyGuIST0-FNDz-Z?>G!qtUf;t`&+O@p zLGLyaFe5uXm-32u+hnRTfhr$|=PCs4c$HchvGf6AfEiyZ)?AYV%nq@`7@{zWB6^f5OE#Yt7lB&Gr83~ZLAUPv!4iItFNtVEUM3E$kwz2V^kR<< zBv$yG$nXhFSQwj=E{7PSlD<&$x%PV7AF0l?y5p^E*h?YD8_tv7KoaRzVx_%(gr=xk zGYMrH$w!Gj(i;nRR>Fk{KHYhlN$8r-mZhx-j6a)i5?gTHHi0g{t*uR@v}{*%?=KZ` zIg9(B_Z>DP)GE#*iSBPv`G(K#(C+P=qwo%^3_6q}bu}V&OY7A68sCSYFe5}zEnBpU zK8$OpQP*4ULWGcJV1!gGl7DVUC40rfl)+DIrNYZ~a`FMp%pNo26xx%+QzAso8|MNS zadxfyA8YPxIWG|kJhB`iEI8Z|8Cx<((C{l*i~ERVqIlQ1J5Fk~jQT0HB2DmZd63ivHDz0Og%*f!4u?cpf1R@R3U z7cW<-6S|q~-)pF(#H=<5l%1Zn2GcIWn^eRAow;@vPxI+2@oHD*%?_^2*4#%6oQCa; z2L6o`1sGg+pnIOH1QpUK(ME`A=B(E$ITV=bhaKw2$xjD;nR)4}YEHuul6AlE0Wcy5 z?9COXwo{^x9@uy0pI-hcL686hVp?rMLBUF)KM>9ibiGq6kTW*^Qf41WN5o$(TBfv3 zhSEy+7}8s*kT_vGG-Pr9q1+V`wP5)by^<(X9i}YQKs7qD$$y@6_SdVhr_JN6dAu$4VTQy zYLPv@a$x3Mxh`Fh9bAhO_CS+OQ$s5%7|?lWiHX~#k+A!06+VMZs5^P9TPTl`H7JhM z0{8C#h}*n?-R#Y{vz&$CHv2n*b3Ln3kIhotzW(>m{9u19d?cnbw!#Se@283?N9o8S z>%y>uQGA^0$SFB_>!UL3;W&o|OVD59N~36IyxOvfq%`oHwn7+?qSpSZu@DYtZD|_j z9r!NIkbD%q11mJ+kEG2Qf3G|of(s}{>K1|kz@sxZgFr*waMOR>Yr8*4@cS~c3|2%r zISa+>9q?Sl9St}(YL4`m2Pm$iAG#J?y8LMdr00!R|6Qy&yE#)^Mo!XQjWkAGWtTp= z8>&j!_iqHBwq6?XwR?#~pUsQ2%kH;26OWm#`CM~jXEulB+xXU4HEaqd-jq}z6a26} z2gX?P-h?x*5&Yoyb#>MGTi4Yo;$+5J(>2#<+Z6YfTEvL{!|`EsObxFhPEE^xZwNM| zXNuTFG>0NxG1(7w2+bf5Yd0lqz&o$SkL6I-qYk&d$IeRLSc#Cdxb_BUWASA9DDk~4{3Url}d;>40Gh5R4~ z3lk7tz2s%^`Nyh3uPRGZd7gf7SGNQ2G1x9MO|QyGdB}ilAYF!>Johwp@D~Q;;0#(1 z0{yBd5@E4nw&>`-aTu?>^sMuyuu+y@7>I`x4&-#J@UdD;Ku$5^F!}8JPtz`J;H)8mihZ7?KS|IoamzJplR#?gfE z_ewpCFSijKT3RB7RErS}Dk!zL#_3PL^?BVGzUFp#>&vU1ovI9tRlN$Y^#f*^aCC4H zgbYfB=l7~1gpR5-oSf1mPq^TZ2xy3tQKTd0M=~d&>v;4h24Rhg!yQMPT&L#B$UZo` zxTc+p)%eu?Nxx=N?{$y+3)YSuQCt@l&gF&VJBF~nvX(}t!Iys)t^hAj=@1#8lwdEDD2%(qW9I}eA5SmC0bHLZcM z3kPJ(IU2{RQ=xH2yEUy0e`I;4mVf8 z&N}vhPR}I4Zn0HKwbot~!l-c>GbMPoW49wBRC*>a9ZJ&=sqoZii>GZy#HOv$MQ(mF zgNUR@;l-1VS)s-#tV*ySkK(Jy61w!2g{@YmHg6z06(AC8p9+7ElZkkn2vHsMIgEdN0k4Q!kS z`P|6P-$g%hrr(lXR{x~xwoVgQCDi6Bj(xTgHWu;OGDHg4S(^*q8AJM%I;F7NAH#oB zFd^f8xF>t{Yr8GUE~&E60S7xvND);l$7{7EhrI5*3xKvNdJLu{@Fs=5qERebO2;5h zw`n-l%%uil>)ezb8ybX53*Ke8zmOo!?TI!!o~=;z${y|D#k77}mo(MTTE~PVUpo!I z60Hv<)%f3BD z-cG)@dx3mO#v>XgP8bT574eXKWki2!= zsjfm_)|C{~3gmdd~$g_+z@Q!ygOlmw>V)Z6mlP+&D zB*YU-tb(~9{x!Z7QJ=x=C3cr>sKGSx3pl;INwX|*s6lXO#&7Q~1N{}iak7j`yKl^= zRg&zI=274|HbU2m34fZnJUKC@O;<-DHke#w(Nm`X>L4#r6FGEd7++DbvJ#HAGN^XC zuw@Df(K`w)cKf(2hV7YDZm0s-4OyTVj0Gng1e9ZA1TO1g1rl8uo*VE&26 zr**MZxgCl`;<@0>5>6{#K!VB}of^NCyH6i;46MAxE^T^$g)Sc08=WB2g-+=WnEAu45l)GL3X1%JN+3 zSqudelcH#v5)8~t)?L(UalykR1GNZP*qc`ijczsIu_)S5mtsUgxlBq&VF-w2X*_Q! z40;y;99n^=uGEQ=wvM7sN_e-g)>~ptX7>a{{26xKOrMbfj9nF!E8~Zi{yPhDbRC&fXDj0xX*cu$?n4e|4;lopy0;DBiCS0^5FT_4_F-Pq2v&3e(^ug)^&njf85JX-B4|i9+PRk~gI% z&_@V%heZ{*CxScG=3+DBG|w0Ap(eDF>h(P{uVve@JEhNx!=d$OvdonZwcm4lsm28( zwojUJd^+*F9qPSyZD{f5jJM*$3ChL7?S2tc@pWncrAAQ;v^(;51HK`1M>_QH{-pSM zu+b=ReGw>M;mF|F;;K&^pMZ}~Sn+3E6ercXKu6HA{K8{YGu`Uz9iJ z3fa9!Ij1(zk;TAkEZN#pY6=6c@e6D%rbF%Qb4vi?(zC(csbUTP)BMt3(5b#a1P)fS z&dR5q5aI0dZS7HE1-Of1J|CuXCR*$?IgWwgjccN$_-AYVnK;CpjVgxbC$94yTj0-M_ z>=3(FOBF%rfNnd8D ze)(Q)gLJWQV)jImSN@`wwrpqbe?jf1bIbB}2+hzIWCT?ov^i&s!F7N2hbYFdzjk6u zS6GD1js=U$BY}f;1@0L~4*Ey%+2m-vyYBY&@I zGe*sPx9#eX{xo~+0*=+OY@WnS49WzNE@vhqOw8;L{hkN^6iZ;!h6%r(Hn#yk&}I7o ztfF=1=YF9OvXWBi-OZ;XtcPd{2ZC(Cr|=97aGzj%0XYQ^q0bKN-lvph!&%Yf-gGxiQ|(=Cx>p`kZKr9d)?V&d>JqK`NCMuD+bWeQ*LM z?5?|%G+(RN1EZi;BXEXAd#fz98Xwfy84%FZef z2E~{r5NLtZq(2c!uF08-OL(TUy*QgLMJZYc%Fv`ugB9#qlOpr0dFH zRP}y!JWg@D(8y$xCrvYMGW4{$QGXuhQB_}8P01Ck##kZewh)EdR84(w^&3mpRhVH* zJM=A!WW%GMKBi1=(V{tU&4-=lfnM$@(BQ&<6*#x+L;4%nZfoW2oSl1KNN(eBjPbgg zerui?cGZ0Eb8=PROulHk`}*Wh^G}lx->o=sX)oaP7bO3JX7G1`mV2g=zOlYOh@qZO zebVhayB^LrDssWs*K5w8VGlm&f#Y{wjwq;WJ`(Q#X^_5sJ;0v)udn4V zJvt}^K~xNVD3D|eD24B&zP&v?7oY<~uY+G-6LNx{peXRd4hLV|D7fKzg3Jnt5uaaQ zL=&lFJw48FG{_icub=}3+_P8dq2=GFGK6Yzp*} zK4g8qHC*=3A798UKR{@1RaqCmXYv1ATdgmV zwe~FMB5shN3ElYK_NNu za;bVguu-(y5Nd<|^PH$LiM@4i}SGcP$wkqie8!+;S5`K#d&yu(Gnbx>(x22k@l~=_vdM2AG~~M zDYxs->#-#rn7^M7lpSBZ9QpAI$Y<*ID$_HEFUS1bwXHs|Anw3S8--Oh3}%!|oU6o-3+n|loMOQ?KHkC}I`y7No$ z^^1SbOOW*Y&<~*Yu3fFJ^Fx+`oO!(UjJGkXdRzRN=CASw0viN6M%4g3p>)~86h}1* zPj)o7MPYHO&hT-zA4tU zo`C_8EO%}m1e4H3x(f41pXQ21zB;&7A`0 z0VIpNzab+kR{e;I(cQBD|C*r27(QeNh`N~p6B!=Vj9$4_D&VY@%}=xcHMKOAN&s_( z(46n@h1!N67K;UwN~NEJ%B`#L&~op4E)M~)h>`JZGwR|8ZsG)PWSE0KZME=r>X?d* zw)h{(a*hx~j?maAx&HGt*LUudl9&gQZvFy}97^kY`)J&gkk#{%;2h$-Lq6Mx+JxYykO-v>xQXu!y|-H-j@-B*u< z1|Ga0J>Ig1gFUyphp+#E2MszLaKZ&QJn+JYVmLukd;u*Ki6v5*T%lxCYK^(pLT71Z zZDVU^@5r$ey@LTMAafUP*}L+iVa4v;0`+SE>(>O{uLYuC8$?brMw$t-Op#}XB6E~k zpvn?;R%o(Dn+>{b(PxJtdyF|?$`Nx;SaQai3$|Rb=Y~`6IOhqMJmZ=d-13Th-tfpf zp83ElpLpjBpM2w+9~}9`FAw~a^fPGd;@!~R#e1Nmi|;^Z7vG1jE`AK%UHk+RUHk!h zy7(jXcG(DhT_&Kv%MuK9xetR~{uhS&a~}-9$Xm09x!X&+K&*s;0!!!c+%8eM{}DL2 z#kSWtL0)+wi}YWUajD0$Z>%M3A}#$6B#hpXK%6aBcF@|v9TO(GV zTSqSn>l|_`#dGw*aDeOOVsCBn-79^sa1ni;qaSN-Lqa$gQfITg))FD z2L{|@K#zO6op|IC&uZ4EWTCoJdGCdXP&}zDq4CVu=B)>+!VwgNUpPi*LQq2(Tq7K6 ziGUc9P)8J~Cn_`$4W1zS%1#LMiByWE?I5U0pO!+iOLjH%MbbY9?Cxtx|2|;`Dt1}K z<4EPnF(czd!$vf)2@Op&jH6*Q8n&QeD;l<;VLKXjpp7JeMq8n$IkKiePmV@Uo}5aV zFxPS~0z4Z&Sf7wS03#@}E@@hv`qW#c5ghvSNA=>CuRD}(S_1vCe?X6o%D zgTM!_R}7&dmvgvWm6U(S6zb}T9OEj||02_6P*=o!LWY3`Bi*5rb9Alk) zagY-ZG8POo658`rJzLAk$mca;VXWHHBjd zo{FN;QsQ)}g|sCv!AT8WSCn*pFU?#s;0MoWahpalDF@~2SdbJ3Anm(H8P?6F1~gii zUR{0>IB@dln`Zs;Q^TfA{eaWpc%Cho0Vi@cZp^%HU>@y8Lmq4PCPTJ@h-sP$bSKee z^Xq2kXBIT5WqRt?9ExK&eD{l5pT86%17_kd47+C|)5e<0kX0TbzY^mw01<@~&4;X% zx*&!1ri5CEENXj)1DixRw%4P_P697N$s=X$X-bLc~Id z6cdsq%VCz3VwRL)mXu>wRe*Kf#sx;5NRSr znhBlO^0EMv(lc6LS!ePr-G&Oea>H{OD!KL11l!fKb_Gn?6cAP&3rtOj_Vg6KmY$Lw zB!7Xc^$Tz)Aap9Aa8`ZO*p;5f?({VFq^Gf0C(x&WutovJTIid>b?F&gpPs=D=^5Op z6WFAHuvq~|w&1o$Qv1fwl-PL+R|6x|0|Z_N zt~+=lZvtp@zkh;{(NB6-3xxfP zUgnp?Fth`3Y6nlMUIT>ez8Mu6hKtHG#f7TLqHB9b})37U9_^|bmWXs}NeigwBy&ScCUxN&E)Do+$e@JQ(a;oM) zO2h(i=w|mNxVBh^1MX9$6fsq{dBi#hTu#}Ga?u5lQ*RC|^P;5ZNE;TalZ;s{EHTt{ z5rV}w2Sm+#xWKJv0F-mcE!1G_ifFQZ#i2}f4N}PC`#Fch^xv2NYnAPo_}~BjW0rnr z*ZM2P>OdVGv#k-|{A~t$aJus{?gZ7(Z{PLZzALZ_lB+kY}^c z0#iZP8p?{VHyS}U12UbgnHr1wG{ctj5nDl46aoH#sWcVbvU^0&ossvCl)DI#S`+Bx z?a-|*7Wu1}YTp)wG7>j3C0EF?JkliV&HD!H<`ceb~@x-B715D#j4oLBy6|Ng#WACvuc{ z3vgbJ(2edwZK>(-Uz8Pgh*=);8_HgaMonut-1pGhf=PILUt8}7ryC#%6LP9fK$=~A zf?YvJU5zbk1q~odFLS6AXafV`j3NKkBnxF;(e^W|k-j>UvI@)drKv4F2iyL3YV^i+ zmwKE4t~Q+lB^R``=$u=&9kekqHN28K&r?BSYYz7(x%E;CtB-2}36a95>(L8nn9nh} z%WOVc4Po%}tFf??d^#U;0q44>Io)kb`WDdRDo^o_VQQQxnK*oPEu~WXUm$L6`N$TP z3L1`01ewh?9{HVJ>#Y>4eFmHV$cQ4fNyx*GvghZREOt?HD5#)Txt>Fb_Eo6uam+&I zKnltKK)PfZrHBa{gRpP)#tq4esjo{pitxCY6rcFm1!P8Vu=&6t)igFZu<4*`NE>Y0 zyIHm1`g=DY2_2o|eSQ9hbwk#SWx!L{%v+naY^Kyv=B-^Hn7JMHw3SHVRiI+^UcIB1 zl%jH?IP_|y=lWJ3{M*I61Ji}oSDIMB>5CO7+f=i28+LxQfg>q7hd{v%xa+FTZV7SR zIeYl!U<415k<)9{8SJ8xfmEq^j-wr>gX$EJ(j#j@oKFHcbWlAU(Aw!ra~{BOm0LGX z)tKyj*U{XkiiF)IzNUw(p+LV4sqZQOx@T%CaU-V_(*s!OsjP9>lIPk*QN$K-dTqtY zS|JR^!5fCf#%Yo3Yj&==PBQuGKN{&vGvR^~JoW1g&P>6W>}FzmBPW+N#w}nPL=BbW zWf$A&Fk1*~kCy*Jrq7{hUfTRCF5uR|`@`MsJvTC;$#0>1jmr73QtaBk$;=W5ZSb|j7Xc+)%1#HlEeaGSqBQ#i_n9N~K&I^vG z1ri}_&P_b#OxTlT{AZhB!wD6<=~7o98Kp>uV0&RDI3WQ$m;? zXe14zcgjn;7PI1f{ddssGhSw#d176~a(vB?YGsXUsgD&n1qlb?)~0kEEqcL$9z4+n z3gl*bU{49}q)2jpSdvvw?Nc^Gmr+-7rStE-0MaomhvuQzeDMUSM5v$39&>vEV`dqw zg_1*~dv5L>EdYx_Al|To6-^!EWC3G}-zd%dmQ;_Q6-`kOC|%-rc#OKR0x)Hk&1{8N z2>GCB!*hn2)kiE9>KZwL>PY6jlJ4E>KJ3+`=uc+-$C|~HkNI@_MW{OGi78fYV@xs$ z*8dQ)qDjtgFkA!$`-i&WV&nRg(G`UKDM>2CO4_h6tePItQE(1Z~%H#auko zBOa6DaqY1b04xloJNh#2Jchhc?}*tGl8=d8Q!}1|)0Myy>en;}mY2KVID_7Eb;xq9 zJ!*?(WPBRFTDcm*kAz48R|!*qOx5G_2SXzJ9e@-X?8|Aog>3R$Sxvm)UeV;~+4AA# z*B@$$EI^Q2*-1kyxIW7n3lKCYMJb@VGFo%eMIeY&NiNWXpCBC|AbC8q^+TLqw)#I! z@4hsr<8w+}G4Fkx*7aApA*Q$1?dfu}2@tM0*)mkd>LgP_A=5W0qCQlYuADiTewI)o zL>HR;vsP=blSk(r$%5XE_YQ{LR@z2A+J+<3N<#_n9=Rtxac^`~9~g-R9imD`PKe5%S=5{JU4TU*a#77MoV zFy=hnMR%uD{b}}xw;qa8H--|Ti!^T?OpRuqh>Jh&Pq6ksWg3}Zv54uX`xk5M7_?U+ zL01~Muksh}abM&^h;nZMo})FuhsMGJcOC|Ho=S(<$j@82|7f)@V_qISlxZd1y;ta9 zqu~VEhJVNX{fvJL9_kwCF8akg-rj|z5$0HAW5%kjcQlD8%`M~0tmNHZJ_RS^WD3d> zig)eRw)EYhS=p7Zbhft18`gze)}~47y^hHV>!We2b25`z^9YOD9Gdr)T4XxnwQhUR zW+d9bl79A1$WdCu+I=Xh&B(-m&dYlbs?3&c9j0p=(%GH#afnrYtRYusU>osti_rV?bGRnd*Yc9zPPC9w}m3JSZ3(! zldPAXYcQLS3tZt5;StCEj~AIw2#)XGEwp-tC;WL*j?}QGTh7C31_nO`2m0$U-ihA2 zX0^?4p!~2QGt=YMzKn_rd-CkcMfBCSc&)BAbH{(Lc??Ko++G`w4o7~1TPu| z^hGrq^g{L{8Hsix5Un)FOw#x`&)xkgRMs|VIc^2&M053W07pNU;l%GY< zO>2{}0#b}TmmQKF8ic`i5uPz1zNOOih$#u&ytr8QAHna=n!gQ}vOP|D=j~j%LUSeM z?fs;sv-}$-&Ctp`?^Do3ej?-obWDCo2%=AfMybVmc|Bn@Cp_anbeto3xW1IlDXiuO z;%iiwAub6;<%uCivav!F_t2Co6*nQ@A^7!86}b_xarEo=GSzo9>L^91#gBlD+uvQ` za9-?ilF#;bp9I%9Ld9cLGAJDSY22k7PP?jBpYS&_pE8SA=C?UJ+gcG>n$@dmDzK+| zHqb{IS6o99c70u!-Ks6-s>$|jfhMRF;m|MRE}d(FSepe2itu0&(_ekn-vw9_21^dn zy8;|SUsWjyQuZo(6&3HRA|!m(jvRp~ZbNJ1ZjJk?ql#e1AyXarKK%Mhe&H*k*G2AJ z6NyFh{e)f?PPZo5T{^Ezp4Um;gS#~r&fWr1k(lSP*I;hi>s8I&Tjw;SEA$TOZ6?h8 zM9J0zkG>{w>D0p1Z2CtZ^O2y#Idy9;Xd6VnxX8d&9VF4lA%Nlyk|e>wz}uOxXVO*S zIaWZKOToV~boz#Vc^AvGVPQF!I`(Z&P)Q;|5O$Sb5F5F;$X7JnqItk6JcuabRH$|x zpoyMRhY|L4No`c_gQPmo-E%vZ{<>@|TCv!@$}QDc97UxpWttylC-0Kr|91ck4PMG^^Zhtx?s=D~i(N zu(Gnp2Tanj{@uGq1S7k5oe&%^GOr@MX`JxCW;SCyZ_1x3nLz^D20ONTVB|h0KzE@7 z-)M*4;CX5>ZT{cyn1uborceInzPO}Y=UeT7e&5fMgy3jkaj_(DRj>4$jK^gb$hjcX zU@A@O-kXr6%*}Fh??#XGTK=!;nVLAa#zmPL!!@!!w}6+`3|fj@-F7@8JR-s+a1|9fJ$uh__vefVMvn9z2PY$a0<6BlAXN<>Cc`%_ zU(CUSoA|D2HGkB9)1iZ6nPDRy_|US$gQtGvPqbZOMyxI!2UhUMlgHiHul3g-)zCUb z%NhF1Q9nyO(Q}xBjor^On(I>;wX|WHry;aKfuIZ`FN;MLt7VQ`RR&MF9jc{v$c>Eh zBRy2{yHR%-u8S#=y4!lW2xDORA2vneq;%fV8$5KTDp9VR9xC4b4wJ;e!a-`* z^?jcE>MsO>Sa=YL`N{5PJ>(YLoZhnQldeH&|ACZ22LOC=TSQWZacB?kY;DogQN2He zQP99?xIo$U6GA^A1gj79g|`mvN=C%~_$Gr)eCXgNzV&;xV90;d!Gq#du}dXW)z??r z5XJ+g?6ea4IE{AWqL)CfR(Dig>Ao}oie(hdCx3aaFte~;Qt7mlj&ZcVE@E?f^4h8` z|5g7NCe?Gfujc1p#=P|L`6uR|)L^4SP0e4xOMc}E?i@UWj=>M_e?RM24!`>TH^Eqr zMFATXX&@cX9;9^+v>Qzl3YY?O4DcDyn*2D zn5unqw|={7GsjlI0+`Q>FjaO7*t4WWzhV3RcN@_D?4oV->F9}bZ82|y#EYn(|D(j5 z{~$s<3AtKBpi$~%NQA&89Y^KL_Ba&<8vMO2}4G#K25=aa3y%Jt#K?aTDe!0MI$`Y__6Z$I>oYF0TS81~RWa zXKg{eWkphjufR-Rt9T3p0Pb&o_l-cjwpAI540wZl3ppHFbpI$TlUE&1F9WDX>ZNS} zfbUHYUXxAVx@>2H8>*8cJ;CXhEtf2DbyT--f3tUz0wAfA`NbxdPu7RRJ+w25$LP)}tZ6YsuA_O2TEmHz#6;pX7^{PvOj z6+FkU#n@%XWB8pIN#53(frN~!oV)LlJZIfzZu#k7uPjmU!(=*g^lWru2od|iqsXg~ zlP4mF;=nkYeyGT{`Q5ZD5wci?NciPP`Tmlt!2g`X?pO1{{T(ImvP-PatSK$sMR#7O zyP!sBQLj6FwrX-xb@%z=m9_$hqW~zW85{s=GIJaXKD6rS(N(7YvcSBR5*b0rqRZ55 zi%mJzLho@|tg&u_$~Q;&$Z?ZuLd7(YDF&vIOvc%g2?Lw>_U^ae8ktzmr_jEQ3t4DMT@Jd_uf zu#`v@pApNJCGAgGlJGf=L`vm;?;g5P#O!JgcSI0)ra zP_Lz7NM%aQ&t|Rp=a|x%M@6}5dju4{uPs~@-v3Ls!?9+*m4Cm=V^6im1HZDr=>L@R zA5^>Vsd6X#mCeN{Q$jr@3Kukb1`r8UPSPDRg`eq5{&#M zbj>wU(oM#Ez`T>c5tV6p!gcNO;^sjuc~C>X@C2E!p{K+U=yY2LkW5w^B#|X?>@Y`d_#rnb3z{pb2}f7H6sSn7X0{*fw3EWPC0! z(4_qifwsY+4pkkRUJ%p9$+3YVG(pJZ)?guv z160V1W=Md6Jt&h~5c2{Q<|f>*_mhhC0%VGz*5_yjhF1|WLY^|enG?S-TW{zCy0 zU$#ZWwrCTiM^`w!14Kt-hsipmyZ7!c-JUIUc9c11?g;Ip4FJYVovG`l=Mr8uj3j)T zKMUNfS*?(Y4w(wX-vLNmSJ0hX1?lG@=%-^=3)S_Y7d_Zk0C>#^d@{ooiF`7Po{4u6 z2>?6>MIaht7J80;i?lN#*NU(Y0KlsP1sV(5Uz7zu2VBpRjo=^p9gG+UWs?@;BFlhL^Qx(T=FgT zM`MngL+_v$;@#d&Pr}5>Pk0^Wgp+dv$s7*8JRTKAoDGzBt!X=u^WB!q{pJfk008b_aMyP(#i+6=T3MJrQ)! z<`S;dU;{a7p*>_IK;+!%PYq42b+^#(*_$94oujkE<^4>6P8W<)>K}FZp16~4W@z|? zlh3eJN%IMM%{pXLMJhv0kfrPZG8oZRWYnC&3EM$PiK0_3+tOSg>ZTVJ+zakZG<6_n z(^aJ{32G9I)-#LY&K+&0EU0kMbMc?0MIX!jS@34f>V_Kb0L5^Fae;vaxcvo32RrG2gGU$Ug9%-U#8qV_;ud0~yMmZf%C9RpMtIM;~LqEdDp7+etl@sYG zbPOE)@^0|Tj?Pl3!X*dM> zx|BUq zEPL>AG!+1Zra=0xML6YFFP)T;B2PkK)ug}FwWt%&6MD{yU}pZ z_t(+8WXA_!Vjzo6^JlJ;HLC|AEc_-kgxA=E18LYpL1C6XNWu~(ecN!5VWGQve9T1;}{31_jSgVpXjd$l($&+?2>J*o!yvB2iZ?l(gzfEgkMS zCD;b+&=q zp{TB!dmM7(F$W7VrmMM|b7cf>jJ8Tkh!e&(NPode%Vd!bc&iz#51gR0GY^A1+yYMv zlL|%=b@$kfOfJl}xmL4Uw(~3vDqTe~$SH!Zm?{fy&PCmZeN1Y?rkgzPV%K!L~H>K&|7i$vmdC{Y@!p>ZHN32!up1Jmd|- zcxIE|{KoF*pH@o6xk7IODKRjY=<0G9T0ftY^mGGSK9cfD7G`&BE8UzE z^zn!?v}{RhF9^x0W2c8mfQh}NZ?;t0LTQ=)roxNvt%GgAjtYgyNp7x%YwUfBrhPPK zwG6e!F=(dY0mieWW5L>kjqGrqs&Nvw^{Mzs+_LK8*gJUnCUS6QH80kvjHaZ7z(Y2m zS~Ko`-9f7{57Zff_gafQj+CHeG9J>LjmMBHd!_?`{A}r1QUEdo&29{6gyjMyidKXOn~p{lchnY4M7*a;Ey%K1f+FRyTqd={pW~GaIBy_?Q#Lc1O z=HeEJ+s!IZ;va3Go=hhZdX}*}xdCdvhvSF3ZihSy*WZM^gEriPQ`v zeU*H`H4g}XF8xl2;PLPt0sj!9JT3_#9~|SEnz8@zSX(}O0T~KT)nGn<*59&nSWIME z$WQab3RaFzhV?eCJMr)(z!5srrAbyik(jkCu_8G%(Mhv$jbesf|3$4ldk&F-zWf_{ zHu^?cC(Hdu@lXo8S>MXNogd+^&7lMP_Kv!S-*|ms^QJX@&gVVn*~&?2ySVl6!QDGc zi}Q22Y&tnM(w`h3?Y4`yGFcLZl=zI9vex8zKMIf)oZwI?i<@wdYh|o*cIg0|0sWYh zwV-A_r?Om@T}9bB4_B3Z+K7EDKCl;WPfcE&$C+o1o*GNR5Kp0Y(^1Ev#p@Bi-0n!> zbt6zi50CJX2xVa@lN>z(n5H@c1I&U6DcCnDi0}cyz)^(=g<1Fq{uyR76El51?X7Li zic%8|0Dyp&OQ9v+$;b4L{~7?kf9i6zVqbF^h?4PPMK|6j(u3~ig;VjD!Wy==Y(Z-j+ z>xX$NQ?J&ily;@1vmuwT`Ov2tWkc+pKZ5>T&!K4){uc z&Jc;OGD5)*8AIZCbmd4UFydq;k=SJx_y7-sBc8x(nDqOw;u_vhGQ^T4Bdqy^FqiV0 za8N$V1fHgIk)WK)EO3_2?lIzR`lbDVDEG15_*lO|9g8lLl@{O5Kp_UL)SmNnxjgCb zSCgN}ce++>dEaI?GY-jZtvprguU5C!XvN&I249^^7gCKo$0Cr%A&&4YPEbY(JE+1y z8`5Z>tNrNhMPDg4f-4LhZZUfq2Uy1*46Nf6RqQMk6%-bVZ4n0!QB-1YuO_frjNQj` z@HEOOXJWCamT-!!wlLPucFdN|Y6VYe(eI#Q zY#TC84BVE1oV8^Jj+TqZH?iq55;s6pi|ROf+9|oRl%YHf3;gVTLy$&iFj-hRaKVvF zuDIqSd=$lSf~5EYS|}1rq%yfe$*9yCbFGEW(#qP#*3RCMV<&nCr_O?l&M9`k6{)?Y zXm#Avs+hl&@^7G|5aiV4bNN6^!8tj~Td{tg@*ev>;@8g>HDITr+~|J{sq2vf&yhkc zBt>c}QXMI%omTmEvR>H{yA)L(ND3k;s$M@^>^|Jy)|bj|gh#XNpj;%lrHX#A+!8}u z=WUcrYUy>a?^R>iWLaKDx(7wK#eyS-6a|e@Zp+o3(+w#Rk^(paLB&)kBPlQVV z7gg%1q)D!%&>=o7j3*(qd z`g>XGf6w4N^5W#QvZKE-Msor<&haID`^?%o(Hm^iy`kqkI)|D%2Rix(cHHyJ0Gz>$ z;{XRT=W+O|+u_Xmw>Ax1q;2_^G4H3x(W41pXQphh+0n3cfB z0X$*+gpmkgmY#rvA^&so|F9rayi>5aI}fB&Pp z2-cI;BpEasA<3-&eLuC%x%A%GmlPyr?8X3+YGOAzYE}|QQJNeg*Kg1u?S{9E%c)sS z&6aqDXb@nVL-fd9kbEnx69)>L28}XjmmOn$%Dis%#UW@A9{~b0jOyrJY&P*-wMC9J?G8z4JC4-W0oBWQ!tQBhw}yQ@Zi9^l>9zXuN3ZndhO6d6(Y!+BR?7vRiuFmUYu^xBi{Y{*Tu$ylid@p`r3S zc%j1+6}!D+M$PW|s&<8GGPRQePehh1f55kFS0MOL8}02fb}*;@OG$f?Hg@d7#%)s= z0oc}v(!TeRa*_US(snZ>Z8r`Nq40P_f*n81zs_|1Up}`A`+}EZ$OUv>hb6cbx9#i8 z|MLHr>{vReEZ;SjLyoSX^96J&9+YtffK8SQham@jS0JA9I%Q0Ut;5=7O1F+H(6H^L zh+P^EEFdHy9AL}|y_i0H@%O$uXLj$e^wFw9>nYV*vE%{9f)Jnzm}Sj0kT6bg?lAP% zXMgrHEk-lOM&wRZgokW3`D>uv!vO)*uok-^2M_0(f#&nw&K6)H4ErL{;c0C?->)qP z^4?My48fcX%z%1>?}7tzOTGc%ZFfIDe}*>^AaKQbStIArD&RX|eGlIH;8X)1*Hica zyEqaZqC#ECPrdBKYTV2y+?$}NX~sE+VYGOAhnBxP>fHn*pMI-|_o36?^sav;tlFA; zwkAMP4J+h5f~rrLz_D0X<(5SmT6;^0_$|JNf+DnuuC8N3~zBZK*U9dF1#Y+4yu>l;N1llyU8$ma zX&`;)J;4(MH%Yqz&`nVbLNKr6f(YWp7sSBu1TWv1(iS};M$KrsrMd3jM8ty$XgCpD zX-INCX;7!bs4T|!JZ3i5%Jhx*unp11Q;&ZM!Tn)mO{l1|MFvg=47l@Gcxt~o48i{i zN%_?@YO*uvkR1e19Jcp6Bu-a9ZoL2cs>Iq-=kek6WEfI~zgx?00 zp*1wkm^I{qrz9ctw^rhDtpm)?F)nG6_k@=`4u9Y)m88y#0E=wkgKWb)It$27+>Dd=H+ zH>~f!qd9Lw-eG-Y;IleDuO<-a zza*>c2SHF0emKg=e4N(Q!~E@@)d%_aX*s6Yric%O?d)KJ-iby*PKhBgDvTOqfHA~q zFh&?-?0ybZ+Nwo0GOlRJaobWSFNL1Z%{9LS7unIFo3;Yb>&8UpBrS+n?>><`!NEGd zpUc+Nfw7h1YM806bi!K`P~FI;`{bot;1k!)J4~U=Iq1(MOg_5Cj?FAW4pQAGWF+Ael*%NKj*?%kzdQ2QP6&M$aNVxW zQQ^wg#Qb({JD-vpksGw03VMb>$V z&Fco%$7U#IvE(uv+)@WZ(^L!SMxybHj~kz?DX37&0_(zCk+q4?<`=a-?-e}*#^T@* zcF#%{oHvyQZ#;tAP6OvxfUw(7sBG|3VL>{KAKsw`Hm^6px#=~|LSsK1=FXS9kO4d# z^MJQ^gQrRN`~|{}phUNp4XBfQq0OVfc&prph8b`xh$-4aFlWQbJQfoq*+M9%s&N8v z5hf_xM!3kv(>M-}qvPaka(|2u#wX*8+1zB-59^op$8LX~XcQWiMx)Vb3>uThqOThn zb}DaMSlf%^U*sm+QEWOSJ}pqL9FKdDtj+?4vw&K83G8BsD|fLfcWt}S^pw@}Q@IPM z?gFkoRed*WayM&pH|ugY>*q)t3aE_*TyKK<9yaG5w&WhR<{q}qk+v65Jq5hqk?=Xn zs`me5vFLM<=%G{mA}gM-D&v14jekamM^;7ZFA@R4DX?+g+Kk5Yc=J}E{2NbRBCOxF z^YOK`Xh*=2gJBrq?-D{*xWn8jhU2^;TP2JPoV;BuJ7x(lewUBthC4`e!I;@3RV^A* z@D~+}>VfMxoQJU&xdrDgw?bY^r!aiORt5vjshAgV9!Cvt8eI?iT;tDO%KAcdI0;QN z9VU$$$0pCay6V|oY(xC@vrg?7I}#Kb@bzcG5qu7 zdiDj66`y|11a*0$qTN?<@#w7jh(-kqPSd<)1$+f+m}CZH5rR}$0Q+zsCnV^ng{TSm zGquhHyb2+@p2}(tE>cKk!YrWWHdL?{mN(bICL!GlV^L`Yg8u#`aO-Rz?H@6R>>rDi z$3lsq=xN9zgm?e|4L>c74>Jvm6hkN5x&2%`?V$OAoLH2{Zl}|6t#-+yQgW@eF+wR$ z5~KRxsnMeHXQsK7N|@7t29}#^sH_dCm6J9EUvH5O0YW^2ez9#>n(m}ch<|i?oBSxU zA&VW-*IZro5Y%U|NO`5SX^z1`n_g(;T2me52)?uOjh>A4_WOGP2ES&NSZ4x2v2c1~ z-#dd~mbSY-sfiA+lI^3R`wRp-+Y^gaCZt*Ie-EhC8nX4$RqDLyW|74uA(e&9;PI85 zqz&>v=lC+yq-OAFQSiYCE?2mg9Xa(z5UT(fDO8VijrWt8+0>_Mu~?h~^p8}c z5nTK1nz?p=_{}4t9*jvZj~(%9@a`4W__rWZHZwwH1fr(eCUug&U4*o6AZvPvg?XM5 zK6&}C6SS-oJk}GLEro0!=En~Ul^{ZWuhb!`US^C*fwUQYpR0+)yn4@B?x5N%%=&nK zjIjt0mk`lDpn6&=*93D^Y&y``7T?=NDw_x^mTS(=t9G&{6Ot9OTBb$zswi$#60II& ztV#jkh4ipGPYwinma?-70Ixi!A!LTE9)P>U#kz_Rx8`Po|7_|!nuH)xf%RkSMx20I zI&6EBbg#E)918RsL&tGqt1Is7bF}uE@fPu@bi;gVW|(R?bwPKrP5VC~?iVO)h%q^I zl4?0khV*npxy+vZc7y`?)twV$w}~K|t+mETthsT1Y_=6H4XyAXmG0rZM;mUekP;DN zi1ydNQ*-lKy@cHYQF|QI^LtjkUd~ktW){E4D2$4<;`}>|#fN6B^&Ij8(1Lc|tuEIt zUV)JGHT%RXr3wDupe4r5H+sO$HQ4_378ki53iZ(2MCd2;#k|)aPZKY>dfo25qUToc zUb{zhQT5s#>qH+$cC6d)Ixro_&aBldhnUF=L6}-Tb4AR;DJZaJu2|)mvI$1^5`kb7 zNUrj*cB$Hic=>Q{@aN%cx3=8C-_KoS8_HM|dmvxFGzo!2!AaCCdw zn*r1fth<0ljk9&m3b-A7XDQg6AK7}?j>OJA$eitd_r6c1TW@zc!V3YN6Q)%CcB6i< zFN)GPOWRkJd8ePC11(?;!K8Z{+Nvt+>Zys2Oy!^TEJCAr0P1L%8ZF}Ebu_BvC)Kkr z3w{2R4-kw(8(PaT253eCqZdWWN6U-=BeT@fyee-uPSgH@M?+UHUc3F`=FOAObdSXb z^8sJv-fowwcSb=*b4TgUmNv!P2&yO)PD^$x4UvDo<59qU5^_sS&-|OXQ9n!ISGY;>EVk=$Y;7wr6@0 z`*97FKU|0E$+voh;LiOqfs#73c>@hOkU$2)CJazt?fHwvLj8FuvS>Xb4dv047Yc{O zC#iHtaZQ*ZO>D8ohQR`KhRSbi`w_R?z{qh?BVq`_t)J z9FODF!Z6I(MY40*q;{%2@GLA={0>6|Z~|LN1j^4^1TU4+R9?&`klDSw z9ijw=6)c)#0ui-xh{LH#HC4qoI0pc2tcb4IiGKwd2Y`wUoznldMV|AE??f1yy)MXggpCaux-56-MY-iQTt+XQ{pM=T)oV4^ey3C?KaLSk!QQqAc$hF1 z5ySIJCq#1P2z~w+mwZJy%HkSW(T#)odwu8_{h%N9+{=y1+Kk!|G&DzwvflQwkr<*3 zsW0WN0K?vnLhZTq_YUKh&T%glXa_nB0dK*R`6;j$Fw(gZ5kgZ6JWMDt$r~_-E%_<; zp?eHR@qQz_rEu69vF}7iwYW4=Bu|O3;Abr|Wj|;9tIpqka{`@DZ;Qsi9X~nNp70)s zJ&!B;OsGo4`9WNgqwOSOwA-W!RJW@p17KsT?69bGaLOgvmY1s$| zV;p`$x6r?3U^7n+FWUGCD6SNSooi&i%wM?2e4Y<3=-vYB7O|0a$S*7~=UE`m6VTur z`&BFRZ=LQ%!i%HFj5ML$dWor{jU+lL#{ZS{*E9abduVJVc}b_k-n~YciP;i`+te#} zUel(Ch(79Xa?a8lCM^mmCXM9L-aNdtFnLjz<#? z&s6qc6R!^u&93<%saYLH-lZ>u)D05vHw_HyM>PaWH5XPSLMof4w7_@ zS-#z*37AoHqA^cq_O+l{b}=1ww;%X@bv3=rO?)K|%VSo}wdSs%s(*~o;7-_WxR?3y zJxmbkHRl`hq$)<0Mk#|4k{y+FRWr(l(Q8Ei4I9EUvNa_HDwQBgN)!>Pw7b`y&u#nl z*Dq!k?uloIxZ>jCUl)pPVwriv2FVubSfkB0!t+MQM8}M9Mv85typjF;HL704Q4U+` zCpB+eD`z9Mef?j6eZBPvd#&8OF{gcgD|B~jb~feZWp!mGs-5-}MSvgz?f3PQfFt^K zur~_!LjFk9QT~p;OG4 zOwG|TRxorrJoDw5=vPA)7l(L5?sZ^n*~{vE!oX&F=@#0P-XN`_FUv3B!cDg&I;u3_ zJrF;60wUeFK6s~SM$#^dxdiwVAuvd!)rw9PUn~D*VvRN-$8N=?Bf7+=luIZypkM=0 zxe>m38;&WBdSpRm&;tryDn;?{L(4!IG4+OqZ2-~0-tCL+;ZDoLe`yLz`feG9t=#?j zZu7NzJpTjNc7bQyu2Y1rjmj_MZ_Vh^5GyW0p645p8ySYMTmn?Rg@0>R!6UjPv}bW~ zh%+R7M>$T`v?>EF5Z)9PA8dxe2V+@=zxyy-b4{y>Q$*T>G1#*EgF?6Gbe9MJzx8Y1 z1UI@P#p47#$RGG|!fPDNJg?D=axC;G^m6NidvbFfm9b?x>$S~RR|d6_G)z19gf8*L z=Zv{+x^ke}Txu&kNr3nRKTmj#UIxBSyD%(uPmr{=t;wbQe(b8oe3OLJUFadP1CpP)iuld3dpE`+@!Vj(zuj-G zHk>S-H>MSalpKCQmmwUq3W~*S%0aWO`JjId^I*NloTV_irB~_lprZpG4|w#xu*#+v zrsuLg{fsLNJFc(acuLnO2toyBrs^n;H~|9|0OBO!;lO*U?`E@9(Rv4<%%h;+S~PvA z-`qe9P9#cyrt45ovPu#Qf-G;@DY1o#3W5ZKt=b2EMMs5-B$Y_F8PLX0Yoah$mZUB& z??Gxk)x>Yd-dkUz->z4k5Gbv?cf5CwXOm$hYBPNXw;TAIUBcW$afdA%o(>KsvwzMe z3?fqRlDZ+E#FT{AN3*BZf)+W|G!S$N| z*ZT$h-tdCY|6)ErW8556O&8tiWk_7CcwlkS%kx${>Z^WSZihV!GA*LgW*oc>+sl3I zmk(+)5S2{(U-L7vem+f$G7W-iWe2VREw58o4s7U%uJ6gc?lsa#i4ODw^`#oTE9)Ap zK|$wOb}^8S&=eXNL<(qIE&=^aga)H3$4o=_oq|UPN>Ha#j^XFcA&z**C@ggk$;DUh zAABTyJkhfdUYzy2Nw|FYLR-X@`+EqYskt2s{NfN*kl5omV;>A8`knLppESK-K=gDR zUMf7lYa}K*CdSM278i#m{lG|&GKP3VM|AgNr3p9ikcLLHR5e(L4BfWunWIOybG3G(`WfA?uEu}iRmW;z@9lY}Z7 zLlnNq{Tz#}A%j*&93)cBk&OzWh=v(*7zD9K=Dt#GrpjG#9idBZp;f%TfhhjKOD1CX zV_mlTgbET4+aMPpG$jAEh9n-S`HVbhGqT-Lj7(4_;QT^r;PGLNVh+09EE69)x}EE|qu~v3wjVtz&JcT5GF3xEB@J#gRO*{qN}3?z zVZ5YL*xP0fYpT`=5&%fF2v!q)Ggg#cgy#f0=|mP1sJ||(X9=`rBd!0{{1+uPF_|yt z=U*he2n_r?;qMqe;aGFa9(cj68fD&M&5FiZ5AO%e1y`_MeDModh~BPXSt!o3YBMEB zsj~x0Azx!N25Kp@B}rP?$aaP4Jbj&Esv>PB7FHi%!TZK*@HQVkOBXiC4_9?=(iQ%Z zEI*%VjsM&jP=smy_S<3)U6l*}&=u@Beh5AFOWjr*|hVZI%2H^_H=@pVZp}Zi|q`rJfh;|~X&YmvPsp_G~ z3J?bp_&iFL+XCc2a(ZGf0KO4lOv~{d3{eMc5aK|CRLBZwJ;86M)GUjxGNdN2=Yu#` zCIBkePZcR62YGr@A0?y|?-0cF%|@5RwS|$w^3sJqe7ynyJ$+B-9J)XE^94Zlh8m<0fMs^^1OL(#f6Wu&k#0OZ>7(ZWUYr#ac|nrKovK(G+b z>;eG%U{d(TT++_vdy{=cMyYUJc-C3_8GBMa!6%wy3rJM}I8EAy7F5mB#`an^yDHzv zDgy_*^TUGHl;<9@p@HFyAm<;(awX0@o*l0*+m4t%sBDE)OLXZltDt*B4#-*tvJZvTfTnUSeM-9OjRw!$D`ODW|o?JYCnDk}YCKB`?J? z#P5h@%To_0FG>E2$RLwJ|4)*yb8@T1vww?QV)X~4p04DMq`%9!4{FE< zs>%4^@>>bYbmi^Aw81WRZuX0es8=3El_x#S)fNAgSf2QkO{aTwA(15t`I5u#%;4S> z-3=x);BQ`h^&#N(&XL;Iu0I2=_ka@~&jjdRzkGY(t%Ud3&ttgkYA9N^1i^m;U+_+r zuEisPpyBW*qAD1i^j>(psO;C_`?dH}{|cusObpi!@lEfw$8&1TfFH513xynO*LFbu zFZ>;ZwH~N56nHbu0pS3NcszvP(aJQ;6n%=wUw6JFM`c1Zm9@aG<&{d>S8}U1^EViD z_78Na>P1=Buy#OEmiYKSndSIebkI4FNXUq-*BVOGo4I=m2etNH)|7ziWu;kYX<}cL zmQVldHP?5KLs-ETD5=0t#9A9v#%T+XE=xCj7;X=bT(%uhb0b1zS>Bg6pR%sT%GQD2 zR`#vMIf!wew(jbrX95k&&WYM{rwjlvHI84vQ|4)ZQ zi~0)g(n!e|G4(5ph3OySUc;+0U*I>gpyN=7`xVjSY`d3FrW*bpzEIi!>NeaI$-=Sl zrg{2AKP8(h{~`F8j_X5v6$Gk@sZ>EpCTTJgFopGy$TWtO*aZ_uiP^JUNBqQ*9dkow zE@JMAHeE*&u7pV&bPiH=*zf^DBch@aF^L%LhYDO9_L@=-<4|QwSG1X#3$e;92qA5# zKok`~0Vm-Qb?Jd-90O_3z-T8oUCom5h_S^h+E@V4z&;Ev<~@k2bReQ#sOad1P2m;} z-RCsRhlp$=#3j6ftGG_W6l$nINKkrEgN{KJ&j5;(b7fMG>!HGytZ1WvsSQBz4Ne7g z%(<@%D`RL=cZ%%h%?U0Op%4h$N`VYW;M(kt?-RCgMT^Elss+b;7!wuKY3ia5Qooj@ z4+rSzff3{GFS-cE=$zif3kL%!xt2gcfPnb~%x~HtHlG`wvf7%ffM7dnh}d|4CJ3gs z;pT&&3f3kDpmJ*Zl50=eFrzj*eq83BtF-W%uzC>rlDU>*Dhm`Tlq9TuVr=F}p*$M6 z_~6IHLEr&oCW4a$0+I0S?TjpHqo}S2gR+8-+#g_hD~^QCGXgO?v3V<6CWQblM(LR6 zyO=G&T|g)zCJjQr0RRxg0a0Ti{i*Kk^y6JPeRN(}`9T~i)2q&aN-iKW3ErIYpkUIZ zw}&?kt6&8kr;d|i%KgDA7Eoli;NCkN>j!W~xO5z!zHn5prk!5HL(G_ zxVFu#$Z?{z30G8vL?TwKA&q&&l1a5TiX6F!%E4b3375(!8lsb+LWv3);W_$HLObA+ zqbzk8jjHQ?J=pmbTxG}42X!3SRwGmE1f^|M>Y&hsRQkb2mWAU}wqV7dcrAECPK?bO zDU>IIrb!I#geSp#vRmfCKZkbpi9F z^1I4Z)-g>X8iiHE?8uf@NT3o{5L-ks$cz-&5#-bPjvaf~rQFDJ{ik&15TlvG9gjVV z8FO>Aeu9!x{rq@UWod~y-=GWhA!v&Bd-lkfs`By+5oMMzB_{8>yE@zXsR~oHp9SRt zvz*wkkY`<8UK|hmoz9QnS>_V;kX2p*RU4G|kyXA^daU{rw!y znirnJdH()4+VJpied3VQl#BAa9OCmIlH-NjS0N_vuW+TN_HS?Cn#W&Zd921@U;lXJ^5}^jJYGHXD!3!3ZdyL@z1=>NTw~Va69~cV0C^Ac8nM6- ze92N9s^Jna+>jreZ8ha-Aju6p7vu}3oE-M2A;S_72ZZkN2p@xcGzDJjQ8T}LS8C}_ zI-dTPucwm2_Hqb#0-7ReRFGg;T8#%CJD&}!kftsjJsjlr@X`eM*;dx$p%+R&Y?KpC zv4BEI1(DZaq+pmB7_tM{HL)=U9vFr7IH7!>CsAZO;CmW6JAqYL8cq#5>mag|hA zFiY=_ssVI;FHNMq0)pd_UGQgjbFm68tpvaOoohW#M{RXZwqVY{b>t*X$2p2cVgZBZ z&P3QsQmic_b>MNDO>MP6RG=WL;vfUqb~p^BQ#Pnj0El3_VW~GD00w$aJXOb<{ohaiDyU@!16TJO_OSbDxEEIw0n20vXPk@>X|zZiMZ(K?SRL5HBs5cun8-= zB`s5(H(uM)ghML&PK7XgrdMGC#~X$Lvew7l&K=~ulmNL;;DP&!ypx5#BTS+ zl-R5>gt2ajVlDt;!-=hgpb{FN;qh8iF^9%GK-&&A`_PwV(OMY?L981ByFsD00MLR; zNr*5aK?1=H8H0!*Gk3nM{Y>!O31Fux=hQZvw#_hd$NGbe`1$arHEzP(IX{7m=B^+t zg2KmkU*;XkFmv-5DTwxov0~(uyqyEnrRkR;%;t8(tosR(=7n2P&1&dc(2I#_SrY2? zbZJ-?xQ97&d%+vwFl@o@g0TAru%HRu7WivJ2QxRXhnX`pgftWV*#a4uH{XaZJY?(h zPXjs=KNS4^VD)lOr@I(2go>p>uLwTr9yCD1pjoW9F;S9-y#V{Ltg7u|#GQ$m?RRme z7baU}8`+a>RHA1_n%}LfQ#|@BY)bk@wH^KarZ`zKYZH;H2k7hc{v11U=-{w-@YPrP zdbV%e;OSo7<>;ubsjez5u@zw^U5*+>6zPZEcC%hCMolIA-7IyG?Ygq8J@>RSe~7(r z)Fh?aB{a&Wgg2t^O8{UWUXEU8{kojXLvv#3|WBdzSs>JqETn0a|VEj!lE z9u9pd!1w0V!^Cwwgn2#2&rcP^G;X!ebC~lTV$36#yo% zHFAh}J^=bQ9#Y9ptHo&8)Qrtv0SJJ=t~L7~OBp-=mTmnV0Dd?-*L#OQ>W{Rw9Ntp} zwfu$rG;B=-Tm(Cw^UW+YJ=zPun{A3JpdSg(XzENozauF8JLMw`IkW~xfP9YxJ|fCL z8)XMwM|ymR3$iUPNS~KnA;S)QMR_}(AIYqE=MLq`w5s(Tzv{pnI%C$dkTW;q&!__k zj^mAZJAnT*4V*8TiJw3LHj$?&5!e(JBgjYo!b9rI`;giuC9^(`DC~+@;{U0%zH^t_EPF-!r z43h7Yw<)%9(ifZzBfHvFUq6vwfhGPdenT=}HLd2$R~-_W7Jjs{Hu>Yun(S4HTUpiq zc2gv0P=`K-3>?5qn7~b3LLWVx#}%}2KMvplw6Gp)uhK1?jyAXO5=H-gyofHIM+;qC z#TA^#vde<)73`d5FEVUgvgh~oYMgQ27jO&L(MSJ8!$U6J!&Sk$pE_VWJY^okI7_9^ z?9p3Tht*h1gh!MYDU@z+i_h|zzKm;%t!I!{&T*t%;^4MgILuq7g$X>naARjUWiILV=qlWL>W+Ez$&R}9@!5T}}*S*>J=$C!BJ|ITu`V#WgqFa>qRns3$i`B>vi(dKHvBg+obORAMd`PE3Si zIy<2Tmm>Z*mpGKtBtiJ|=XD2^fyW?Dj6b2|^Wd&d;Ky%PlX9Ze5zi%TQ3wfEIF#>% zLysyk0}6){qZAUZTq<|eK}QKVnG1&!+IZpdo7IW$)ztW4d1A^Gm6&>kLK$YQ!-tKG zQAi}~#rj& Date: Mon, 15 Feb 2021 12:01:58 +0100 Subject: [PATCH 11/61] modif config/view/index/index.php --- core/module/config/view/index/index.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/core/module/config/view/index/index.php b/core/module/config/view/index/index.php index 0985a251..42b8b8ae 100755 --- a/core/module/config/view/index/index.php +++ b/core/module/config/view/index/index.php @@ -8,14 +8,7 @@ 'value' => 'Accueil' ]); ?> -
    - helper::baseUrl() . 'config/modules', - 'value' => 'Modules', - 'ico' => 'download', - ]); ?> -
    -
    +
    helper::baseUrl() . 'config/advanced', 'value' => 'Avancée', From 1d75d17e4d33f7f042bf99a708bec0eb3ee8e2db Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Mon, 15 Feb 2021 13:38:23 +0100 Subject: [PATCH 12/61] Ajout de constantes dans getModules() --- core/class/helper.class.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 8b94d698..7abbb97d 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -157,10 +157,31 @@ class helper { } else { $version = '0.0'; } + // Constante UPDATE + if (array_key_exists('UPDATE', $class_constants)) { + $update = $value::UPDATE; + } else { + $update = false; + } + // Constante DELETE + if (array_key_exists('DELETE', $class_constants)) { + $delete = $value::DELETE; + } else { + $delete = false; + } + // Constante DATADIRECTORY + if (array_key_exists('DATADIRECTORY', $class_constants)) { + $dataDirectory= $value::DATADIRECTORY; + } else { + $dataDirectory = ''; + } // Affection $modules [$value] = [ - 'realName' => $realName, - 'version' => $version + 'realName' => $realName, + 'version' => $version, + 'update' => $update, + 'delete' => $delete, + 'dataDirectory' => $dataDirectory ]; } catch (Exception $e){ @@ -550,4 +571,4 @@ class helper { return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv); } -} \ No newline at end of file +} From bcd1f4910adebb1f7d95a63f4bfcf69f51dbe87d Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Mon, 15 Feb 2021 14:37:17 +0100 Subject: [PATCH 13/61] Ajout core/module/addon --- core/class/helper.class.php | 4 ++-- core/core.php | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 7abbb97d..d711bceb 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -137,10 +137,10 @@ class helper { */ public static function getModules() { $modules = array(); - $dirs = array_diff(scandir($folder), array('..', '.')); + $dirs = array_diff(scandir('module'), array('..', '.')); foreach ($dirs as $key => $value) { // Dossier non vide - if (file_exists($folder . '/' . $value . '/' . $value . '.php')) { + if (file_exists('module/' . $value . '/' . $value . '.php')) { // Lire les constantes en gérant les erreurs de nom de classe try { $class_reflex = new \ReflectionClass($value); diff --git a/core/core.php b/core/core.php index 88048e39..e75ba604 100755 --- a/core/core.php +++ b/core/core.php @@ -56,7 +56,8 @@ class common { 'sitemap', 'theme', 'user', - 'translate' + 'translate', + 'addon' ]; public static $accessList = [ 'user', @@ -177,7 +178,8 @@ class common { 'theme' => '', 'admin' => '', 'blacklist' => '', - 'locale' => '' + 'locale' => '', + 'addon' ]; /** @@ -603,7 +605,7 @@ class common { $this->setData(['theme',$tempData['theme']]); // Import des users sauvegardés si option active - if ($keepUsers === false + if ($keepUsers === false AND $tempData['user'] !== NULL) { $this->setData(['user',$tempData['user']]); } @@ -2901,7 +2903,7 @@ class layout extends common { $rightItems .= '
  • ' . template::ico('users') . '
  • '; $rightItems .= '
  • ' . template::ico('brush') . '
  • '; //$rightItems .= '
  • ' . template::ico('flag') . '
  • '; - $rightItems .= '
  • ' . template::ico('puzzle') . '
  • '; + $rightItems .= '
  • ' . template::ico('puzzle') . '
  • '; $rightItems .= '
  • ' . template::ico('cog-alt') . '
  • '; // Mise à jour automatique $today = mktime(0, 0, 0); From f5bb4cb0505ccc69377388296b29c544726b76b3 Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Mon, 15 Feb 2021 14:42:34 +0100 Subject: [PATCH 14/61] Ajout core/module/addon suite --- core/module/addon/addon.php | 332 ++++++++++++++++++++++ core/module/addon/view/index/index.css | 18 ++ core/module/addon/view/index/index.js.php | 21 ++ core/module/addon/view/index/index.php | 58 ++++ 4 files changed, 429 insertions(+) create mode 100644 core/module/addon/addon.php create mode 100644 core/module/addon/view/index/index.css create mode 100644 core/module/addon/view/index/index.js.php create mode 100644 core/module/addon/view/index/index.php diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php new file mode 100644 index 00000000..881d9839 --- /dev/null +++ b/core/module/addon/addon.php @@ -0,0 +1,332 @@ + + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +class addon extends common { + + public static $actions = [ + 'index' => self::GROUP_ADMIN, + 'moduleDelete' => self::GROUP_ADMIN + ]; + + // Gestion des modules + public static $modInstal = []; + + // pour tests + public static $valeur = []; + + /* + * Effacement d'un module installé et non utilisé + */ + public function moduleDelete() { + + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'addon', + 'state' => false, + 'notification' => 'Action non autorisée' + ]); + } + else{ + // Suppression des dossiers + if( $this->delete_directory('./module/'.$this->getUrl(2)) === true){ + $success = true; + $notification = 'Module '.$this->getUrl(2) .' effacé du dossier /module/, il peut rester des données dans d\'autres dossiers'; + } + else{ + $success = false; + $notification = 'La suppression a échouée'; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'addon', + 'notification' => $notification, + 'state' => $success + ]); + } + } + + + /** + * Gestion des modules + */ + public function index() { + + $infomodule = helper::getModules(); + // $infomodule[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] + // Préparation du tableau des modules installés + // Liste des modules installés (répertoire de module/) + if ($dh = opendir( 'module/' )) { + $i=0; + while (($dirmodule = readdir($dh)) !== false) { + if( $dirmodule !== '.' && $dirmodule !== '..'){ + self::$modInstal[$i][0] = $dirmodule; // nom du module + self::$modInstal[$i][1] = $infomodule[$dirmodule]['realName']; + self::$modInstal[$i][2] = $infomodule[$dirmodule]['version']; + // Initialisations + self::$modInstal[$i][3] = ''; // page(s) + self::$modInstal[$i][4] = ''; // pour button effacement + self::$modInstal[$i][5] = ''; // pour button download + $i++; + } + } + closedir($dh); + } + foreach( self::$modInstal as $i=>$value){ + // Page(s) + foreach( $this->getData(['page']) as $keyPage=>$valuePage){ + if( $valuePage['moduleId'] === self::$modInstal[$i][0]){ + if(self::$modInstal[$i][3] !==''){ + self::$modInstal[$i][3] = self::$modInstal[$i][3].'
    '.$valuePage['title']; + } + else{ + self::$modInstal[$i][3] = $valuePage['title']; + } + } + } + // Non utilisé et autorisation de suppression ? + if( self::$modInstal[$i][3] == '' && $infomodule[ self::$modInstal[$i][0] ]['delete'] === true ){ + self::$modInstal[$i][4] = template::button('moduleDelete' . self::$modInstal[$i][0], [ + 'class' => 'moduleDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]); + } + // Présence de données externes à module.json ? + if( $infomodule[ self::$modInstal[$i][0] ]['dataDirectory'] !== '' ){ + self::$modInstal[$i][5] = template::button('moduleExport' . self::$modInstal[$i][0], [ + 'class' => 'buttonBlue', + //'href' => helper::baseUrl() . $this->getUrl(0) . '/exportData/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], + 'href' => helper::baseUrl(false).$this->exportZip( self::$modInstal[$i][0] ), + 'value' => template::ico('upload') + ]); + } + + } + // Retour du formulaire ? + if($this->isPost()) { + // Installation d'un module + $success = true; + $checkValidMaj = $this->getInput('configModulesCheck', helper::FILTER_BOOLEAN); + $zipFilename = $this->getInput('configModulesInstallation', helper::FILTER_STRING_SHORT); + if( $zipFilename !== ''){ + $tempFolder = 'datamodules';//uniqid(); + $zip = new ZipArchive(); + if ($zip->open(self::FILE_DIR.'source/'.$zipFilename) === TRUE) { + $notification = 'Archive ouverte'; + mkdir (self::TEMP_DIR . $tempFolder); + $zip->extractTo(self::TEMP_DIR . $tempFolder ); + // Archive de module ? + $success = false; + $notification = 'Ce n\'est pas l\'archive d\'un module !'; + $moduleDir = self::TEMP_DIR . $tempFolder . '/module'; + $moduleName = ''; + if ( is_dir( $moduleDir )) { + // Lire le nom du module + if ($dh = opendir( $moduleDir )) { + while (($file = readdir($dh)) !== false) { + $moduleName = $file; + } + closedir($dh); + } + // Module normalisé ? + if( is_file( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php' ) AND is_file( $moduleDir.'/'.$moduleName.'/view/index/index.php' ) ){ + + // Lecture de la version du module pour validation de la mise à jour + // Pour une version <= version installée l'utilisateur doit cocher 'Mise à jour forcée' + // Lecture de version en lisant la valeur des constantes directement dans le fichier nommodule.php + $version = '0.0'; + $file = file_get_contents( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php'); + $pos1 = strpos($file, 'const VERSION'); + if( $pos1 !== false){ + $posdeb = strpos($file, "'", $pos1); + $posend = strpos($file, "'", $posdeb + 1); + $version = substr($file, $posdeb + 1, $posend - $posdeb - 1); + } + + // Module déjà installé ? + $moduleInstal = false; + foreach( self::$modInstal as $key=>$value){ + if($moduleName === $value[0]){ + $moduleInstal = true; + } + } + + // Validation de la maj si autorisation du concepteur du module ET + // ( Version plus récente OU Check de forçage ) + $valNewVersion = floatval($version); + $valInstalVersion = floatval( $infomodule[$moduleName]['version'] ); + $newVersion = false; + if( $valNewVersion > $valInstalVersion ) $newVersion = true; + $validMaj = $infomodule[$moduleName]['update'] && ( $newVersion || $checkValidMaj); + + // Nouvelle installation ou mise à jour du module + if( ! $moduleInstal || $validMaj ){ + // Copie récursive des dossiers + $this -> custom_copy( self::TEMP_DIR . $tempFolder, './' ); + $success = true; + if( ! $moduleInstal ){ + $notification = 'Module '.$moduleName.' installé'; + } + else{ + $notification = 'Module '.$moduleName.' mis à jour'; + } + } + else{ + $success = false; + $notification = ' Version détectée '.$version.' <= à celle installée '.$infomodule[$moduleName]['version']; + if( $infomodule[$moduleName]['update'] === false){ + $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; + } + } + } + } + // Supprimer le dossier temporaire même si le module est invalide + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + } else { + // erreur à l'ouverture + $success = false; + $notification = 'Impossible d\'ouvrir l\'archive'; + } + } + + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(), + 'notification' => $notification, + 'state' => $success + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Gestion des modules', + 'view' => 'index' + ]); + } + + /* + * Copie récursive de dossiers + * + */ + private function custom_copy($src, $dst) { + // open the source directory + $dir = opendir($src); + // Make the destination directory if not exist + @mkdir($dst); + // Loop through the files in source directory + while( $file = readdir($dir) ) { + if (( $file != '.' ) && ( $file != '..' )) { + if ( is_dir($src . '/' . $file) ){ + // Recursively calling custom copy function + // for sub directory + $this -> custom_copy($src . '/' . $file, $dst . '/' . $file); + } + else { + copy($src . '/' . $file, $dst . '/' . $file); + } + } + } + closedir($dir); + } + + /* + * + * Suppression d'un dossier et de ses sous-dossiers + */ + private function delete_directory($directory, $empty = false) { + if(substr($directory,-1) == "/") { + $directory = substr($directory,0,-1); + } + if(!file_exists($directory) || !is_dir($directory)) { + return false; + } elseif(!is_readable($directory)) { + return false; + } else { + $directoryHandle = opendir($directory); + while ($contents = readdir($directoryHandle)) { + if($contents != '.' && $contents != '..') { + $path = $directory . "/" . $contents; + if(is_dir($path)) { + $this->delete_directory($path); + } else { + unlink($path); + } + } + } + closedir($directoryHandle); + if($empty == false) { + if(!rmdir($directory)) { + return false; + } + } + return true; + } + } + + /* + * Création récursive d'un zip + * https://makitweb.com/how-to-create-and-download-a-zip-file-with-php/ + */ + private function createZip($zip,$dir){ + if (is_dir($dir)){ + if ($dh = opendir($dir)){ + while (($file = readdir($dh)) !== false){ + // If file + if (is_file($dir.$file)) { + if($file != '' && $file != '.' && $file != '..'){ + $zip->addFile($dir.$file); + } + } + else{ + // If directory + if(is_dir($dir.$file) ){ + if($file != '' && $file != '.' && $file != '..'){ + // Add empty directory + $zip->addEmptyDir($dir.$file); + $folder = $dir.$file.'/'; + // Read data of the folder + $this->createZip($zip,$folder); + } + } + } + } + closedir($dh); + } + } + } + + /* + * Export des données d'un module externes à module.json + */ + private function exportZip( $exportModule ){ + $infomodule = helper::getModules(); + // création du zip + $zip = new ZipArchive(); + if( ! is_dir('tmp/exportDataModules')) mkdir('tmp/exportDataModules',0777, true); + $filename = 'tmp/exportDataModules/'.$exportModule.'dataExport.zip'; + if( is_file( $filename )) unlink( $filename); + $directory = $infomodule[$exportModule]['dataDirectory'].'/'; + if($zip->open( $filename, ZipArchive::CREATE) !== TRUE){ + exit; + } + else{ + $this->createZip($zip,$directory); + $zip->close(); + } + return( $filename ); + } +} diff --git a/core/module/addon/view/index/index.css b/core/module/addon/view/index/index.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/core/module/addon/view/index/index.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/core/module/addon/view/index/index.js.php b/core/module/addon/view/index/index.js.php new file mode 100644 index 00000000..222b85a1 --- /dev/null +++ b/core/module/addon/view/index/index.js.php @@ -0,0 +1,21 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Confirmation de suppression + */ +$(".moduleDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer, effacer ce module ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/core/module/addon/view/index/index.php b/core/module/addon/view/index/index.php new file mode 100644 index 00000000..9b421e4b --- /dev/null +++ b/core/module/addon/view/index/index.php @@ -0,0 +1,58 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl(), + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
    +
    + 'Valider', + 'ico' => 'check' + ]); ?> +
    +
    +
    +
    +
    +

    Installer ou mettre à jour un module

    +
    +
    + 'Archive ZIP :', + 'type' => 2 + ]); ?> +
    +
    +
    +
    + false, + 'help' => 'Permet de forcer une mise à jour même si la version du module est inférieure ou égale à celle du module installé.', + ]); ?> +
    +
    +
    +
    + + + + + + + + + + + + + +
    '; + var_dump( helper::getModules('site/tmp/toto/module') );*/ +?> + From e1bfde36dc4629775248f5ae06e70b5d2b5ecd8c Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Mon, 15 Feb 2021 15:01:38 +0100 Subject: [PATCH 15/61] Suppression de gps.php fichier vide --- module/gps/gps.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 module/gps/gps.php diff --git a/module/gps/gps.php b/module/gps/gps.php deleted file mode 100644 index e69de29b..00000000 From fdcbb22e0c997f6464ccfe7765a9e1401686ed9e Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Mon, 15 Feb 2021 17:13:57 +0100 Subject: [PATCH 16/61] Nettoyage de core/module/config/config.php --- core/module/addon/addon.php | 1 + core/module/config/config.php | 278 +--------------------------------- 2 files changed, 2 insertions(+), 277 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 881d9839..5bfddc11 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -151,6 +151,7 @@ class addon extends common { // Lecture de version en lisant la valeur des constantes directement dans le fichier nommodule.php $version = '0.0'; $file = file_get_contents( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php'); + // A FAIRE supprimer les espaces et les tab et rechercher 'constVERSION' $pos1 = strpos($file, 'const VERSION'); if( $pos1 !== false){ $posdeb = strpos($file, "'", $pos1); diff --git a/core/module/config/config.php b/core/module/config/config.php index 99af0760..46fe9cf7 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -29,15 +29,9 @@ class config extends common { 'logReset' => self::GROUP_ADMIN, 'logDownload'=> self::GROUP_ADMIN, 'blacklistReset' => self::GROUP_ADMIN, - 'blacklistDownload' => self::GROUP_ADMIN, - 'modules' => self::GROUP_ADMIN, - 'moduleDelete' => self::GROUP_ADMIN - + 'blacklistDownload' => self::GROUP_ADMIN ]; - public static $modInstal = []; - public static $str; - public static $timezones = [ 'Pacific/Midway' => '(GMT-11:00) Midway Island', 'US/Samoa' => '(GMT-11:00) Samoa', @@ -598,215 +592,6 @@ class config extends common { ]); } - /* - * Installation de modules à partir d'un zip normalisé - * Affichage des modules installés - */ - public function modules() { - var_dump(helper::getModules ()); - // Préparation du tableau des modules installés - // Liste des modules installés (répertoire de module/) - if ($dh = opendir( 'module/' )) { - $i=0; - while (($dirmodule = readdir($dh)) !== false) { - if( $dirmodule !== '.' && $dirmodule !== '..'){ - self::$modInstal[$i][0] = $dirmodule; - self::$modInstal[$i][1] = page::$moduleNames[$dirmodule]; - // Lecture de la version pour les modules officiels et distribués - $blogversion = blog::VERSION; - $formversion = form::VERSION; - $galleryversion = gallery::VERSION; - $newsversion = news::VERSION; - $redirectionversion = redirection::VERSION; - $searchversion = search::VERSION; - self::$str = $dirmodule.'version'; - self::$modInstal[$i][2] = '?'; - if( ${self::$str} !== null){ - self::$modInstal[$i][2] = ${self::$str}; - } - // Lecture de la version pour les modules non distribués - elseif($this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]) !== null){ - self::$modInstal[$i][2] = $this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]); - } - self::$modInstal[$i][3] = 'non'; - self::$modInstal[$i][4] = ''; - self::$modInstal[$i][5] = ''; - $i++; - } - } - closedir($dh); - } - // Module utilisé ? - $nb = count(self::$modInstal); - for ($i = 0; $i < $nb; $i++) { - foreach( $this->getData(['page']) as $keyPage=>$valuePage){ - if( $valuePage['moduleId'] === self::$modInstal[$i][0]){ - self::$modInstal[$i][3] = 'oui'; - if(self::$modInstal[$i][4] !==''){ - self::$modInstal[$i][4] = self::$modInstal[$i][4].'
    '.$valuePage['title']; - } - else{ - self::$modInstal[$i][4] = $valuePage['title']; - } - } - } - $modulesDistrib = array('blog', 'form', 'gallery', 'news', 'redirection', 'search'); - if( self::$modInstal[$i][4] =='' && array_search( self::$modInstal[$i][0], $modulesDistrib ) === false - && $this->getData(['module', '_gestion_modules_', self::$modInstal[$i][0], 'delete' ]) === true){ - self::$modInstal[$i][5] = template::button('moduleDelete' . self::$modInstal[$i][0], [ - 'class' => 'moduleDelete buttonRed', - 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], - 'value' => template::ico('cancel') - ]); - - } - } - - // Retour du formulaire ? - if($this->isPost()) { - // Installation d'un module - $success = true; - $checkValidMaj = $this->getInput('configModulesCheck', helper::FILTER_BOOLEAN); - $zipFilename = $this->getInput('configModulesInstallation', helper::FILTER_STRING_SHORT); - if( $zipFilename !== ''){ - $tempFolder = uniqid(); - $zip = new ZipArchive(); - if ($zip->open(self::FILE_DIR.'source/'.$zipFilename) === TRUE) { - $notification = 'Archive ouverte'; - mkdir (self::TEMP_DIR . $tempFolder); - $zip->extractTo(self::TEMP_DIR . $tempFolder ); - // Archive de module ? - $success = false; - $notification = 'Ce n\'est pas l\'archive d\'un module !'; - $moduleDir = self::TEMP_DIR . $tempFolder . '/module'; - $moduleName = ''; - if ( is_dir( $moduleDir )) { - // Lire le nom du module - if ($dh = opendir( $moduleDir )) { - while (($file = readdir($dh)) !== false) { - $moduleName = $file; - } - closedir($dh); - } - // Module normalisé ? - if( is_file( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php' ) AND is_file( $moduleDir.'/'.$moduleName.'/view/index/index.php' ) ){ - - // Lecture de info.json et mémorisation des 3 paramètres version, update et delete - $version = '?'; - $update = '?'; - $delete = false; - if( is_file( $moduleDir.'/'.$moduleName.'/info/info.json' )){ - $json = file_get_contents( $moduleDir.'/'.$moduleName.'/info/info.json' ); - $param = json_decode( $json, true); - if( $param['module'] === $moduleName && is_bool($param['update']) && is_bool($param['update'])){ - $version = $param['version']; - $update = $param['update']; - $delete = $param['delete']; - } - } - $this->setData(['module','_gestion_modules_',$moduleName, 'version', $version]); - $this->setData(['module','_gestion_modules_',$moduleName, 'update', $update]); - $this->setData(['module','_gestion_modules_',$moduleName, 'delete', $delete]); - - // Module déjà installé ? - $moduleInstal = false; - foreach( self::$modInstal as $key=>$value){ - if($moduleName === $value[0]){ - if( $value[3] !== 'non'){ - $notification = 'Module déjà installé et utilisé page '.$value[4]; - } - else{ - $notification = 'Module déjà installé et non utilisé'; - } - $moduleInstal = true; - } - } - $validMaj = $checkValidMaj; - if(is_bool($update)){ - $validMaj = $checkValidMaj && $update; - } - - // Nouvelle installation ou mise à jour du module avec validation du concepteur et validation de l'utilisateur - if( ! $moduleInstal || ( $moduleInstal && $validMaj )){ - // Copie récursive des dossiers - $this -> custom_copy( self::TEMP_DIR . $tempFolder, './' ); - $success = true; - if( ! $moduleInstal ){ - $notification = 'Module '.$moduleName.' installé'; - } - else{ - $notification = 'Module '.$moduleName.' mis à jour'; - } - } - else{ - $success = false; - $notification = ' Vous devez cocher la case "Valider la mise à jour d\'un module déjà installé"'; - if( $update === false){ - $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; - } - } - } - } - // Supprimer le dossier temporaire même si le module est invalide - $this->removeDir(self::TEMP_DIR . $tempFolder); - $zip->close(); - } else { - // erreur à l'ouverture - $success = false; - $notification = 'Impossible d\'ouvrir l\'archive'; - } - } - - $this->addOutput([ - 'redirect' => helper::baseUrl() . $this->getUrl(), - 'notification' => $notification, - 'state' => $success - ]); - } - // Valeurs en sortie - $this->addOutput([ - 'title' => 'Gestion des modules', - 'view' => 'modules' - ]); - } - - /* - * - * Effacement d'un module installé et non utilisé - */ - public function moduleDelete() { - - // Jeton incorrect - if ($this->getUrl(3) !== $_SESSION['csrf']) { - // Valeurs en sortie - $this->addOutput([ - 'redirect' => helper::baseUrl() . 'config/modules', - 'state' => false, - 'notification' => 'Action non autorisée' - ]); - } - else{ - // suppression de la clef version du module - $this->deleteData(['module', '_gestion_modules_', $this->getUrl(2)]); - // Suppression des dossiers - if( $this->delete_directory('./module/'.$this->getUrl(2)) === true){ - $success = true; - $notification = 'Module '.$this->getUrl(2) .' effacé du dossier /module/, il peut rester des données dans d\'autres dossiers'; - } - else{ - $success = false; - $notification = 'La suppression a échouée'; - } - // Valeurs en sortie - $this->addOutput([ - 'redirect' => helper::baseUrl() . 'config/modules', - 'notification' => $notification, - 'state' => $success - ]); - } - } - - public function script() { // Soumission du formulaire if($this->isPost()) { @@ -1027,65 +812,4 @@ class config extends common { } return $newArray; } - - - /* - * Copie récursive de dossiers - * - */ - private function custom_copy($src, $dst) { - // open the source directory - $dir = opendir($src); - // Make the destination directory if not exist - @mkdir($dst); - // Loop through the files in source directory - while( $file = readdir($dir) ) { - if (( $file != '.' ) && ( $file != '..' )) { - if ( is_dir($src . '/' . $file) ){ - // Recursively calling custom copy function - // for sub directory - $this -> custom_copy($src . '/' . $file, $dst . '/' . $file); - } - else { - copy($src . '/' . $file, $dst . '/' . $file); - } - } - } - closedir($dir); - } - - /* - * - * Suppression d'un dossier et de ses sous-dossiers - */ - private function delete_directory($directory, $empty = false) { - if(substr($directory,-1) == "/") { - $directory = substr($directory,0,-1); - } - if(!file_exists($directory) || !is_dir($directory)) { - return false; - } elseif(!is_readable($directory)) { - return false; - } else { - $directoryHandle = opendir($directory); - while ($contents = readdir($directoryHandle)) { - if($contents != '.' && $contents != '..') { - $path = $directory . "/" . $contents; - if(is_dir($path)) { - $this->delete_directory($path); - } else { - unlink($path); - } - } - } - closedir($directoryHandle); - if($empty == false) { - if(!rmdir($directory)) { - return false; - } - } - return true; - } - } - } From ec5b33dd0f24c094a960eb5d33faefee203dde7a Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Mon, 15 Feb 2021 17:27:50 +0100 Subject: [PATCH 17/61] Suppression de core/module/config/view/modules --- core/module/config/view/modules/modules.css | 18 ------- .../module/config/view/modules/modules.js.php | 21 -------- core/module/config/view/modules/modules.php | 48 ------------------- 3 files changed, 87 deletions(-) delete mode 100644 core/module/config/view/modules/modules.css delete mode 100644 core/module/config/view/modules/modules.js.php delete mode 100644 core/module/config/view/modules/modules.php diff --git a/core/module/config/view/modules/modules.css b/core/module/config/view/modules/modules.css deleted file mode 100644 index 805e9150..00000000 --- a/core/module/config/view/modules/modules.css +++ /dev/null @@ -1,18 +0,0 @@ -/** - * This file is part of Zwii. - * - * For full copyright and license information, please see the LICENSE - * file that was distributed with this source code. - * - * @author Rémi Jean - * @copyright Copyright (C) 2008-2018, Rémi Jean - * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez - * @license GNU General Public License, version 3 - * @link http://zwiicms.fr/ - */ - - -/** NE PAS EFFACER -* admin.css -*/ \ No newline at end of file diff --git a/core/module/config/view/modules/modules.js.php b/core/module/config/view/modules/modules.js.php deleted file mode 100644 index 222b85a1..00000000 --- a/core/module/config/view/modules/modules.js.php +++ /dev/null @@ -1,21 +0,0 @@ -/** - * This file is part of Zwii. - * - * For full copyright and license information, please see the LICENSE - * file that was distributed with this source code. - * - * @author Rémi Jean - * @copyright Copyright (C) 2008-2018, Rémi Jean - * @license GNU General Public License, version 3 - * @link http://zwiicms.fr/ - */ - -/** - * Confirmation de suppression - */ -$(".moduleDelete").on("click", function() { - var _this = $(this); - return core.confirm("Êtes-vous sûr de vouloir supprimer, effacer ce module ?", function() { - $(location).attr("href", _this.attr("href")); - }); -}); \ No newline at end of file diff --git a/core/module/config/view/modules/modules.php b/core/module/config/view/modules/modules.php deleted file mode 100644 index 9ffe9b65..00000000 --- a/core/module/config/view/modules/modules.php +++ /dev/null @@ -1,48 +0,0 @@ - -
    -
    - 'buttonGrey', - 'href' => helper::baseUrl() . 'config', - 'ico' => 'left', - 'value' => 'Retour' - ]); ?> -
    -
    - 'Valider', - 'ico' => 'check' - ]); ?> -
    -
    -
    -
    -
    -

    Installer un module

    -
    -
    - 'Archive ZIP :', - 'type' => 2 - ]); ?> -
    -
    -
    -
    - false, - 'help' => 'Vérifier sur le forum que ce module supporte la mise à jour par réinstallation des fichiers.', - ]); ?> -
    -
    -
    -
    -
    - - - - - - - - \ No newline at end of file From 3b1f6a874a2aa98df5d431448c0578d09e7dfe35 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 15 Feb 2021 18:31:23 +0100 Subject: [PATCH 18/61] core + ordre is_post avant --- core/core.php | 3 +- core/module/addon/addon.php | 103 ++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/core/core.php b/core/core.php index e75ba604..75c28746 100755 --- a/core/core.php +++ b/core/core.php @@ -178,8 +178,7 @@ class common { 'theme' => '', 'admin' => '', 'blacklist' => '', - 'locale' => '', - 'addon' + 'locale' => '' ]; /** diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 5bfddc11..f2a9d733 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -65,58 +65,6 @@ class addon extends common { * Gestion des modules */ public function index() { - - $infomodule = helper::getModules(); - // $infomodule[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] - // Préparation du tableau des modules installés - // Liste des modules installés (répertoire de module/) - if ($dh = opendir( 'module/' )) { - $i=0; - while (($dirmodule = readdir($dh)) !== false) { - if( $dirmodule !== '.' && $dirmodule !== '..'){ - self::$modInstal[$i][0] = $dirmodule; // nom du module - self::$modInstal[$i][1] = $infomodule[$dirmodule]['realName']; - self::$modInstal[$i][2] = $infomodule[$dirmodule]['version']; - // Initialisations - self::$modInstal[$i][3] = ''; // page(s) - self::$modInstal[$i][4] = ''; // pour button effacement - self::$modInstal[$i][5] = ''; // pour button download - $i++; - } - } - closedir($dh); - } - foreach( self::$modInstal as $i=>$value){ - // Page(s) - foreach( $this->getData(['page']) as $keyPage=>$valuePage){ - if( $valuePage['moduleId'] === self::$modInstal[$i][0]){ - if(self::$modInstal[$i][3] !==''){ - self::$modInstal[$i][3] = self::$modInstal[$i][3].'
    '.$valuePage['title']; - } - else{ - self::$modInstal[$i][3] = $valuePage['title']; - } - } - } - // Non utilisé et autorisation de suppression ? - if( self::$modInstal[$i][3] == '' && $infomodule[ self::$modInstal[$i][0] ]['delete'] === true ){ - self::$modInstal[$i][4] = template::button('moduleDelete' . self::$modInstal[$i][0], [ - 'class' => 'moduleDelete buttonRed', - 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], - 'value' => template::ico('cancel') - ]); - } - // Présence de données externes à module.json ? - if( $infomodule[ self::$modInstal[$i][0] ]['dataDirectory'] !== '' ){ - self::$modInstal[$i][5] = template::button('moduleExport' . self::$modInstal[$i][0], [ - 'class' => 'buttonBlue', - //'href' => helper::baseUrl() . $this->getUrl(0) . '/exportData/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], - 'href' => helper::baseUrl(false).$this->exportZip( self::$modInstal[$i][0] ), - 'value' => template::ico('upload') - ]); - } - - } // Retour du formulaire ? if($this->isPost()) { // Installation d'un module @@ -212,6 +160,57 @@ class addon extends common { 'state' => $success ]); } + $infomodule = helper::getModules(); + // $infomodule[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] + // Préparation du tableau des modules installés + // Liste des modules installés (répertoire de module/) + if ($dh = opendir( 'module/' )) { + $i=0; + while (($dirmodule = readdir($dh)) !== false) { + if( $dirmodule !== '.' && $dirmodule !== '..'){ + self::$modInstal[$i][0] = $dirmodule; // nom du module + self::$modInstal[$i][1] = $infomodule[$dirmodule]['realName']; + self::$modInstal[$i][2] = $infomodule[$dirmodule]['version']; + // Initialisations + self::$modInstal[$i][3] = ''; // page(s) + self::$modInstal[$i][4] = ''; // pour button effacement + self::$modInstal[$i][5] = ''; // pour button download + $i++; + } + } + closedir($dh); + } + foreach( self::$modInstal as $i=>$value){ + // Page(s) + foreach( $this->getData(['page']) as $keyPage=>$valuePage){ + if( $valuePage['moduleId'] === self::$modInstal[$i][0]){ + if(self::$modInstal[$i][3] !==''){ + self::$modInstal[$i][3] = self::$modInstal[$i][3].'
    '.$valuePage['title']; + } + else{ + self::$modInstal[$i][3] = $valuePage['title']; + } + } + } + // Non utilisé et autorisation de suppression ? + if( self::$modInstal[$i][3] == '' && $infomodule[ self::$modInstal[$i][0] ]['delete'] === true ){ + self::$modInstal[$i][4] = template::button('moduleDelete' . self::$modInstal[$i][0], [ + 'class' => 'moduleDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]); + } + // Présence de données externes à module.json ? + if( $infomodule[ self::$modInstal[$i][0] ]['dataDirectory'] !== '' ){ + self::$modInstal[$i][5] = template::button('moduleExport' . self::$modInstal[$i][0], [ + 'class' => 'buttonBlue', + //'href' => helper::baseUrl() . $this->getUrl(0) . '/exportData/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], + 'href' => helper::baseUrl(false).$this->exportZip( self::$modInstal[$i][0] ), + 'value' => template::ico('upload') + ]); + } + + } // Valeurs en sortie $this->addOutput([ 'title' => 'Gestion des modules', From 9d7810ebf24acb9be7044623b603b21c61ce1e15 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 15 Feb 2021 20:38:38 +0100 Subject: [PATCH 19/61] index construction du tableau --- core/module/addon/addon.php | 92 +++++++++++++++---------------------- 1 file changed, 37 insertions(+), 55 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index f2a9d733..6bf11ea4 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -118,10 +118,10 @@ class addon extends common { // Validation de la maj si autorisation du concepteur du module ET // ( Version plus récente OU Check de forçage ) $valNewVersion = floatval($version); - $valInstalVersion = floatval( $infomodule[$moduleName]['version'] ); + $valInstalVersion = floatval( $infoModules[$moduleName]['version'] ); $newVersion = false; if( $valNewVersion > $valInstalVersion ) $newVersion = true; - $validMaj = $infomodule[$moduleName]['update'] && ( $newVersion || $checkValidMaj); + $validMaj = $infoModules[$moduleName]['update'] && ( $newVersion || $checkValidMaj); // Nouvelle installation ou mise à jour du module if( ! $moduleInstal || $validMaj ){ @@ -137,8 +137,8 @@ class addon extends common { } else{ $success = false; - $notification = ' Version détectée '.$version.' <= à celle installée '.$infomodule[$moduleName]['version']; - if( $infomodule[$moduleName]['update'] === false){ + $notification = ' Version détectée '.$version.' <= à celle installée '.$infoModules[$moduleName]['version']; + if( $infoModules[$moduleName]['update'] === false){ $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; } } @@ -160,57 +160,39 @@ class addon extends common { 'state' => $success ]); } - $infomodule = helper::getModules(); - // $infomodule[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] - // Préparation du tableau des modules installés - // Liste des modules installés (répertoire de module/) - if ($dh = opendir( 'module/' )) { - $i=0; - while (($dirmodule = readdir($dh)) !== false) { - if( $dirmodule !== '.' && $dirmodule !== '..'){ - self::$modInstal[$i][0] = $dirmodule; // nom du module - self::$modInstal[$i][1] = $infomodule[$dirmodule]['realName']; - self::$modInstal[$i][2] = $infomodule[$dirmodule]['version']; - // Initialisations - self::$modInstal[$i][3] = ''; // page(s) - self::$modInstal[$i][4] = ''; // pour button effacement - self::$modInstal[$i][5] = ''; // pour button download - $i++; - } - } - closedir($dh); - } - foreach( self::$modInstal as $i=>$value){ - // Page(s) - foreach( $this->getData(['page']) as $keyPage=>$valuePage){ - if( $valuePage['moduleId'] === self::$modInstal[$i][0]){ - if(self::$modInstal[$i][3] !==''){ - self::$modInstal[$i][3] = self::$modInstal[$i][3].'
    '.$valuePage['title']; - } - else{ - self::$modInstal[$i][3] = $valuePage['title']; - } - } - } - // Non utilisé et autorisation de suppression ? - if( self::$modInstal[$i][3] == '' && $infomodule[ self::$modInstal[$i][0] ]['delete'] === true ){ - self::$modInstal[$i][4] = template::button('moduleDelete' . self::$modInstal[$i][0], [ - 'class' => 'moduleDelete buttonRed', - 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], - 'value' => template::ico('cancel') - ]); - } - // Présence de données externes à module.json ? - if( $infomodule[ self::$modInstal[$i][0] ]['dataDirectory'] !== '' ){ - self::$modInstal[$i][5] = template::button('moduleExport' . self::$modInstal[$i][0], [ - 'class' => 'buttonBlue', - //'href' => helper::baseUrl() . $this->getUrl(0) . '/exportData/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], - 'href' => helper::baseUrl(false).$this->exportZip( self::$modInstal[$i][0] ), - 'value' => template::ico('upload') - ]); - } + // Lister les modules + // $infoModules[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] + $infoModules = helper::getModules(); + + // Clés moduleIds dans les pages + $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); + + // Parcourir les données des modules + foreach ($infoModules as $key=>$value) { + // Construire le tableau de sortie + self::$modInstal[] = [ + $key, + $infoModules[$key]['realName'], + $infoModules[$key]['version'], + array_search($key,$inPages),// devrait retourner toutes les valeurs et pas la première + array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true + ? template::button('moduleDelete' . $key, [ + 'class' => 'moduleDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + : '', + array_key_exists('update',$infoModules[$key]) && $infoModules[$key]['update'] === true + ? template::button('moduleDelete' . $key, [ + 'class' => 'moduleDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + : '' + ]; } + // Valeurs en sortie $this->addOutput([ 'title' => 'Gestion des modules', @@ -313,13 +295,13 @@ class addon extends common { * Export des données d'un module externes à module.json */ private function exportZip( $exportModule ){ - $infomodule = helper::getModules(); + $infoModules = helper::getModules(); // création du zip $zip = new ZipArchive(); if( ! is_dir('tmp/exportDataModules')) mkdir('tmp/exportDataModules',0777, true); $filename = 'tmp/exportDataModules/'.$exportModule.'dataExport.zip'; if( is_file( $filename )) unlink( $filename); - $directory = $infomodule[$exportModule]['dataDirectory'].'/'; + $directory = $infoModules[$exportModule]['dataDirectory'].'/'; if($zip->open( $filename, ZipArchive::CREATE) !== TRUE){ exit; } From f04a05168f69aac7d113659ad8885428bc728cca Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 15 Feb 2021 20:45:26 +0100 Subject: [PATCH 20/61] all pages match --- core/module/addon/addon.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 6bf11ea4..6c041295 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -175,7 +175,7 @@ class addon extends common { $key, $infoModules[$key]['realName'], $infoModules[$key]['version'], - array_search($key,$inPages),// devrait retourner toutes les valeurs et pas la première + implode(', ',array_keys($inPages,$key)), array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true ? template::button('moduleDelete' . $key, [ 'class' => 'moduleDelete buttonRed', From 19825afe2db2082098ae0c768bf80a564a1e8ef6 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Tue, 16 Feb 2021 09:44:04 +0100 Subject: [PATCH 21/61] 10.4.03 petites corrections --- CHANGES.md | 7 + README.md | 2 +- core/core.php | 31 +-- core/layout/main.php | 5 +- core/module/config/config.php | 28 +-- module/blog/view/article/article.php | 282 +++++++++++++-------------- module/blog/view/index/index.php | 2 - 7 files changed, 176 insertions(+), 181 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 028c8565..3857a8e6 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ # Changelog +## version 10.4.03 +- Corrections : + - En-tête html : absence de la langue. + - Suppression de la balise sémantique
    . + - Génération image Opengraph, mauvaise redirection. + - Nouvelle structure de données articles de blog dans le sitemap. + ## version 10.4.02 - Corrections : - Thème : aperçu du site amélioré. diff --git a/README.md b/README.md index cb9d1c5f..487b18c0 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ZwiiCMS 10.4.02 +# ZwiiCMS 10.4.03 Zwii est un CMS sans base de données (flat-file) qui permet de créer et gérer facilement un site web sans aucune connaissance en programmation. diff --git a/core/core.php b/core/core.php index e0602d7c..17cf9ca2 100755 --- a/core/core.php +++ b/core/core.php @@ -44,7 +44,7 @@ class common { const ACCESS_TIMER = 1800; // Numéro de version - const ZWII_VERSION = '10.4.02'; + const ZWII_VERSION = '10.4.03'; const ZWII_UPDATE_CHANNEL = "v10"; public static $actions = []; @@ -603,7 +603,7 @@ class common { $this->setData(['theme',$tempData['theme']]); // Import des users sauvegardés si option active - if ($keepUsers === false + if ($keepUsers === false AND $tempData['user'] !== NULL) { $this->setData(['user',$tempData['user']]); } @@ -766,6 +766,16 @@ class common { if ($this->getData(['page', $parentPageId, 'disable']) !== true ) { $sitemap->addUrl ($parentPageId,$datetime); } + // Articles du blog + if ($this->getData(['page', $parentPageId, 'moduleId']) === 'blog' && + !empty($this->getData(['module',$parentPageId])) ) { + foreach($this->getData(['module',$parentPageId,'posts']) as $articleId => $article) { + if($this->getData(['module',$parentPageId,'posts',$articleId,'state']) === true) { + $date = $this->getData(['module',$parentPageId,'posts',$articleId,'publishedOn']); + $sitemap->addUrl( $parentPageId . '/' . $articleId , new DateTime("@{$date}",new DateTimeZone($timezone))); + } + } + } // Sous-pages foreach($childrenPageIds as $childKey) { if ($this->getData(['page',$childKey,'group']) !== 0 || $this->getData(['page', $childKey, 'disable']) === true) { @@ -776,24 +786,15 @@ class common { // La sous-page est un blog if ($this->getData(['page', $childKey, 'moduleId']) === 'blog' && !empty($this->getData(['module',$childKey])) ) { - foreach($this->getData(['module',$childKey]) as $articleId => $article) { - if($this->getData(['module',$childKey,$articleId,'state']) === true) { - $date = $this->getData(['module',$childKey,$articleId,'publishedOn']); + foreach($this->getData(['module',$childKey,'posts']) as $articleId => $article) { + if($this->getData(['module',$childKey,'posts',$articleId,'state']) === true) { + $date = $this->getData(['module',$childKey,'posts',$articleId,'publishedOn']); $sitemap->addUrl( $childKey . '/' . $articleId , new DateTime("@{$date}",new DateTimeZone($timezone))); } } } } - // Articles du blog - if ($this->getData(['page', $parentPageId, 'moduleId']) === 'blog' && - !empty($this->getData(['module',$parentPageId])) ) { - foreach($this->getData(['module',$parentPageId]) as $articleId => $article) { - if($this->getData(['module',$parentPageId,$articleId,'state']) === true) { - $date = $this->getData(['module',$parentPageId,$articleId,'publishedOn']); - $sitemap->addUrl( $parentPageId . '/' . $articleId , new DateTime("@{$date}",new DateTimeZone($timezone))); - } - } - } + } // generating internally a sitemap diff --git a/core/layout/main.php b/core/layout/main.php index fb3eacfb..1f19cbc4 100755 --- a/core/layout/main.php +++ b/core/layout/main.php @@ -1,7 +1,6 @@ - + - + diff --git a/core/module/config/config.php b/core/module/config/config.php index 85f34738..a1932ca1 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -286,16 +286,20 @@ class config extends common { $data = str_replace('_','/',$googlePagespeedData['lighthouseResult']['audits']['final-screenshot']['details']['data']); $data = str_replace('-','+',$data); $img = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data)); - $success = file_put_contents( self::FILE_DIR.'source/screenshot.jpg',$img) ; - // Effacer la miniature png - if (file_exists(self::FILE_DIR.'source/screenshot.png')) { - unlink (self::FILE_DIR.'source/screenshot.png'); + // Effacer l'image et la miniature png + if (file_exists(self::FILE_DIR.'thumb/screenshot.jpg')) { + unlink (self::FILE_DIR.'thumb/screenshot.jpg'); } + if (file_exists(self::FILE_DIR.'source/screenshot.jpg')) { + unlink (self::FILE_DIR.'source/screenshot.jpg'); + } + $success = file_put_contents( self::FILE_DIR.'source/screenshot.jpg',$img) ; + } // Valeurs en sortie $this->addOutput([ 'notification' => $success === false ? 'Service inaccessible ou erreur d\'écriture de l\'image' : 'Image générée avec succès', - 'redirect' => helper::baseUrl() . 'advanced', + 'redirect' => helper::baseUrl() . 'config/advanced', 'state' => $success === false ? false : true ]); } @@ -376,13 +380,6 @@ class config extends common { $this->getInput('configManageImportUser', helper::FILTER_BOOLEAN) === true) { $this->setData(['user',$users]); } - /* - if ($version === '9' ) { - $this->importData($this->getInput('configManageImportUser', helper::FILTER_BOOLEAN)); - $this->setData(['core','dataVersion',0]); - }*/ - - // Met à jours les URL dans les contenus de page // Message de notification $notification = $success === true ? 'Restauration réalisée avec succès' : 'Erreur inconnue'; @@ -453,12 +450,7 @@ class config extends common { 'state' => $success ]); } - // Initialisation du screen - APPEL AUTO DESACTIVE POUR EVITER UN RALENTISSEMENT - /* - if (!file_exists(self::FILE_DIR.'source/screenshot.jpg')) { - $this->configMetaImage(); - } - */ + // Valeurs en sortie $this->addOutput([ 'title' => 'Configuration', diff --git a/module/blog/view/article/article.php b/module/blog/view/article/article.php index 7016c91c..6706ffa4 100755 --- a/module/blog/view/article/article.php +++ b/module/blog/view/article/article.php @@ -1,154 +1,152 @@ -
    -
    -
    -
    - - getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true) - ? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])) - : utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))); - $heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true) - ? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])) - : utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))); - echo $date . ' à ' . $heure; - ?> -
    -
    -
    - getUser('password') === $this->getInput('ZWII_USER_PASSWORD') - AND - ( // Propriétaire - ( - $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_OWNER - AND ( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'userId']) === $this->getUser('id') - OR $this->getUser('group') === self::GROUP_ADMIN ) - ) - OR ( - // Groupe - ( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_ADMIN - OR $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_MODERATOR) - AND $this->getUser('group') >= $this->getData(['module',$this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) - ) - OR ( - // Tout le monde - $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_ALL - AND $this->getUser('group') >= $module::$actions['config'] - ) - ) - ): ?> - helper::baseUrl() . $this->getUrl(0) . '/edit/' . $this->getUrl(1) . '/' . $_SESSION['csrf'], - 'value' => 'Editer' - ]); ?> - +
    +
    +
    + + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true) + ? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])) + : utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))); + $heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true) + ? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])) + : utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))); + echo $date . ' à ' . $heure; + ?>
    - getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']) === null ? '100' : $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']); ?> - getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'hidePicture']) == false) { - echo '' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picture']) . ''; - } ?> - getData(['module', $this->getUrl(0),'posts', $this->getUrl(1), 'content']); ?> -

    - - getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?> - - - getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentClose'])): ?> -

    Cet article ne reçoit pas de commentaire.

    - -

    - - - - 0 ? $commentsNb . ' ' . 'commentaire' . $s : 'Pas encore de commentaire'; ?> -

    - - 'Rédiger un commentaire...', - 'readonly' => true - ]); ?> -
    - getUser('password') === $this->getInput('ZWII_USER_PASSWORD')): ?> - 'Nom', - 'readonly' => true, - 'value' => $module::$editCommentSignature - ]); ?> - $this->getUser('id') - ]); ?> - -
    -
    - 'Nom' - ]); ?> -
    -
    -
    Ou
    -
    -
    - helper::baseUrl() . 'user/login/' . str_replace('/', '_', $this->getUrl()) . '__comment', - 'value' => 'Connexion' - ]); ?> -
    -
    - - 'Commentaire avec maximum '.$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength']).' caractères', - 'class' => 'editorWysiwygComment', - 'noDirty' => true, - 'maxlength' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength']) +
    + getUser('password') === $this->getInput('ZWII_USER_PASSWORD') + AND + ( // Propriétaire + ( + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_OWNER + AND ( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'userId']) === $this->getUser('id') + OR $this->getUser('group') === self::GROUP_ADMIN ) + ) + OR ( + // Groupe + ( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_ADMIN + OR $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_MODERATOR) + AND $this->getUser('group') >= $this->getData(['module',$this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) + ) + OR ( + // Tout le monde + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_ALL + AND $this->getUser('group') >= $module::$actions['config'] + ) + ) + ): ?> + helper::baseUrl() . $this->getUrl(0) . '/edit/' . $this->getUrl(1) . '/' . $_SESSION['csrf'], + 'value' => 'Editer' ]); ?> -
    - getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')): ?> -
    -
    - $this->getData(['config','captchaStrong']) - ]); ?> -
    -
    - + +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']) === null ? '100' : $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']); ?> + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'hidePicture']) == false) { + echo '' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picture']) . ''; + } ?> +getData(['module', $this->getUrl(0),'posts', $this->getUrl(1), 'content']); ?> +

    + +getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?> + + +getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentClose'])): ?> +

    Cet article ne reçoit pas de commentaire.

    + +

    + + + + 0 ? $commentsNb . ' ' . 'commentaire' . $s : 'Pas encore de commentaire'; ?> +

    + + 'Rédiger un commentaire...', + 'readonly' => true + ]); ?> +
    + getUser('password') === $this->getInput('ZWII_USER_PASSWORD')): ?> + 'Nom', + 'readonly' => true, + 'value' => $module::$editCommentSignature + ]); ?> + $this->getUser('id') + ]); ?> +
    -
    - 'buttonGrey', - 'value' => 'Annuler' +
    + 'Nom' ]); ?>
    -
    - 'Envoyer', - 'ico' => '' +
    +
    Ou
    +
    +
    + helper::baseUrl() . 'user/login/' . str_replace('/', '_', $this->getUrl()) . '__comment', + 'value' => 'Connexion' ]); ?>
    + + 'Commentaire avec maximum '.$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength']).' caractères', + 'class' => 'editorWysiwygComment', + 'noDirty' => true, + 'maxlength' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength']) + ]); ?> +
    + getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')): ?> +
    +
    + $this->getData(['config','captchaStrong']) + ]); ?> +
    +
    + +
    +
    + 'buttonGrey', + 'value' => 'Annuler' + ]); ?> +
    +
    + 'Envoyer', + 'ico' => '' + ]); ?> +
    - -
    -
    - $comment): ?> -
    -

    - le - -

    -
    + +
    +
    + $comment): ?> +
    +

    + le + +

    +
    - -
    \ No newline at end of file +
    + \ No newline at end of file diff --git a/module/blog/view/index/index.php b/module/blog/view/index/index.php index 1434d5b7..ca0f24d7 100755 --- a/module/blog/view/index/index.php +++ b/module/blog/view/index/index.php @@ -21,7 +21,6 @@
    From ee476e284241891130ff3bab420708a7b43275ee Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Tue, 16 Feb 2021 11:53:52 +0100 Subject: [PATCH 22/61] Modification fonction index() de addon.php --- core/module/addon/addon.php | 81 ++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 6c041295..506429f9 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -65,6 +65,42 @@ class addon extends common { * Gestion des modules */ public function index() { + // Lister les modules + // $infoModules[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] + $infoModules = helper::getModules(); + + // Clés moduleIds dans les pages + $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); + $inPagesTitle = []; + foreach( $inPages as $key=>$value){ + $inPagesTitle[ $this->getData(['page', $key, 'title' ]) ] = $value; + } + + // Parcourir les données des modules + foreach ($infoModules as $key=>$value) { + // Construire le tableau de sortie + self::$modInstal[] = [ + $key, + $infoModules[$key]['realName'], + $infoModules[$key]['version'], + implode(', ', array_keys($inPagesTitle,$key)), + array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true && implode(', ',array_keys($inPages,$key)) ==='' + ? template::button('moduleDelete' . $key, [ + 'class' => 'moduleDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + : '', + array_key_exists('dataDirectory',$infoModules[$key]) && $infoModules[$key]['dataDirectory'] !== '' + ? template::button('moduleExport' . $key, [ + 'class' => 'buttonBlue', + 'href' => helper::baseUrl(false).$this->exportZip( $key ), + 'value' => template::ico('upload') + ]) + : '' + ]; + } + // Retour du formulaire ? if($this->isPost()) { // Installation d'un module @@ -96,11 +132,11 @@ class addon extends common { // Lecture de la version du module pour validation de la mise à jour // Pour une version <= version installée l'utilisateur doit cocher 'Mise à jour forcée' - // Lecture de version en lisant la valeur des constantes directement dans le fichier nommodule.php $version = '0.0'; $file = file_get_contents( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php'); - // A FAIRE supprimer les espaces et les tab et rechercher 'constVERSION' - $pos1 = strpos($file, 'const VERSION'); + $file = str_replace(' ','',$file); + $file = str_replace("\t",'',$file); + $pos1 = strpos($file, 'constVERSION'); if( $pos1 !== false){ $posdeb = strpos($file, "'", $pos1); $posend = strpos($file, "'", $posdeb + 1); @@ -137,7 +173,12 @@ class addon extends common { } else{ $success = false; - $notification = ' Version détectée '.$version.' <= à celle installée '.$infoModules[$moduleName]['version']; + if( $valNewVersion == $valInstalVersion){ + $notification = ' Version détectée '.$version.' = à celle installée '.$infoModules[$moduleName]['version']; + } + else{ + $notification = ' Version détectée '.$version.' < à celle installée '.$infoModules[$moduleName]['version']; + } if( $infoModules[$moduleName]['update'] === false){ $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; } @@ -161,38 +202,6 @@ class addon extends common { ]); } - // Lister les modules - // $infoModules[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] - $infoModules = helper::getModules(); - - // Clés moduleIds dans les pages - $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); - - // Parcourir les données des modules - foreach ($infoModules as $key=>$value) { - // Construire le tableau de sortie - self::$modInstal[] = [ - $key, - $infoModules[$key]['realName'], - $infoModules[$key]['version'], - implode(', ',array_keys($inPages,$key)), - array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true - ? template::button('moduleDelete' . $key, [ - 'class' => 'moduleDelete buttonRed', - 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'], - 'value' => template::ico('cancel') - ]) - : '', - array_key_exists('update',$infoModules[$key]) && $infoModules[$key]['update'] === true - ? template::button('moduleDelete' . $key, [ - 'class' => 'moduleDelete buttonRed', - 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'], - 'value' => template::ico('cancel') - ]) - : '' - ]; - } - // Valeurs en sortie $this->addOutput([ 'title' => 'Gestion des modules', From 9dabff9d748973671b1d8840ac49f8d4d53063a0 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Tue, 16 Feb 2021 13:37:05 +0100 Subject: [PATCH 23/61] typos dans change --- CHANGES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 028c8565..713b4d54 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,7 +6,7 @@ - Thème : rétablissement du contrôle de l'import d'une version ancienne d'un thème. - Éditeur de texte : couleur de fond parasite quand une image en arrière-plan est sélectionnée. -## version 10.4.01 +## version 10.4.01 Corrections : - Module form, erreur de syntaxe. - Chargement d'un thème, désactivation du contrôle des clés. @@ -65,7 +65,7 @@ Correction : Corrections : - Conflit page inactive et droit d'un membre. - Module de recherche, correction dans les pages enfants. - - Module formulaire, perte des données en cas d'édition du fomulaire ou des champs. + - Module formulaire, perte des données en cas d'édition du formulaire ou des champs. Modification : - TinyMCE nettoyage init.js d'options non supportées. @@ -73,7 +73,7 @@ Modification : Corrections : - Configuration : persistance de l'ouverture des blocs. - Réinitialisation du mot de passe : - - Remise à zéro du timer après renouvèlement du mot de passe. + - Remise à zéro du timer après renouvellement du mot de passe. - Affichage de le fenêtre "Nouveau mot de passe" allégée. - Redirection sur la page d'accueil. - Modules news et blog : transparence icône RSS. From ca5e16d729cfdc0f465d64bf9f8040f8f89347c7 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Tue, 16 Feb 2021 14:31:25 +0100 Subject: [PATCH 24/61] =?UTF-8?q?D=C3=A9claration=20supprim=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/addon/addon.php | 1 - 1 file changed, 1 deletion(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 506429f9..c7ba9900 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -71,7 +71,6 @@ class addon extends common { // Clés moduleIds dans les pages $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); - $inPagesTitle = []; foreach( $inPages as $key=>$value){ $inPagesTitle[ $this->getData(['page', $key, 'title' ]) ] = $value; } From fdeb89465d0ccbe4982ce0bbc80625da24dc26ca Mon Sep 17 00:00:00 2001 From: fredtempez Date: Tue, 16 Feb 2021 18:45:01 +0100 Subject: [PATCH 25/61] =?UTF-8?q?removedir=20retourn=20un=20bool=C3=A9en?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/core.php | 8 ++++---- core/module/addon/addon.php | 41 +++++-------------------------------- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/core/core.php b/core/core.php index 75c28746..25468402 100755 --- a/core/core.php +++ b/core/core.php @@ -1009,11 +1009,11 @@ class common { * @param string URL du dossier à supprimer */ public function removeDir ( $path ) { - foreach ( new DirectoryIterator($path) as $item ): - if ( $item->isFile() ) unlink($item->getRealPath()); + foreach ( new DirectoryIterator($path) as $item ) { + if ( $item->isFile() ) @unlink($item->getRealPath()); if ( !$item->isDot() && $item->isDir() ) $this->removeDir($item->getRealPath()); - endforeach; - rmdir($path); + } + return ( rmdir($path) ); } /** diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index c7ba9900..402d96f7 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -43,7 +43,7 @@ class addon extends common { } else{ // Suppression des dossiers - if( $this->delete_directory('./module/'.$this->getUrl(2)) === true){ + if( $this->removeDir('./module/'.$this->getUrl(2) ) === true){ $success = true; $notification = 'Module '.$this->getUrl(2) .' effacé du dossier /module/, il peut rester des données dans d\'autres dossiers'; } @@ -65,6 +65,7 @@ class addon extends common { * Gestion des modules */ public function index() { + // Lister les modules // $infoModules[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory'] $infoModules = helper::getModules(); @@ -216,7 +217,9 @@ class addon extends common { // open the source directory $dir = opendir($src); // Make the destination directory if not exist - @mkdir($dst); + if (!is_dir($dst)) { + mkdir($dst); + } // Loop through the files in source directory while( $file = readdir($dir) ) { if (( $file != '.' ) && ( $file != '..' )) { @@ -233,40 +236,6 @@ class addon extends common { closedir($dir); } - /* - * - * Suppression d'un dossier et de ses sous-dossiers - */ - private function delete_directory($directory, $empty = false) { - if(substr($directory,-1) == "/") { - $directory = substr($directory,0,-1); - } - if(!file_exists($directory) || !is_dir($directory)) { - return false; - } elseif(!is_readable($directory)) { - return false; - } else { - $directoryHandle = opendir($directory); - while ($contents = readdir($directoryHandle)) { - if($contents != '.' && $contents != '..') { - $path = $directory . "/" . $contents; - if(is_dir($path)) { - $this->delete_directory($path); - } else { - unlink($path); - } - } - } - closedir($directoryHandle); - if($empty == false) { - if(!rmdir($directory)) { - return false; - } - } - return true; - } - } - /* * Création récursive d'un zip * https://makitweb.com/how-to-create-and-download-a-zip-file-with-php/ From df42bb55c9c32de909db92d1aff25515d1e8dd7e Mon Sep 17 00:00:00 2001 From: fredtempez Date: Tue, 16 Feb 2021 18:46:58 +0100 Subject: [PATCH 26/61] div manquant --- core/module/addon/view/index/index.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/module/addon/view/index/index.php b/core/module/addon/view/index/index.php index 9b421e4b..f1877e4e 100644 --- a/core/module/addon/view/index/index.php +++ b/core/module/addon/view/index/index.php @@ -37,9 +37,8 @@ - + - From f0a9371e5aac8cb41eb4ca55e1c8e6751c7790ac Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Wed, 17 Feb 2021 07:32:43 +0100 Subject: [PATCH 27/61] Nettoyage de core/module/addon....index.php --- core/module/addon/view/index/index.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/module/addon/view/index/index.php b/core/module/addon/view/index/index.php index f1877e4e..56c5bcf1 100644 --- a/core/module/addon/view/index/index.php +++ b/core/module/addon/view/index/index.php @@ -44,14 +44,3 @@ - - - - - -
    '; - var_dump( helper::getModules('site/tmp/toto/module') );*/ -?> - From 23de277cd661b6f3f76c705d9706cb3ce67a9290 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Wed, 17 Feb 2021 08:37:53 +0100 Subject: [PATCH 28/61] blog version --- module/blog/blog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/blog/blog.php b/module/blog/blog.php index 110d92f0..ae1d44e9 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -87,7 +87,7 @@ class blog extends common { public static $users = []; - const BLOG_VERSION = '4.2'; + const BLOG_VERSION = '4.3'; /** * Flux RSS From 0bf94567bf0e9115a99e047e92ec5302aa887bab Mon Sep 17 00:00:00 2001 From: fredtempez Date: Wed, 17 Feb 2021 13:49:58 +0100 Subject: [PATCH 29/61] =?UTF-8?q?Copyright=20ann=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 5 +++++ core/core.js.php | 5 +++-- core/core.php | 4 ++-- core/layout/blank.css | 5 +++-- core/layout/common.css | 5 +++-- core/layout/light.css | 5 +++-- core/module/addon/addon.php | 2 +- core/module/addon/view/index/index.css | 2 +- core/module/addon/view/index/index.js.php | 5 +++-- core/module/config/config.php | 2 +- core/module/config/view/advanced/advanced.css | 2 +- core/module/config/view/advanced/advanced.js.php | 2 +- core/module/config/view/backup/backup.css | 2 +- core/module/config/view/backup/backup.js.php | 2 +- core/module/config/view/index/index.css | 2 +- core/module/config/view/manage/manage.css | 2 +- core/module/config/view/script/script.css | 2 +- core/module/install/install.php | 5 +++-- core/module/install/view/index/index.js.php | 5 +++-- core/module/install/view/update/update.css | 2 +- core/module/maintenance/maintenance.php | 5 +++-- core/module/page/page.php | 2 +- core/module/page/view/edit/edit.css | 2 +- core/module/page/view/edit/edit.js.php | 2 +- core/module/sitemap/sitemap.php | 5 +++-- core/module/theme/theme.php | 2 +- core/module/theme/view/admin/admin.css | 2 +- core/module/theme/view/advanced/advanced.css | 2 +- core/module/theme/view/advanced/advanced.js.php | 5 +++-- core/module/theme/view/body/body.css | 2 +- core/module/theme/view/body/body.js.php | 5 +++-- core/module/theme/view/footer/footer.css | 2 +- core/module/theme/view/footer/footer.js.php | 2 +- core/module/theme/view/header/header.css | 2 +- core/module/theme/view/header/header.js.php | 2 +- core/module/theme/view/index/index.css | 5 +++-- core/module/theme/view/index/index.js.php | 5 +++-- core/module/theme/view/manage/manage.css | 2 +- core/module/theme/view/manage/manage.js.php | 5 +++-- core/module/theme/view/menu/menu.css | 2 +- core/module/theme/view/menu/menu.js.php | 5 +++-- core/module/theme/view/site/site.css | 2 +- core/module/theme/view/site/site.js.php | 5 +++-- core/module/translate/translate.php | 5 +++-- core/module/translate/view/index/index.css | 2 +- core/module/user/user.php | 5 +++-- core/module/user/view/add/add.css | 2 +- core/module/user/view/add/add.js.php | 5 +++-- core/module/user/view/edit/edit.css | 2 +- core/module/user/view/edit/edit.js.php | 5 +++-- core/module/user/view/import/import.css | 2 +- core/module/user/view/index/index.css | 2 +- core/module/user/view/index/index.js.php | 5 +++-- core/module/user/view/reset/reset.css | 2 +- index.php | 2 +- module/blog/blog.php | 5 +++-- module/blog/view/add/add.css | 2 +- module/blog/view/add/add.js.php | 5 +++-- module/blog/view/article/article.js.php | 5 +++-- module/blog/view/comment/comment.css | 2 +- module/blog/view/comment/comment.js.php | 5 +++-- module/blog/view/config/config.css | 2 +- module/blog/view/config/config.js.php | 5 +++-- module/blog/view/edit/edit.css | 2 +- module/blog/view/edit/edit.js.php | 5 +++-- module/form/form.php | 4 ++-- module/form/view/config/config.css | 2 +- module/form/view/config/config.js.php | 5 +++-- module/form/view/data/data.css | 2 +- module/form/view/data/data.js.php | 5 +++-- module/gallery/gallery.php | 2 +- module/gallery/view/config/config.css | 2 +- module/gallery/view/config/config.js.php | 2 +- module/gallery/view/edit/edit.css | 2 +- module/gallery/view/edit/edit.js.php | 5 +++-- module/gallery/view/gallery/gallery.js.php | 2 +- module/gallery/view/theme/theme.css | 2 +- module/news/news.php | 5 +++-- module/news/view/add/add.css | 2 +- module/news/view/add/add.js.php | 5 +++-- module/news/view/config/config.css | 2 +- module/news/view/config/config.js.php | 5 +++-- module/news/view/edit/edit.js.php | 5 +++-- module/news/view/index/index.css | 2 +- module/redirection/redirection.php | 5 +++-- module/redirection/view/config/config.css | 2 +- module/redirection/view/index/index.css | 2 +- module/search/search.php | 2 +- module/search/view/config/config.css | 2 +- 89 files changed, 165 insertions(+), 125 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d0afe0c9..74f586fa 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ # Changelog +## version 10.5.00 +- Modifications : + - Gestion des module dans l'interface d'administration. + - à compléter.. + ## version 10.4.03 - Corrections : - En-tête html : absence de la langue. diff --git a/core/core.js.php b/core/core.js.php index 09bfb0dd..869cd52c 100755 --- a/core/core.js.php +++ b/core/core.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/core.php b/core/core.php index 728c4ea3..840a8497 100755 --- a/core/core.php +++ b/core/core.php @@ -7,9 +7,9 @@ * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean - * @license GNU General Public License, version 3 * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez + * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/layout/blank.css b/core/layout/blank.css index b0bb2187..fed98888 100755 --- a/core/layout/blank.css +++ b/core/layout/blank.css @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/layout/common.css b/core/layout/common.css index 3a7f49da..adec27a8 100755 --- a/core/layout/common.css +++ b/core/layout/common.css @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/layout/light.css b/core/layout/light.css index 5ea840d3..ff248b7b 100755 --- a/core/layout/light.css +++ b/core/layout/light.css @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 402d96f7..eecbc3e4 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -9,7 +9,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/addon/view/index/index.css b/core/module/addon/view/index/index.css index 805e9150..5a91e7a7 100644 --- a/core/module/addon/view/index/index.css +++ b/core/module/addon/view/index/index.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/addon/view/index/index.js.php b/core/module/addon/view/index/index.js.php index 222b85a1..65ddb98d 100644 --- a/core/module/addon/view/index/index.js.php +++ b/core/module/addon/view/index/index.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/config.php b/core/module/config/config.php index c60dc090..7665cfd7 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -9,7 +9,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/view/advanced/advanced.css b/core/module/config/view/advanced/advanced.css index fc8f1ca2..fdc5d676 100644 --- a/core/module/config/view/advanced/advanced.css +++ b/core/module/config/view/advanced/advanced.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/view/advanced/advanced.js.php b/core/module/config/view/advanced/advanced.js.php index 14354f54..cc6664e6 100644 --- a/core/module/config/view/advanced/advanced.js.php +++ b/core/module/config/view/advanced/advanced.js.php @@ -5,7 +5,7 @@ * file that was distributed with this source code. * * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/view/backup/backup.css b/core/module/config/view/backup/backup.css index 01a06f8d..8796d11b 100755 --- a/core/module/config/view/backup/backup.css +++ b/core/module/config/view/backup/backup.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/view/backup/backup.js.php b/core/module/config/view/backup/backup.js.php index 90b38808..7e564b07 100755 --- a/core/module/config/view/backup/backup.js.php +++ b/core/module/config/view/backup/backup.js.php @@ -5,7 +5,7 @@ * file that was distributed with this source code. * * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/view/index/index.css b/core/module/config/view/index/index.css index 805e9150..5a91e7a7 100755 --- a/core/module/config/view/index/index.css +++ b/core/module/config/view/index/index.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/view/manage/manage.css b/core/module/config/view/manage/manage.css index 805e9150..5a91e7a7 100755 --- a/core/module/config/view/manage/manage.css +++ b/core/module/config/view/manage/manage.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/config/view/script/script.css b/core/module/config/view/script/script.css index 805e9150..5a91e7a7 100755 --- a/core/module/config/view/script/script.css +++ b/core/module/config/view/script/script.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/install/install.php b/core/module/install/install.php index e9fef5a2..d7c419c5 100755 --- a/core/module/install/install.php +++ b/core/module/install/install.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/install/view/index/index.js.php b/core/module/install/view/index/index.js.php index eef087dd..9f487c3a 100755 --- a/core/module/install/view/index/index.js.php +++ b/core/module/install/view/index/index.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/install/view/update/update.css b/core/module/install/view/update/update.css index 805e9150..5a91e7a7 100755 --- a/core/module/install/view/update/update.css +++ b/core/module/install/view/update/update.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/maintenance/maintenance.php b/core/module/maintenance/maintenance.php index 8840123b..cee861af 100755 --- a/core/module/maintenance/maintenance.php +++ b/core/module/maintenance/maintenance.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/page/page.php b/core/module/page/page.php index c8f57db4..f842e3da 100755 --- a/core/module/page/page.php +++ b/core/module/page/page.php @@ -9,7 +9,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/page/view/edit/edit.css b/core/module/page/view/edit/edit.css index f456dd05..3eed60ff 100755 --- a/core/module/page/view/edit/edit.css +++ b/core/module/page/view/edit/edit.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/page/view/edit/edit.js.php b/core/module/page/view/edit/edit.js.php index 941b24a0..c73b5f66 100755 --- a/core/module/page/view/edit/edit.js.php +++ b/core/module/page/view/edit/edit.js.php @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @authorFrédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/sitemap/sitemap.php b/core/module/sitemap/sitemap.php index 0d14ded4..f57e382d 100755 --- a/core/module/sitemap/sitemap.php +++ b/core/module/sitemap/sitemap.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/theme.php b/core/module/theme/theme.php index a3c1b137..c1441b26 100755 --- a/core/module/theme/theme.php +++ b/core/module/theme/theme.php @@ -11,7 +11,7 @@ * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ * @copyright : Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez */ class theme extends common { diff --git a/core/module/theme/view/admin/admin.css b/core/module/theme/view/admin/admin.css index 08286440..4b233fe4 100755 --- a/core/module/theme/view/admin/admin.css +++ b/core/module/theme/view/admin/admin.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/advanced/advanced.css b/core/module/theme/view/advanced/advanced.css index 805e9150..5a91e7a7 100755 --- a/core/module/theme/view/advanced/advanced.css +++ b/core/module/theme/view/advanced/advanced.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/advanced/advanced.js.php b/core/module/theme/view/advanced/advanced.js.php index 464d93bb..b2a50fa7 100755 --- a/core/module/theme/view/advanced/advanced.js.php +++ b/core/module/theme/view/advanced/advanced.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/body/body.css b/core/module/theme/view/body/body.css index 1a3509ef..8911d1f1 100755 --- a/core/module/theme/view/body/body.css +++ b/core/module/theme/view/body/body.css @@ -7,7 +7,7 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean * @license GNU General Public License, version 3 * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/body/body.js.php b/core/module/theme/view/body/body.js.php index 19a42926..c2d4cdd9 100755 --- a/core/module/theme/view/body/body.js.php +++ b/core/module/theme/view/body/body.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/footer/footer.css b/core/module/theme/view/footer/footer.css index 805e9150..5a91e7a7 100755 --- a/core/module/theme/view/footer/footer.css +++ b/core/module/theme/view/footer/footer.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/footer/footer.js.php b/core/module/theme/view/footer/footer.js.php index 9b5e9c5c..da12b143 100755 --- a/core/module/theme/view/footer/footer.js.php +++ b/core/module/theme/view/footer/footer.js.php @@ -8,7 +8,7 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean * @license GNU General Public License, version 3 * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/header/header.css b/core/module/theme/view/header/header.css index 9346d7ac..d2dafebe 100755 --- a/core/module/theme/view/header/header.css +++ b/core/module/theme/view/header/header.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/header/header.js.php b/core/module/theme/view/header/header.js.php index 87a89cf2..3669bcb8 100755 --- a/core/module/theme/view/header/header.js.php +++ b/core/module/theme/view/header/header.js.php @@ -8,7 +8,7 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean * @license GNU General Public License, version 3 * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/index/index.css b/core/module/theme/view/index/index.css index 809178d3..eb802426 100755 --- a/core/module/theme/view/index/index.css +++ b/core/module/theme/view/index/index.css @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/index/index.js.php b/core/module/theme/view/index/index.js.php index 345e765e..1d5eaff3 100755 --- a/core/module/theme/view/index/index.js.php +++ b/core/module/theme/view/index/index.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/manage/manage.css b/core/module/theme/view/manage/manage.css index 805e9150..5a91e7a7 100755 --- a/core/module/theme/view/manage/manage.css +++ b/core/module/theme/view/manage/manage.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/manage/manage.js.php b/core/module/theme/view/manage/manage.js.php index 765a9662..99bc73c9 100755 --- a/core/module/theme/view/manage/manage.js.php +++ b/core/module/theme/view/manage/manage.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/menu/menu.css b/core/module/theme/view/menu/menu.css index 805e9150..5a91e7a7 100755 --- a/core/module/theme/view/menu/menu.css +++ b/core/module/theme/view/menu/menu.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/menu/menu.js.php b/core/module/theme/view/menu/menu.js.php index 891c6d58..c707fb66 100755 --- a/core/module/theme/view/menu/menu.js.php +++ b/core/module/theme/view/menu/menu.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/site/site.css b/core/module/theme/view/site/site.css index 805e9150..5a91e7a7 100755 --- a/core/module/theme/view/site/site.css +++ b/core/module/theme/view/site/site.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/theme/view/site/site.js.php b/core/module/theme/view/site/site.js.php index 279dd85e..e5090081 100755 --- a/core/module/theme/view/site/site.js.php +++ b/core/module/theme/view/site/site.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/translate/translate.php b/core/module/translate/translate.php index 890e4d0a..c9a9f87e 100755 --- a/core/module/translate/translate.php +++ b/core/module/translate/translate.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/translate/view/index/index.css b/core/module/translate/view/index/index.css index 51a18ec5..88fe3629 100755 --- a/core/module/translate/view/index/index.css +++ b/core/module/translate/view/index/index.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/user.php b/core/module/user/user.php index 69c3580e..21e05cfd 100755 --- a/core/module/user/user.php +++ b/core/module/user/user.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/add/add.css b/core/module/user/view/add/add.css index 55e779b3..1ab3eefb 100755 --- a/core/module/user/view/add/add.css +++ b/core/module/user/view/add/add.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/add/add.js.php b/core/module/user/view/add/add.js.php index 6d797f0c..545fb77c 100755 --- a/core/module/user/view/add/add.js.php +++ b/core/module/user/view/add/add.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/edit/edit.css b/core/module/user/view/edit/edit.css index 805e9150..5a91e7a7 100755 --- a/core/module/user/view/edit/edit.css +++ b/core/module/user/view/edit/edit.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/edit/edit.js.php b/core/module/user/view/edit/edit.js.php index ad7e1087..d7ce4dc8 100755 --- a/core/module/user/view/edit/edit.js.php +++ b/core/module/user/view/edit/edit.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/import/import.css b/core/module/user/view/import/import.css index 2aa6edae..20dbdfe1 100755 --- a/core/module/user/view/import/import.css +++ b/core/module/user/view/import/import.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/index/index.css b/core/module/user/view/index/index.css index 805e9150..5a91e7a7 100755 --- a/core/module/user/view/index/index.css +++ b/core/module/user/view/index/index.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/index/index.js.php b/core/module/user/view/index/index.js.php index 53d5d62d..13e05743 100755 --- a/core/module/user/view/index/index.js.php +++ b/core/module/user/view/index/index.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/core/module/user/view/reset/reset.css b/core/module/user/view/reset/reset.css index 75723119..f422a347 100755 --- a/core/module/user/view/reset/reset.css +++ b/core/module/user/view/reset/reset.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/index.php b/index.php index 30ea149e..3e6b954b 100755 --- a/index.php +++ b/index.php @@ -9,7 +9,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/blog.php b/module/blog/blog.php index e6843a1f..087505f4 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/add/add.css b/module/blog/view/add/add.css index 805e9150..5a91e7a7 100755 --- a/module/blog/view/add/add.css +++ b/module/blog/view/add/add.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/add/add.js.php b/module/blog/view/add/add.js.php index 6067ca10..aacac9d9 100755 --- a/module/blog/view/add/add.js.php +++ b/module/blog/view/add/add.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/article/article.js.php b/module/blog/view/article/article.js.php index 0d0fb3e9..b2e7e613 100755 --- a/module/blog/view/article/article.js.php +++ b/module/blog/view/article/article.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/comment/comment.css b/module/blog/view/comment/comment.css index 805e9150..5a91e7a7 100755 --- a/module/blog/view/comment/comment.css +++ b/module/blog/view/comment/comment.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/comment/comment.js.php b/module/blog/view/comment/comment.js.php index fc6f7aaa..f7bc30d0 100755 --- a/module/blog/view/comment/comment.js.php +++ b/module/blog/view/comment/comment.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/config/config.css b/module/blog/view/config/config.css index 805e9150..5a91e7a7 100755 --- a/module/blog/view/config/config.css +++ b/module/blog/view/config/config.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/config/config.js.php b/module/blog/view/config/config.js.php index df6138c0..156fb1b1 100755 --- a/module/blog/view/config/config.js.php +++ b/module/blog/view/config/config.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/edit/edit.css b/module/blog/view/edit/edit.css index 805e9150..5a91e7a7 100755 --- a/module/blog/view/edit/edit.css +++ b/module/blog/view/edit/edit.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/blog/view/edit/edit.js.php b/module/blog/view/edit/edit.js.php index 96e2872a..503c99bd 100755 --- a/module/blog/view/edit/edit.js.php +++ b/module/blog/view/edit/edit.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/form/form.php b/module/form/form.php index fd66b16a..f8fea92a 100755 --- a/module/form/form.php +++ b/module/form/form.php @@ -9,7 +9,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ @@ -167,7 +167,7 @@ class form extends common { /** * Export CSV * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez */ public function export2csv() { // Jeton incorrect diff --git a/module/form/view/config/config.css b/module/form/view/config/config.css index 5ad89b08..c9c08e84 100755 --- a/module/form/view/config/config.css +++ b/module/form/view/config/config.css @@ -8,7 +8,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/form/view/config/config.js.php b/module/form/view/config/config.js.php index 37afae73..f0f985bd 100755 --- a/module/form/view/config/config.js.php +++ b/module/form/view/config/config.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/form/view/data/data.css b/module/form/view/data/data.css index 805e9150..5a91e7a7 100755 --- a/module/form/view/data/data.css +++ b/module/form/view/data/data.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/form/view/data/data.js.php b/module/form/view/data/data.js.php index 9fb2aafd..f4c0b2b2 100755 --- a/module/form/view/data/data.js.php +++ b/module/form/view/data/data.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index e8526b7c..a99b62db 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -9,7 +9,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/gallery/view/config/config.css b/module/gallery/view/config/config.css index 8079fedb..b15a3331 100755 --- a/module/gallery/view/config/config.css +++ b/module/gallery/view/config/config.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/gallery/view/config/config.js.php b/module/gallery/view/config/config.js.php index f56117b3..ca2edf11 100755 --- a/module/gallery/view/config/config.js.php +++ b/module/gallery/view/config/config.js.php @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/gallery/view/edit/edit.css b/module/gallery/view/edit/edit.css index 805e9150..5a91e7a7 100755 --- a/module/gallery/view/edit/edit.css +++ b/module/gallery/view/edit/edit.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/gallery/view/edit/edit.js.php b/module/gallery/view/edit/edit.js.php index c36e08d7..97aa4fc3 100755 --- a/module/gallery/view/edit/edit.js.php +++ b/module/gallery/view/edit/edit.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/gallery/view/gallery/gallery.js.php b/module/gallery/view/gallery/gallery.js.php index d99980d2..0b7c46b9 100755 --- a/module/gallery/view/gallery/gallery.js.php +++ b/module/gallery/view/gallery/gallery.js.php @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/gallery/view/theme/theme.css b/module/gallery/view/theme/theme.css index 805e9150..5a91e7a7 100755 --- a/module/gallery/view/theme/theme.css +++ b/module/gallery/view/theme/theme.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/news/news.php b/module/news/news.php index d65c2860..2aec5e94 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/news/view/add/add.css b/module/news/view/add/add.css index 805e9150..5a91e7a7 100755 --- a/module/news/view/add/add.css +++ b/module/news/view/add/add.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/news/view/add/add.js.php b/module/news/view/add/add.js.php index 77bb1442..34d682e6 100755 --- a/module/news/view/add/add.js.php +++ b/module/news/view/add/add.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/news/view/config/config.css b/module/news/view/config/config.css index 805e9150..5a91e7a7 100755 --- a/module/news/view/config/config.css +++ b/module/news/view/config/config.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/news/view/config/config.js.php b/module/news/view/config/config.js.php index 608f5324..1a75b6f8 100755 --- a/module/news/view/config/config.js.php +++ b/module/news/view/config/config.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/news/view/edit/edit.js.php b/module/news/view/edit/edit.js.php index ef1444ff..2b5a4ece 100755 --- a/module/news/view/edit/edit.js.php +++ b/module/news/view/edit/edit.js.php @@ -1,11 +1,12 @@ /** - * This file is part of Zwii. - * + * This file is part of Zwii. * * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/news/view/index/index.css b/module/news/view/index/index.css index d500e8fe..ba6dd269 100755 --- a/module/news/view/index/index.css +++ b/module/news/view/index/index.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/redirection/redirection.php b/module/redirection/redirection.php index 97a5e6ea..86a4765d 100755 --- a/module/redirection/redirection.php +++ b/module/redirection/redirection.php @@ -1,13 +1,14 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/redirection/view/config/config.css b/module/redirection/view/config/config.css index 805e9150..5a91e7a7 100755 --- a/module/redirection/view/config/config.css +++ b/module/redirection/view/config/config.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/redirection/view/index/index.css b/module/redirection/view/index/index.css index 805e9150..5a91e7a7 100755 --- a/module/redirection/view/index/index.css +++ b/module/redirection/view/index/index.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ diff --git a/module/search/search.php b/module/search/search.php index 7952edd8..fb1d22c7 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -9,7 +9,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @copyright Sylvain Lelièvre * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ diff --git a/module/search/view/config/config.css b/module/search/view/config/config.css index 9346d7ac..d2dafebe 100755 --- a/module/search/view/config/config.css +++ b/module/search/view/config/config.css @@ -7,7 +7,7 @@ * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ From 75539e2ef1fc09e961e1c42d11e731876732181f Mon Sep 17 00:00:00 2001 From: fredtempez Date: Wed, 17 Feb 2021 13:51:12 +0100 Subject: [PATCH 30/61] Copyright encore --- core/core.js.php | 2 +- core/core.php | 2 +- core/layout/blank.css | 2 +- core/layout/common.css | 2 +- core/layout/light.css | 2 +- core/module/addon/view/index/index.js.php | 2 +- core/module/install/install.php | 2 +- core/module/install/view/index/index.js.php | 2 +- core/module/maintenance/maintenance.php | 2 +- core/module/sitemap/sitemap.php | 2 +- core/module/theme/view/advanced/advanced.js.php | 2 +- core/module/theme/view/body/body.css | 2 +- core/module/theme/view/body/body.js.php | 2 +- core/module/theme/view/index/index.css | 2 +- core/module/theme/view/index/index.js.php | 2 +- core/module/theme/view/manage/manage.js.php | 2 +- core/module/theme/view/menu/menu.js.php | 2 +- core/module/theme/view/site/site.js.php | 2 +- core/module/translate/translate.php | 2 +- core/module/user/user.php | 2 +- core/module/user/view/add/add.js.php | 2 +- core/module/user/view/edit/edit.js.php | 2 +- core/module/user/view/index/index.js.php | 2 +- module/blog/blog.php | 2 +- module/blog/view/add/add.js.php | 2 +- module/blog/view/article/article.js.php | 2 +- module/blog/view/comment/comment.js.php | 2 +- module/blog/view/config/config.js.php | 2 +- module/blog/view/edit/edit.js.php | 2 +- module/form/view/config/config.js.php | 2 +- module/form/view/data/data.js.php | 2 +- module/gallery/view/edit/edit.js.php | 2 +- module/news/news.php | 2 +- module/news/view/add/add.js.php | 2 +- module/news/view/config/config.js.php | 2 +- module/news/view/edit/edit.js.php | 2 +- module/redirection/redirection.php | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/core/core.js.php b/core/core.js.php index 869cd52c..456cd067 100755 --- a/core/core.js.php +++ b/core/core.js.php @@ -1,5 +1,5 @@ /** - * This file is part of Zwii. * + * This file is part of Zwii. * For full copyright and license information, please see the LICENSE * file that was distributed with this source code. * diff --git a/core/core.php b/core/core.php index 840a8497..5d760b11 100755 --- a/core/core.php +++ b/core/core.php @@ -1,7 +1,7 @@ Date: Wed, 17 Feb 2021 14:16:58 +0100 Subject: [PATCH 31/61] =?UTF-8?q?Effacement=20autoris=C3=A9=20si=20DELETE?= =?UTF-8?q?=20=3D=20TRUE=20OU=20NON=20DEFINI=20et=20module=20pas=20mis=20e?= =?UTF-8?q?n=20oeuvre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/addon/addon.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index eecbc3e4..1dd4d8ea 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -84,7 +84,8 @@ class addon extends common { $infoModules[$key]['realName'], $infoModules[$key]['version'], implode(', ', array_keys($inPagesTitle,$key)), - array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true && implode(', ',array_keys($inPages,$key)) ==='' + //array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true && implode(', ',array_keys($inPages,$key)) === '' + ($infoModules[$key]['delete'] === false || $infoModules[$key]['delete'] !== false ) && implode(', ',array_keys($inPages,$key)) === '' ? template::button('moduleDelete' . $key, [ 'class' => 'moduleDelete buttonRed', 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'], From 1eb994368ef1bc12c259a33fe3dd1ea5fe8a22e1 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Wed, 17 Feb 2021 19:34:08 +0100 Subject: [PATCH 32/61] Export WIP --- core/class/helper.class.php | 8 ++-- core/module/addon/addon.php | 93 ++++++++++++++++++++++++++++++------- 2 files changed, 79 insertions(+), 22 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index d711bceb..5cc558dc 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -161,19 +161,19 @@ class helper { if (array_key_exists('UPDATE', $class_constants)) { $update = $value::UPDATE; } else { - $update = false; + $update = true; } // Constante DELETE if (array_key_exists('DELETE', $class_constants)) { $delete = $value::DELETE; } else { - $delete = false; + $delete = true; } // Constante DATADIRECTORY if (array_key_exists('DATADIRECTORY', $class_constants)) { - $dataDirectory= $value::DATADIRECTORY; + $dataDirectory = $value::DATADIRECTORY; } else { - $dataDirectory = ''; + $dataDirectory = ['fr/module.json']; } // Affection $modules [$value] = [ diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 1dd4d8ea..0aebd0b5 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -18,7 +18,8 @@ class addon extends common { public static $actions = [ 'index' => self::GROUP_ADMIN, - 'moduleDelete' => self::GROUP_ADMIN + 'moduleDelete' => self::GROUP_ADMIN, + 'exportModuleData' => self::GROUP_ADMIN, ]; // Gestion des modules @@ -85,17 +86,17 @@ class addon extends common { $infoModules[$key]['version'], implode(', ', array_keys($inPagesTitle,$key)), //array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true && implode(', ',array_keys($inPages,$key)) === '' - ($infoModules[$key]['delete'] === false || $infoModules[$key]['delete'] !== false ) && implode(', ',array_keys($inPages,$key)) === '' + $infoModules[$key]['delete'] === true && implode(', ',array_keys($inPages,$key)) === '' ? template::button('moduleDelete' . $key, [ 'class' => 'moduleDelete buttonRed', 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'], 'value' => template::ico('cancel') ]) : '', - array_key_exists('dataDirectory',$infoModules[$key]) && $infoModules[$key]['dataDirectory'] !== '' + is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) !== '' ? template::button('moduleExport' . $key, [ 'class' => 'buttonBlue', - 'href' => helper::baseUrl(false).$this->exportZip( $key ), + 'href' => helper::baseUrl(). $this->getUrl(0) . '/exportModuleData/' . $key,// appel de fonction vaut exécution, utiliser un paramètre 'value' => template::ico('upload') ]) : '' @@ -270,23 +271,79 @@ class addon extends common { } /* - * Export des données d'un module externes à module.json + * Export des données d'un module externes ou interne à module.json */ - private function exportZip( $exportModule ){ + public function exportModuleData(){ + // Lire les données du module $infoModules = helper::getModules(); + // Créer un dossier par défaut + $tmpFolder = self::TEMP_DIR . uniqid(); + //$tmpFolder = self::TEMP_DIR . 'test'; + if (!is_dir($tmpFolder)) { + mkdir($tmpFolder); + } + // Clés moduleIds dans les pages + $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); + // Parcourir les pages utilisant le module + foreach (array_keys($inPages,$this->getUrl(2)) as $pageId) { + foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $moduleId) { + /** + * Données module.json ? + */ + if (strpos($moduleId,'module.json')) { + // Création de l'arborescence des langues + // Pas de nom dossier de langue - dossier par défaut + $t = explode ('/',$moduleId); + if ( is_array($t)) { + $path = 'fr'; + } else { + $path = $t[0]; + } + // Créer le dossier si inexistant + if (!is_dir($tmpFolder . '/' . $path)) { + mkdir ($tmpFolder . '/' . $path); + } + // Sauvegarde si données non vides + $tmpData [$pageId] = $this->getData(['module',$pageId ]); + if ($tmpData [$pageId] !== null) { + file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData)); + } + /** + * Données dans un json personnalisé, le sauvegarder + */ + } else { + if (file_exists(self::DATA_DIR . '/' . $moduleId) && + !file_exists($tmpFolder . '/' . $moduleId ) ) { + copy ( self::DATA_DIR . '/' . $moduleId, $tmpFolder . '/' . $moduleId ); + } + } + } + } // création du zip - $zip = new ZipArchive(); - if( ! is_dir('tmp/exportDataModules')) mkdir('tmp/exportDataModules',0777, true); - $filename = 'tmp/exportDataModules/'.$exportModule.'dataExport.zip'; - if( is_file( $filename )) unlink( $filename); - $directory = $infoModules[$exportModule]['dataDirectory'].'/'; - if($zip->open( $filename, ZipArchive::CREATE) !== TRUE){ - exit; + $fileName = self::TEMP_DIR . '/' . $this->geturl(2) . 'zip'; + $this->createZip($fileName,$tmpFolder); + if (file_exists($fileName)) { + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename="' . $fileName . '"'); + header('Content-Length: ' . filesize($fileName)); + readfile( $fileName); + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_RAW + ]); + //unlink($filename); + //$this->removeDir($tmpFolder); + // Valeurs en sortie + + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'addon', + 'notification' => 'Quelque chose s\'est mal passé', + 'state' => false + ]); } - else{ - $this->createZip($zip,$directory); - $zip->close(); - } - return( $filename ); + } + } From e584e9fd5fd8f37440a36494872c2297cf9d9370 Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Thu, 18 Feb 2021 08:56:07 +0100 Subject: [PATCH 33/61] Ajout copyright addon --- core/module/addon/addon.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 0aebd0b5..81067f05 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -10,6 +10,8 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez * @copyright Copyright (C) 2018-2021, Frédéric Tempez + * @author Sylvain Lelièvre +* @copyright Copyright (C) 2020-2021, Sylvain Lelièvre * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ From b5d31033ffccb56dbc33b557ce5694ceab3fc1a7 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 10:07:05 +0100 Subject: [PATCH 34/61] Blog Balise de fermeture de commentaire - constantes dans les modules --- CHANGES.md | 6 ++++++ README.md | 2 +- core/core.php | 2 +- module/blog/blog.php | 9 ++++++++- module/blog/view/article/article.php | 1 + module/blog/view/config/config.php | 2 +- module/form/form.php | 10 +++++++++- module/form/view/config/config.php | 2 +- module/form/view/data/data.php | 2 +- module/gallery/gallery.php | 11 ++++++++++- module/gallery/view/config/config.php | 2 +- module/gallery/view/edit/edit.php | 2 +- module/gallery/view/theme/theme.php | 2 +- module/news/news.php | 9 ++++++++- module/news/view/config/config.php | 2 +- module/redirection/redirection.php | 9 ++++++++- module/redirection/view/config/config.php | 2 +- module/search/search.php | 9 ++++++++- module/search/view/config/config.php | 2 +- 19 files changed, 69 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3857a8e6..d8eca2fe 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Changelog +## version 10.4.04 +- Correction : + - Module Blog : balise non fermée dans les commentaires. +- Modifications : + -Constantes de modules. + ## version 10.4.03 - Corrections : - En-tête html : absence de la langue. diff --git a/README.md b/README.md index 487b18c0..7a84065d 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ZwiiCMS 10.4.03 +# ZwiiCMS 10.4.04 Zwii est un CMS sans base de données (flat-file) qui permet de créer et gérer facilement un site web sans aucune connaissance en programmation. diff --git a/core/core.php b/core/core.php index 17cf9ca2..66b8fbdc 100755 --- a/core/core.php +++ b/core/core.php @@ -44,7 +44,7 @@ class common { const ACCESS_TIMER = 1800; // Numéro de version - const ZWII_VERSION = '10.4.03'; + const ZWII_VERSION = '10.4.04'; const ZWII_UPDATE_CHANNEL = "v10"; public static $actions = []; diff --git a/module/blog/blog.php b/module/blog/blog.php index ae1d44e9..2e7e0538 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -14,6 +14,14 @@ class blog extends common { + const VERSION = '4.4'; + const REALNAME = 'Blog'; + const DELETE = true; + const UPDATE = true; + const DATADIRECTORY = [ + 'fr/module.json' + ]; + const EDIT_OWNER = 'owner'; const EDIT_GROUP = 'group'; const EDIT_ALL = 'all'; @@ -87,7 +95,6 @@ class blog extends common { public static $users = []; - const BLOG_VERSION = '4.3'; /** * Flux RSS diff --git a/module/blog/view/article/article.php b/module/blog/view/article/article.php index 6706ffa4..aa19fe55 100755 --- a/module/blog/view/article/article.php +++ b/module/blog/view/article/article.php @@ -144,6 +144,7 @@ ? strftime('%d %B %Y - %H:%M', $comment['createdOn']) : utf8_encode(strftime('%d %B %Y - %H:%M', $comment['createdOn'])); ?> + diff --git a/module/blog/view/config/config.php b/module/blog/view/config/config.php index 7830d8fd..fee5671a 100755 --- a/module/blog/view/config/config.php +++ b/module/blog/view/config/config.php @@ -47,6 +47,6 @@
    Version n° - +
    diff --git a/module/form/form.php b/module/form/form.php index a47a0ec7..597a0323 100755 --- a/module/form/form.php +++ b/module/form/form.php @@ -16,6 +16,14 @@ class form extends common { + const VERSION = '2.8'; + const REALNAME = 'Formulaire'; + const DELETE = true; + const UPDATE = true; + const DATADIRECTORY = [ + 'fr/module.json' + ]; + public static $actions = [ 'config' => self::GROUP_MODERATOR, 'data' => self::GROUP_MODERATOR, @@ -32,7 +40,7 @@ class form extends common { public static $pagination; - const FORM_VERSION = '2.7'; + // Objets const TYPE_MAIL = 'mail'; diff --git a/module/form/view/config/config.php b/module/form/view/config/config.php index 5d2e8946..fea6d9ff 100755 --- a/module/form/view/config/config.php +++ b/module/form/view/config/config.php @@ -164,5 +164,5 @@
    Version n° - +
    diff --git a/module/form/view/data/data.php b/module/form/view/data/data.php index c60511b4..947e20db 100755 --- a/module/form/view/data/data.php +++ b/module/form/view/data/data.php @@ -26,5 +26,5 @@
    Version n° - +
    \ No newline at end of file diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 77d0f2c3..a3bb4618 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -16,10 +16,19 @@ class gallery extends common { + + const VERSION = '2.6'; + const REALNAME = 'Galerie'; + const DELETE = true; + const UPDATE = true; + const DATADIRECTORY = [ + 'fr/module.json' + ]; + const SORT_ASC = 'SORT_ASC'; const SORT_DSC = 'SORT_DSC'; const SORT_HAND = 'SORT_HAND'; - const GALLERY_VERSION = '2.5'; + public static $directories = []; diff --git a/module/gallery/view/config/config.php b/module/gallery/view/config/config.php index 0c41378b..91400a98 100755 --- a/module/gallery/view/config/config.php +++ b/module/gallery/view/config/config.php @@ -58,6 +58,6 @@
    Version n° - +
    diff --git a/module/gallery/view/edit/edit.php b/module/gallery/view/edit/edit.php index 9b243d32..c745d1e5 100755 --- a/module/gallery/view/edit/edit.php +++ b/module/gallery/view/edit/edit.php @@ -64,6 +64,6 @@
    Version n° - +
    diff --git a/module/gallery/view/theme/theme.php b/module/gallery/view/theme/theme.php index 8ada32ed..694ecaf9 100755 --- a/module/gallery/view/theme/theme.php +++ b/module/gallery/view/theme/theme.php @@ -139,7 +139,7 @@
    Version n° - +
    \ No newline at end of file diff --git a/module/news/news.php b/module/news/news.php index 13fcb2fa..89eb1aca 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -14,6 +14,14 @@ class news extends common { + const VERSION = '2.1'; + const REALNAME = 'Actualités'; + const DELETE = true; + const UPDATE = true; + const DATADIRECTORY = [ + 'fr/module.json' + ]; + public static $actions = [ 'add' => self::GROUP_MODERATOR, 'config' => self::GROUP_MODERATOR, @@ -33,7 +41,6 @@ class news extends common { false => 'Brouillon', true => 'Publié' ]; - const NEWS_VERSION = '2.0'; public static $users = []; diff --git a/module/news/view/config/config.php b/module/news/view/config/config.php index f25fe3d0..73929b9d 100755 --- a/module/news/view/config/config.php +++ b/module/news/view/config/config.php @@ -48,5 +48,5 @@
    Version n° - +
    \ No newline at end of file diff --git a/module/redirection/redirection.php b/module/redirection/redirection.php index 5c92521c..e39d70d4 100755 --- a/module/redirection/redirection.php +++ b/module/redirection/redirection.php @@ -14,12 +14,19 @@ class redirection extends common { + const VERSION = '1.5'; + const REALNAME = 'Redirection'; + const DELETE = true; + const UPDATE = true; + const DATADIRECTORY = [ + 'fr/module.json' + ]; + public static $actions = [ 'config' => self::GROUP_MODERATOR, 'index' => self::GROUP_VISITOR ]; - const REDIRECTION_VERSION = '1.4'; /** * Configuration diff --git a/module/redirection/view/config/config.php b/module/redirection/view/config/config.php index 72071f4c..ff421b39 100755 --- a/module/redirection/view/config/config.php +++ b/module/redirection/view/config/config.php @@ -37,5 +37,5 @@
    Version n° - +
    \ No newline at end of file diff --git a/module/search/search.php b/module/search/search.php index f84dfdeb..56e71f05 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -18,6 +18,14 @@ class search extends common { + const VERSION = '1.3'; + const REALNAME = 'Recherche'; + const DELETE = true; + const UPDATE = true; + const DATADIRECTORY = [ + 'fr/module.json' + ]; + public static $actions = [ 'index' => self::GROUP_VISITOR, 'config' => self::GROUP_MODERATOR @@ -38,7 +46,6 @@ class search extends common { 400 => '400 caractères', ]; - const SEARCH_VERSION = '1.2'; // Configuration vide public function config() { diff --git a/module/search/view/config/config.php b/module/search/view/config/config.php index 37a60653..f54674d7 100755 --- a/module/search/view/config/config.php +++ b/module/search/view/config/config.php @@ -68,5 +68,5 @@
    Version n° - +
    \ No newline at end of file From d9003808228f732ff1ff67993e84892212a49276 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 10:19:12 +0100 Subject: [PATCH 35/61] news erreur de merge --- module/news/news.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/module/news/news.php b/module/news/news.php index 63be7158..93421f44 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -45,9 +45,6 @@ class news extends common { public static $users = []; - const VERSION = '2.0'; - const REALNAME = 'Nouvelles'; - /** * Flux RSS */ From af72107c794788d35138732bcde73adde17fb653 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 12:07:40 +0100 Subject: [PATCH 36/61] addon export WIP (pages missing) --- core/core.php | 32 ++++++++++++++++++++++++++++++++ core/module/addon/addon.php | 11 +++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/core/core.php b/core/core.php index 5d760b11..265abdd0 100755 --- a/core/core.php +++ b/core/core.php @@ -1017,6 +1017,38 @@ class common { return ( rmdir($path) ); } + + /** + * Génère une archive d'un dossier et des sous-dossiers + * @param string fileName path et nom de l'archive + * @param string folder path à zipper + * @param array filter dossiers à exclure + */ + public function makeZip ($fileName, $folder, $filter ) { + $zip = new ZipArchive(); + $zip->open($fileName, ZipArchive::CREATE | ZipArchive::OVERWRITE); + //$directory = 'site/'; + $files = new RecursiveIteratorIterator( + new RecursiveCallbackFilterIterator( + new RecursiveDirectoryIterator( + $folder, + RecursiveDirectoryIterator::SKIP_DOTS + ), + function ($fileInfo, $key, $iterator) use ($filter) { + return $fileInfo->isFile() || !in_array($fileInfo->getBaseName(), $filter); + } + ) + ); + foreach ($files as $name => $file) { + if (!$file->isDir()) { + $filePath = $file->getRealPath(); + $relativePath = substr($filePath, strlen(realpath($folder)) + 1); + $zip->addFile($filePath, $relativePath); + } + } + $zip->close(); + } + /** * Mises à jour */ diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 81067f05..15c35a27 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -322,8 +322,8 @@ class addon extends common { } } // création du zip - $fileName = self::TEMP_DIR . '/' . $this->geturl(2) . 'zip'; - $this->createZip($fileName,$tmpFolder); + $fileName = $this->getUrl(2) . '.zip'; + $this->makeZip ($fileName, $tmpFolder, []); if (file_exists($fileName)) { header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $fileName . '"'); @@ -333,10 +333,9 @@ class addon extends common { $this->addOutput([ 'display' => self::DISPLAY_RAW ]); - //unlink($filename); - //$this->removeDir($tmpFolder); - // Valeurs en sortie - + unlink($fileName); + $this->removeDir($tmpFolder); + exit(); } else { // Valeurs en sortie $this->addOutput([ From 0e4d1ed5704b4bcd73311bc73af1a73c05e8df85 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 12:32:28 +0100 Subject: [PATCH 37/61] datadirectory si erreur de syntaxe --- core/class/helper.class.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 5cc558dc..34332ccd 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -170,7 +170,10 @@ class helper { $delete = true; } // Constante DATADIRECTORY - if (array_key_exists('DATADIRECTORY', $class_constants)) { + if ( array_key_exists('DATADIRECTORY', $class_constants) + && $class_constants['DATADIRECTORY'] !== [] + && is_array($class_constants['DATADIRECTORY']) + ) { $dataDirectory = $value::DATADIRECTORY; } else { $dataDirectory = ['fr/module.json']; From 74f0f60a8a59ce12046300e3a548359881d773bd Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 12:40:41 +0100 Subject: [PATCH 38/61] Effacer createZip --- core/module/addon/addon.php | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 15c35a27..b0f6406a 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -240,37 +240,6 @@ class addon extends common { closedir($dir); } - /* - * Création récursive d'un zip - * https://makitweb.com/how-to-create-and-download-a-zip-file-with-php/ - */ - private function createZip($zip,$dir){ - if (is_dir($dir)){ - if ($dh = opendir($dir)){ - while (($file = readdir($dh)) !== false){ - // If file - if (is_file($dir.$file)) { - if($file != '' && $file != '.' && $file != '..'){ - $zip->addFile($dir.$file); - } - } - else{ - // If directory - if(is_dir($dir.$file) ){ - if($file != '' && $file != '.' && $file != '..'){ - // Add empty directory - $zip->addEmptyDir($dir.$file); - $folder = $dir.$file.'/'; - // Read data of the folder - $this->createZip($zip,$folder); - } - } - } - } - closedir($dh); - } - } - } /* * Export des données d'un module externes ou interne à module.json From 3dcf8f1b960c455e316fb7f93be39d6b5e75840e Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 14:01:44 +0100 Subject: [PATCH 39/61] =?UTF-8?q?export=20ok=20=C3=A0=20tester?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/addon/addon.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index b0f6406a..0c3aa504 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -258,6 +258,8 @@ class addon extends common { // Parcourir les pages utilisant le module foreach (array_keys($inPages,$this->getUrl(2)) as $pageId) { foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $moduleId) { + // Export des pages hébergeant le module + $pageContent[$pageId] = $this->getData(['page',$pageId]); /** * Données module.json ? */ @@ -290,6 +292,10 @@ class addon extends common { } } } + // Enregistrement des pages + if (!file_exists($tmpFolder . '/fr/page.json')) { + file_put_contents($tmpFolder . '/fr/page.json', json_encode($pageContent)); + } // création du zip $fileName = $this->getUrl(2) . '.zip'; $this->makeZip ($fileName, $tmpFolder, []); From 40c862d251ee3a8ed60e59abaea6da8b61f625f2 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 16:54:34 +0100 Subject: [PATCH 40/61] Nom fonction export --- core/module/addon/addon.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 0c3aa504..844294ab 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -21,7 +21,7 @@ class addon extends common { public static $actions = [ 'index' => self::GROUP_ADMIN, 'moduleDelete' => self::GROUP_ADMIN, - 'exportModuleData' => self::GROUP_ADMIN, + 'export' => self::GROUP_ADMIN, ]; // Gestion des modules @@ -98,7 +98,7 @@ class addon extends common { is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) !== '' ? template::button('moduleExport' . $key, [ 'class' => 'buttonBlue', - 'href' => helper::baseUrl(). $this->getUrl(0) . '/exportModuleData/' . $key,// appel de fonction vaut exécution, utiliser un paramètre + 'href' => helper::baseUrl(). $this->getUrl(0) . '/export/' . $key,// appel de fonction vaut exécution, utiliser un paramètre 'value' => template::ico('upload') ]) : '' @@ -244,7 +244,7 @@ class addon extends common { /* * Export des données d'un module externes ou interne à module.json */ - public function exportModuleData(){ + public function export(){ // Lire les données du module $infoModules = helper::getModules(); // Créer un dossier par défaut From ef2aee3f59786be454d460210450cd821876d4fc Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 17:15:13 +0100 Subject: [PATCH 41/61] export ok --- core/module/addon/addon.php | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 844294ab..bc754c95 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -268,34 +268,37 @@ class addon extends common { // Pas de nom dossier de langue - dossier par défaut $t = explode ('/',$moduleId); if ( is_array($t)) { - $path = 'fr'; + $lang = 'fr'; } else { - $path = $t[0]; + $lang = $t[0]; } // Créer le dossier si inexistant - if (!is_dir($tmpFolder . '/' . $path)) { - mkdir ($tmpFolder . '/' . $path); + if (!is_dir($tmpFolder . '/' . $lang)) { + mkdir ($tmpFolder . '/' . $lang); } // Sauvegarde si données non vides $tmpData [$pageId] = $this->getData(['module',$pageId ]); if ($tmpData [$pageId] !== null) { file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData)); } - /** - * Données dans un json personnalisé, le sauvegarder - */ } else { - if (file_exists(self::DATA_DIR . '/' . $moduleId) && - !file_exists($tmpFolder . '/' . $moduleId ) ) { - copy ( self::DATA_DIR . '/' . $moduleId, $tmpFolder . '/' . $moduleId ); + /** + * Données dans un json personnalisé, le sauvegarder + * Dossier non localisé + */ + if ( file_exists(self::DATA_DIR . '/' . $moduleId) + && !file_exists($tmpFolder . '/' . $moduleId ) ) { + copy ( self::DATA_DIR . '/' . $moduleId, $tmpFolder . '/' . $moduleId ); } } } } - // Enregistrement des pages - if (!file_exists($tmpFolder . '/fr/page.json')) { - file_put_contents($tmpFolder . '/fr/page.json', json_encode($pageContent)); + // Enregistrement des pages dans le dossier de langue identique à module + + if (!file_exists($tmpFolder . '/' . $lang . '/page.json')) { + file_put_contents($tmpFolder . '/' . $lang . '/page.json', json_encode($pageContent)); } + // création du zip $fileName = $this->getUrl(2) . '.zip'; $this->makeZip ($fileName, $tmpFolder, []); From 14af9847f61c8aa46f992212633af55932a155c3 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 18 Feb 2021 18:34:53 +0100 Subject: [PATCH 42/61] Import WIP + une correction dans le theme (nom de fonction en double) --- core/module/addon/addon.php | 179 ++++++++++++++--------- core/module/addon/view/import/import.css | 18 +++ core/module/addon/view/import/import.php | 31 ++++ core/module/addon/view/index/index.php | 2 +- core/module/theme/theme.php | 6 +- 5 files changed, 159 insertions(+), 77 deletions(-) create mode 100644 core/module/addon/view/import/import.css create mode 100644 core/module/addon/view/import/import.php diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index bc754c95..e442f178 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -22,6 +22,7 @@ class addon extends common { 'index' => self::GROUP_ADMIN, 'moduleDelete' => self::GROUP_ADMIN, 'export' => self::GROUP_ADMIN, + 'import' => self::GROUP_ADMIN ]; // Gestion des modules @@ -99,6 +100,13 @@ class addon extends common { ? template::button('moduleExport' . $key, [ 'class' => 'buttonBlue', 'href' => helper::baseUrl(). $this->getUrl(0) . '/export/' . $key,// appel de fonction vaut exécution, utiliser un paramètre + 'value' => template::ico('download') + ]) + : '', + is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) !== '' + ? template::button('moduleExport' . $key, [ + 'class' => 'buttonBlue', + 'href' => helper::baseUrl(). $this->getUrl(0) . '/import/' . $key,// appel de fonction vaut exécution, utiliser un paramètre 'value' => template::ico('upload') ]) : '' @@ -245,84 +253,109 @@ class addon extends common { * Export des données d'un module externes ou interne à module.json */ public function export(){ - // Lire les données du module - $infoModules = helper::getModules(); - // Créer un dossier par défaut - $tmpFolder = self::TEMP_DIR . uniqid(); - //$tmpFolder = self::TEMP_DIR . 'test'; - if (!is_dir($tmpFolder)) { - mkdir($tmpFolder); - } - // Clés moduleIds dans les pages - $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); - // Parcourir les pages utilisant le module - foreach (array_keys($inPages,$this->getUrl(2)) as $pageId) { - foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $moduleId) { - // Export des pages hébergeant le module - $pageContent[$pageId] = $this->getData(['page',$pageId]); - /** - * Données module.json ? - */ - if (strpos($moduleId,'module.json')) { - // Création de l'arborescence des langues - // Pas de nom dossier de langue - dossier par défaut - $t = explode ('/',$moduleId); - if ( is_array($t)) { - $lang = 'fr'; - } else { - $lang = $t[0]; - } - // Créer le dossier si inexistant - if (!is_dir($tmpFolder . '/' . $lang)) { - mkdir ($tmpFolder . '/' . $lang); - } - // Sauvegarde si données non vides - $tmpData [$pageId] = $this->getData(['module',$pageId ]); - if ($tmpData [$pageId] !== null) { - file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData)); - } + // Lire les données du module + $infoModules = helper::getModules(); + // Créer un dossier par défaut + $tmpFolder = self::TEMP_DIR . uniqid(); + //$tmpFolder = self::TEMP_DIR . 'test'; + if (!is_dir($tmpFolder)) { + mkdir($tmpFolder); + } + // Clés moduleIds dans les pages + $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); + // Parcourir les pages utilisant le module + foreach (array_keys($inPages,$this->getUrl(2)) as $pageId) { + foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $moduleId) { + // Export des pages hébergeant le module + $pageContent[$pageId] = $this->getData(['page',$pageId]); + /** + * Données module.json ? + */ + if (strpos($moduleId,'module.json')) { + // Création de l'arborescence des langues + // Pas de nom dossier de langue - dossier par défaut + $t = explode ('/',$moduleId); + if ( is_array($t)) { + $lang = 'fr'; } else { - /** - * Données dans un json personnalisé, le sauvegarder - * Dossier non localisé - */ - if ( file_exists(self::DATA_DIR . '/' . $moduleId) - && !file_exists($tmpFolder . '/' . $moduleId ) ) { - copy ( self::DATA_DIR . '/' . $moduleId, $tmpFolder . '/' . $moduleId ); - } + $lang = $t[0]; + } + // Créer le dossier si inexistant + if (!is_dir($tmpFolder . '/' . $lang)) { + mkdir ($tmpFolder . '/' . $lang); + } + // Sauvegarde si données non vides + $tmpData [$pageId] = $this->getData(['module',$pageId ]); + if ($tmpData [$pageId] !== null) { + file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData)); + } + } else { + /** + * Données dans un json personnalisé, le sauvegarder + * Dossier non localisé + */ + if ( file_exists(self::DATA_DIR . '/' . $moduleId) + && !file_exists($tmpFolder . '/' . $moduleId ) ) { + $this->custom_copy ( self::DATA_DIR . '/' . $moduleId, $tmpFolder . '/' . $moduleId ); } } } - // Enregistrement des pages dans le dossier de langue identique à module + } + // Enregistrement des pages dans le dossier de langue identique à module - if (!file_exists($tmpFolder . '/' . $lang . '/page.json')) { - file_put_contents($tmpFolder . '/' . $lang . '/page.json', json_encode($pageContent)); - } - - // création du zip - $fileName = $this->getUrl(2) . '.zip'; - $this->makeZip ($fileName, $tmpFolder, []); - if (file_exists($fileName)) { - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename="' . $fileName . '"'); - header('Content-Length: ' . filesize($fileName)); - readfile( $fileName); - // Valeurs en sortie - $this->addOutput([ - 'display' => self::DISPLAY_RAW - ]); - unlink($fileName); - $this->removeDir($tmpFolder); - exit(); - } else { - // Valeurs en sortie - $this->addOutput([ - 'redirect' => helper::baseUrl() . 'addon', - 'notification' => 'Quelque chose s\'est mal passé', - 'state' => false - ]); - } + if (!file_exists($tmpFolder . '/' . $lang . '/page.json')) { + file_put_contents($tmpFolder . '/' . $lang . '/page.json', json_encode($pageContent)); + } + // création du zip + $fileName = $this->getUrl(2) . '.zip'; + $this->makeZip ($fileName, $tmpFolder, []); + if (file_exists($fileName)) { + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename="' . $fileName . '"'); + header('Content-Length: ' . filesize($fileName)); + readfile( $fileName); + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_RAW + ]); + unlink($fileName); + $this->removeDir($tmpFolder); + exit(); + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'addon', + 'notification' => 'Quelque chose s\'est mal passé', + 'state' => false + ]); + } } -} + /* + * Importer des données d'un module externes ou interne à module.json + */ + public function import(){ + // Soumission du formulaire + if($this->isPost()) { + // Récupérer le fichier et le décompacter + $zipFilename = $this->getInput('addonImportFile', helper::FILTER_STRING_SHORT, true); + $tempFolder = uniqid(); + mkdir (self::TEMP_DIR . $tempFolder); + echo $zipFilename; + $zip = new ZipArchive(); + if ($zip->open(self::FILE_DIR . 'source/' . $zipFilename) === TRUE) { + $zip->extractTo(self::TEMP_DIR . $tempFolder ); + } + + // Supprimer le dossier temporaire même si le thème est invalide + //$this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Importer des données de module', + 'view' => 'import' + ]); + } +} \ No newline at end of file diff --git a/core/module/addon/view/import/import.css b/core/module/addon/view/import/import.css new file mode 100644 index 00000000..5a91e7a7 --- /dev/null +++ b/core/module/addon/view/import/import.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/core/module/addon/view/import/import.php b/core/module/addon/view/import/import.php new file mode 100644 index 00000000..7cc41dac --- /dev/null +++ b/core/module/addon/view/import/import.php @@ -0,0 +1,31 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . 'addon', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
    +
    + 'Appliquer' + ]); ?> +
    +
    +
    +
    +
    +

    Installer des données de module

    +
    +
    + 'Archive ZIP :', + 'type' => 2 + ]); ?> +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/core/module/addon/view/index/index.php b/core/module/addon/view/index/index.php index 56c5bcf1..6da3c716 100644 --- a/core/module/addon/view/index/index.php +++ b/core/module/addon/view/index/index.php @@ -40,7 +40,7 @@ - + diff --git a/core/module/theme/theme.php b/core/module/theme/theme.php index c1441b26..8cb8b382 100755 --- a/core/module/theme/theme.php +++ b/core/module/theme/theme.php @@ -692,7 +692,7 @@ class theme extends common { */ public function export() { // Make zip - $zipFilename = $this->makezip($this->getUrl(2)); + $zipFilename = $this->zipTheme($this->getUrl(2)); // Téléchargement du ZIP header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); @@ -710,7 +710,7 @@ class theme extends common { */ public function save() { // Make zip - $zipFilename = $this->makezip($this->getUrl(2)); + $zipFilename = $this->zipTheme($this->getUrl(2)); // Téléchargement du ZIP if (!is_dir(self::FILE_DIR.'source/theme')) { mkdir(self::FILE_DIR.'source/theme'); @@ -772,7 +772,7 @@ class theme extends common { * construction du zip * @param string $modele theme ou admin */ - private function makezip($modele) { + private function zipTheme($modele) { // Creation du dossier $zipFilename = $modele . ' ' .date('d m Y').' '.date('H i s ').'.zip'; $zip = new ZipArchive(); From 0e002df2af1da836d489a0f377fe6d3affd0884b Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Fri, 19 Feb 2021 07:14:42 +0100 Subject: [PATCH 43/61] =?UTF-8?q?Correction=20dans=20addon=20du=20contr?= =?UTF-8?q?=C3=B4le=20d'update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/addon/addon.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index e442f178..d2a84268 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -11,7 +11,7 @@ * @author Frédéric Tempez * @copyright Copyright (C) 2018-2021, Frédéric Tempez * @author Sylvain Lelièvre -* @copyright Copyright (C) 2020-2021, Sylvain Lelièvre + * @copyright Copyright (C) 2020-2021, Sylvain Lelièvre * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ */ @@ -142,9 +142,10 @@ class addon extends common { // Module normalisé ? if( is_file( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php' ) AND is_file( $moduleDir.'/'.$moduleName.'/view/index/index.php' ) ){ - // Lecture de la version du module pour validation de la mise à jour + // Lecture de la version et de la validation d'update du module pour validation de la mise à jour // Pour une version <= version installée l'utilisateur doit cocher 'Mise à jour forcée' $version = '0.0'; + $update = false; $file = file_get_contents( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php'); $file = str_replace(' ','',$file); $file = str_replace("\t",'',$file); @@ -154,6 +155,15 @@ class addon extends common { $posend = strpos($file, "'", $posdeb + 1); $version = substr($file, $posdeb + 1, $posend - $posdeb - 1); } + $pos1 = strpos($file, 'constUPDATE'); + if( $pos1 !== false){ + $posdeb = strpos($file, "=", $pos1); + $posend = strpos($file, ";", $posdeb + 1); + $strUpdate = substr($file, $posdeb + 1, $posend - $posdeb - 1); + if( strpos( $strUpdate,"true",0) !== false){ + $update = true; + } + } // Module déjà installé ? $moduleInstal = false; @@ -169,7 +179,7 @@ class addon extends common { $valInstalVersion = floatval( $infoModules[$moduleName]['version'] ); $newVersion = false; if( $valNewVersion > $valInstalVersion ) $newVersion = true; - $validMaj = $infoModules[$moduleName]['update'] && ( $newVersion || $checkValidMaj); + $validMaj = $update && ( $newVersion || $checkValidMaj); // Nouvelle installation ou mise à jour du module if( ! $moduleInstal || $validMaj ){ @@ -191,7 +201,7 @@ class addon extends common { else{ $notification = ' Version détectée '.$version.' < à celle installée '.$infoModules[$moduleName]['version']; } - if( $infoModules[$moduleName]['update'] === false){ + if( $update === false){ $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; } } @@ -358,4 +368,4 @@ class addon extends common { 'view' => 'import' ]); } -} \ No newline at end of file +} From f95d8a79611e2b7a7595cdf3f4a059a34a44c485 Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Fri, 19 Feb 2021 07:49:04 +0100 Subject: [PATCH 44/61] addon messages en cas de delete --- core/module/addon/addon.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index d2a84268..b8d5f379 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -47,9 +47,23 @@ class addon extends common { } else{ // Suppression des dossiers - if( $this->removeDir('./module/'.$this->getUrl(2) ) === true){ + $infoModules = helper::getModules(); + $module = $this->getUrl(2); + //Liste des dossiers associés au module non effacés + $list = ''; + foreach( $infoModules[$module]['dataDirectory'] as $moduleId){ + if (strpos($moduleId,'module.json') === false && strpos($moduleId,'page.json') === false) { + $list === '' ? $list = self::DATA_DIR.$moduleId : $list .= ', '.self::DATA_DIR. $moduleId; + } + } + if( $this->removeDir('./module/'.$module ) === true){ $success = true; - $notification = 'Module '.$this->getUrl(2) .' effacé du dossier /module/, il peut rester des données dans d\'autres dossiers'; + if( $list === ''){ + $notification = 'Module '.$module .' désinstallé'; + } + else{ + $notification = 'Module '.$module .' désinstallé, il reste des données dans '.$list; + } } else{ $success = false; From 887ce73f027f53130ed2e1a3ed9d3bef1f9da0fa Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Fri, 19 Feb 2021 07:53:34 +0100 Subject: [PATCH 45/61] correction colonnes tableau addon --- core/module/addon/view/index/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/module/addon/view/index/index.php b/core/module/addon/view/index/index.php index 6da3c716..5248fdc9 100644 --- a/core/module/addon/view/index/index.php +++ b/core/module/addon/view/index/index.php @@ -40,7 +40,7 @@ - + From 95c269873febef0d950ae89feb2536d0c5be1bf6 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Fri, 19 Feb 2021 09:08:56 +0100 Subject: [PATCH 46/61] =?UTF-8?q?Constante=20data=20directory=20par=20d?= =?UTF-8?q?=C3=A9faut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/blog/blog.php | 4 +--- module/form/form.php | 4 +--- module/gallery/gallery.php | 4 +--- module/news/news.php | 4 +--- module/redirection/redirection.php | 4 +--- module/search/search.php | 4 +--- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/module/blog/blog.php b/module/blog/blog.php index 2e7e0538..646e6310 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -18,9 +18,7 @@ class blog extends common { const REALNAME = 'Blog'; const DELETE = true; const UPDATE = true; - const DATADIRECTORY = [ - 'fr/module.json' - ]; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) const EDIT_OWNER = 'owner'; const EDIT_GROUP = 'group'; diff --git a/module/form/form.php b/module/form/form.php index 597a0323..841977e2 100755 --- a/module/form/form.php +++ b/module/form/form.php @@ -20,9 +20,7 @@ class form extends common { const REALNAME = 'Formulaire'; const DELETE = true; const UPDATE = true; - const DATADIRECTORY = [ - 'fr/module.json' - ]; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ 'config' => self::GROUP_MODERATOR, diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index a3bb4618..bc6e4b04 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -21,9 +21,7 @@ class gallery extends common { const REALNAME = 'Galerie'; const DELETE = true; const UPDATE = true; - const DATADIRECTORY = [ - 'fr/module.json' - ]; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) const SORT_ASC = 'SORT_ASC'; const SORT_DSC = 'SORT_DSC'; diff --git a/module/news/news.php b/module/news/news.php index 89eb1aca..ce975f71 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -18,9 +18,7 @@ class news extends common { const REALNAME = 'Actualités'; const DELETE = true; const UPDATE = true; - const DATADIRECTORY = [ - 'fr/module.json' - ]; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ 'add' => self::GROUP_MODERATOR, diff --git a/module/redirection/redirection.php b/module/redirection/redirection.php index e39d70d4..3051ee56 100755 --- a/module/redirection/redirection.php +++ b/module/redirection/redirection.php @@ -18,9 +18,7 @@ class redirection extends common { const REALNAME = 'Redirection'; const DELETE = true; const UPDATE = true; - const DATADIRECTORY = [ - 'fr/module.json' - ]; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ 'config' => self::GROUP_MODERATOR, diff --git a/module/search/search.php b/module/search/search.php index 56e71f05..f07a2200 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -22,9 +22,7 @@ class search extends common { const REALNAME = 'Recherche'; const DELETE = true; const UPDATE = true; - const DATADIRECTORY = [ - 'fr/module.json' - ]; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ 'index' => self::GROUP_VISITOR, From 31d3320f196b9f00d40915335b103b6f99dabd6c Mon Sep 17 00:00:00 2001 From: fredtempez Date: Fri, 19 Feb 2021 16:38:22 +0100 Subject: [PATCH 47/61] =?UTF-8?q?import=20=C3=A0=20tester?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/addon/addon.php | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index b8d5f379..7aac8f98 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -117,7 +117,7 @@ class addon extends common { 'value' => template::ico('download') ]) : '', - is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) !== '' + is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) === '' ? template::button('moduleExport' . $key, [ 'class' => 'buttonBlue', 'href' => helper::baseUrl(). $this->getUrl(0) . '/import/' . $key,// appel de fonction vaut exécution, utiliser un paramètre @@ -366,14 +366,35 @@ class addon extends common { $zipFilename = $this->getInput('addonImportFile', helper::FILTER_STRING_SHORT, true); $tempFolder = uniqid(); mkdir (self::TEMP_DIR . $tempFolder); - echo $zipFilename; $zip = new ZipArchive(); if ($zip->open(self::FILE_DIR . 'source/' . $zipFilename) === TRUE) { $zip->extractTo(self::TEMP_DIR . $tempFolder ); } + // Import des données localisées page.json et module.json + // Pour chaque dossier localisé + $dataTarget = array(); + $dataSource = array(); + foreach (self::$i18nList as $key=>$value) { + // Les Pages et les modules + foreach (['page','module'] as $fileTarget) + if (file_exists(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json')) { + // Le dossier de langue existe + // faire la fusion + $dataSource = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'), true); + $dataTarget = json_decode(file_get_contents(self::DATA_DIR . $key . '/' . $fileTarget . '.json'), true); + $data [$fileTarget] = array_merge($dataTarget[$fileTarget], $dataSource); + file_put_contents(self::DATA_DIR . '/' .$key . '/' . $fileTarget . '.json', json_encode( $data ,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|LOCK_EX) ); + // Supprimer les fichiers importés + unlink (self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'); + rmdir (self::TEMP_DIR . $tempFolder . '/' .$key); + } + } - // Supprimer le dossier temporaire même si le thème est invalide - //$this->removeDir(self::TEMP_DIR . $tempFolder); + // Import des fichiers placés ailleurs que dans les dossiers localisés. + $this->custom_copy (self::TEMP_DIR . $tempFolder,self::DATA_DIR ); + + // Supprimer le dossier temporaire + $this->removeDir(self::TEMP_DIR . $tempFolder); $zip->close(); } // Valeurs en sortie From 20d5c4d2210b4cab28869fb69e3c5b948d38c191 Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Sat, 20 Feb 2021 09:25:22 +0100 Subject: [PATCH 48/61] Modifications helper.class.php, addon.php export import --- core/class/helper.class.php | 4 +- core/module/addon/addon.php | 73 +++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 34332ccd..8701bfa6 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -170,13 +170,13 @@ class helper { $delete = true; } // Constante DATADIRECTORY - if ( array_key_exists('DATADIRECTORY', $class_constants) + if ( array_key_exists('DATADIRECTORY', $class_constants) && $class_constants['DATADIRECTORY'] !== [] && is_array($class_constants['DATADIRECTORY']) ) { $dataDirectory = $value::DATADIRECTORY; } else { - $dataDirectory = ['fr/module.json']; + $dataDirectory = []; } // Affection $modules [$value] = [ diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 7aac8f98..548f1c9b 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -289,40 +289,33 @@ class addon extends common { $inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC'); // Parcourir les pages utilisant le module foreach (array_keys($inPages,$this->getUrl(2)) as $pageId) { + // Export des pages hébergeant le module + $pageContent[$pageId] = $this->getData(['page',$pageId]); + // Export de fr/module.json + $moduleId = 'fr/module.json'; + // Création de l'arborescence des langues + // Pas de nom dossier de langue - dossier par défaut + $t = explode ('/',$moduleId); + if ( is_array($t)) { + $lang = 'fr'; + } else { + $lang = $t[0]; + } + // Créer le dossier si inexistant + if (!is_dir($tmpFolder . '/' . $lang)) { + mkdir ($tmpFolder . '/' . $lang); + } + // Sauvegarde si données non vides + $tmpData [$pageId] = $this->getData(['module',$pageId ]); + if ($tmpData [$pageId] !== null) { + file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData)); + } + // Export des données localisées dans des dossiers foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $moduleId) { - // Export des pages hébergeant le module - $pageContent[$pageId] = $this->getData(['page',$pageId]); - /** - * Données module.json ? - */ - if (strpos($moduleId,'module.json')) { - // Création de l'arborescence des langues - // Pas de nom dossier de langue - dossier par défaut - $t = explode ('/',$moduleId); - if ( is_array($t)) { - $lang = 'fr'; - } else { - $lang = $t[0]; - } - // Créer le dossier si inexistant - if (!is_dir($tmpFolder . '/' . $lang)) { - mkdir ($tmpFolder . '/' . $lang); - } - // Sauvegarde si données non vides - $tmpData [$pageId] = $this->getData(['module',$pageId ]); - if ($tmpData [$pageId] !== null) { - file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData)); - } - } else { - /** - * Données dans un json personnalisé, le sauvegarder - * Dossier non localisé - */ if ( file_exists(self::DATA_DIR . '/' . $moduleId) && !file_exists($tmpFolder . '/' . $moduleId ) ) { $this->custom_copy ( self::DATA_DIR . '/' . $moduleId, $tmpFolder . '/' . $moduleId ); } - } } } // Enregistrement des pages dans le dossier de langue identique à module @@ -376,17 +369,17 @@ class addon extends common { $dataSource = array(); foreach (self::$i18nList as $key=>$value) { // Les Pages et les modules - foreach (['page','module'] as $fileTarget) - if (file_exists(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json')) { - // Le dossier de langue existe - // faire la fusion - $dataSource = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'), true); - $dataTarget = json_decode(file_get_contents(self::DATA_DIR . $key . '/' . $fileTarget . '.json'), true); - $data [$fileTarget] = array_merge($dataTarget[$fileTarget], $dataSource); - file_put_contents(self::DATA_DIR . '/' .$key . '/' . $fileTarget . '.json', json_encode( $data ,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|LOCK_EX) ); - // Supprimer les fichiers importés - unlink (self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'); - rmdir (self::TEMP_DIR . $tempFolder . '/' .$key); + foreach (['page','module'] as $fileTarget){ + if (file_exists(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json')) { + // Le dossier de langue existe + // faire la fusion + $dataSource = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'), true); + $dataTarget = json_decode(file_get_contents(self::DATA_DIR . $key . '/' . $fileTarget . '.json'), true); + $data [$fileTarget] = array_merge($dataTarget[$fileTarget], $dataSource); + file_put_contents(self::DATA_DIR . '/' .$key . '/' . $fileTarget . '.json', json_encode( $data ,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|LOCK_EX) ); + // Supprimer les fichiers importés + unlink (self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'); + } } } From 10ef44aaaf08c3adddc3b12b2d91925d1846420f Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Sat, 20 Feb 2021 16:36:53 +0100 Subject: [PATCH 49/61] =?UTF-8?q?Gestion=20des=20modules=20import=20notifi?= =?UTF-8?q?cation=20si=20pages=20de=20m=C3=AAme=20nom=20dans=20le=20site?= =?UTF-8?q?=20et=20l'archive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/addon/addon.php | 123 +++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 43 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 548f1c9b..8b37821e 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -120,7 +120,7 @@ class addon extends common { is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) === '' ? template::button('moduleExport' . $key, [ 'class' => 'buttonBlue', - 'href' => helper::baseUrl(). $this->getUrl(0) . '/import/' . $key,// appel de fonction vaut exécution, utiliser un paramètre + 'href' => helper::baseUrl(). $this->getUrl(0) . '/import/' . $key.'/' . $_SESSION['csrf'],// appel de fonction vaut exécution, utiliser un paramètre 'value' => template::ico('upload') ]) : '' @@ -311,10 +311,10 @@ class addon extends common { file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData)); } // Export des données localisées dans des dossiers - foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $moduleId) { - if ( file_exists(self::DATA_DIR . '/' . $moduleId) - && !file_exists($tmpFolder . '/' . $moduleId ) ) { - $this->custom_copy ( self::DATA_DIR . '/' . $moduleId, $tmpFolder . '/' . $moduleId ); + foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $dirId) { + if ( file_exists(self::DATA_DIR . '/' . $dirId) + && !file_exists($tmpFolder . '/' . $dirId ) ) { + $this->custom_copy ( self::DATA_DIR . '/' . $dirId, $tmpFolder . '/' . $dirId ); } } } @@ -353,47 +353,84 @@ class addon extends common { * Importer des données d'un module externes ou interne à module.json */ public function import(){ - // Soumission du formulaire - if($this->isPost()) { - // Récupérer le fichier et le décompacter - $zipFilename = $this->getInput('addonImportFile', helper::FILTER_STRING_SHORT, true); - $tempFolder = uniqid(); - mkdir (self::TEMP_DIR . $tempFolder); - $zip = new ZipArchive(); - if ($zip->open(self::FILE_DIR . 'source/' . $zipFilename) === TRUE) { - $zip->extractTo(self::TEMP_DIR . $tempFolder ); - } - // Import des données localisées page.json et module.json - // Pour chaque dossier localisé - $dataTarget = array(); - $dataSource = array(); - foreach (self::$i18nList as $key=>$value) { - // Les Pages et les modules - foreach (['page','module'] as $fileTarget){ - if (file_exists(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json')) { - // Le dossier de langue existe - // faire la fusion - $dataSource = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'), true); - $dataTarget = json_decode(file_get_contents(self::DATA_DIR . $key . '/' . $fileTarget . '.json'), true); - $data [$fileTarget] = array_merge($dataTarget[$fileTarget], $dataSource); - file_put_contents(self::DATA_DIR . '/' .$key . '/' . $fileTarget . '.json', json_encode( $data ,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|LOCK_EX) ); - // Supprimer les fichiers importés - unlink (self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'); + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'addon', + 'state' => false, + 'notification' => 'Action non autorisée' + ]); + } + else{ + // Soumission du formulaire + if($this->isPost()) { + // Récupérer le fichier et le décompacter + $zipFilename = $this->getInput('addonImportFile', helper::FILTER_STRING_SHORT, true); + $tempFolder = uniqid(); + mkdir (self::TEMP_DIR . $tempFolder); + $zip = new ZipArchive(); + if ($zip->open(self::FILE_DIR . 'source/' . $zipFilename) === TRUE) { + $zip->extractTo(self::TEMP_DIR . $tempFolder ); + } + // Import des données localisées page.json et module.json + // Pour chaque dossier localisé + $dataTarget = array(); + $dataSource = array(); + // Liste des pages de même nom dans l'archive et le site + $list = ''; + foreach (self::$i18nList as $key=>$value) { + // Les Pages et les modules + foreach (['page','module'] as $fileTarget){ + if (file_exists(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json')) { + // Le dossier de langue existe + // faire la fusion + $dataSource = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'), true); + // Des pages de même nom que celles de l'archive existent + if( $fileTarget === 'page' ){ + foreach( $dataSource as $keydataSource=>$valuedataSource ){ + foreach( $this->getData(['page']) as $keypage=>$valuepage ){ + if( $keydataSource === $keypage) $list .= ' '.$this->getData(['page', $keypage, 'title']); + } + } + } + $dataTarget = json_decode(file_get_contents(self::DATA_DIR . $key . '/' . $fileTarget . '.json'), true); + $data [$fileTarget] = array_merge($dataTarget[$fileTarget], $dataSource); + if( $list === ''){ + file_put_contents(self::DATA_DIR . '/' .$key . '/' . $fileTarget . '.json', json_encode( $data ,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|LOCK_EX) ); + } + // Supprimer les fichiers importés + unlink (self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'); + } } } + + // Import des fichiers placés ailleurs que dans les dossiers localisés. + $this->custom_copy (self::TEMP_DIR . $tempFolder,self::DATA_DIR ); + + // Supprimer le dossier temporaire + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + if( $list !== '' ){ + $success = false; + $notification = 'Import impossible les pages suivantes doivent être renommées :'.$list; + } + else{ + $success = true; + $notification = 'Import réussi'; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'addon', + 'state' => $success, + 'notification' => $notification + ]); } - - // Import des fichiers placés ailleurs que dans les dossiers localisés. - $this->custom_copy (self::TEMP_DIR . $tempFolder,self::DATA_DIR ); - - // Supprimer le dossier temporaire - $this->removeDir(self::TEMP_DIR . $tempFolder); - $zip->close(); + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Importer des données de module', + 'view' => 'import' + ]); } - // Valeurs en sortie - $this->addOutput([ - 'title' => 'Importer des données de module', - 'view' => 'import' - ]); } } From 3bc9e52c3de359b6020b7af00c251672b56eb05f Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Sun, 21 Feb 2021 08:18:29 +0100 Subject: [PATCH 50/61] Addon modification message import impossible --- core/module/addon/addon.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index 8b37821e..da819d60 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -390,7 +390,9 @@ class addon extends common { if( $fileTarget === 'page' ){ foreach( $dataSource as $keydataSource=>$valuedataSource ){ foreach( $this->getData(['page']) as $keypage=>$valuepage ){ - if( $keydataSource === $keypage) $list .= ' '.$this->getData(['page', $keypage, 'title']); + if( $keydataSource === $keypage){ + $list === '' ? $list .= ' '.$this->getData(['page', $keypage, 'title']) : $list .= ', '.$this->getData(['page', $keypage, 'title']); + } } } } @@ -413,7 +415,7 @@ class addon extends common { $zip->close(); if( $list !== '' ){ $success = false; - $notification = 'Import impossible les pages suivantes doivent être renommées :'.$list; + strpos( $list, ',') === false ? $notification = 'Import impossible la page suivante doit être renommée :'.$list : $notification = 'Import impossible les pages suivantes doivent être renommées :'.$list; } else{ $success = true; From 3fe450e06eb2d4a596cd6a02dc314177732e9652 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 22 Feb 2021 09:43:30 +0100 Subject: [PATCH 51/61] =?UTF-8?q?Mise=20=C3=A0=20jour=20Site=20Map=20Geneg?= =?UTF-8?q?ratoir=204.3.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 4 + README.md | 2 +- core/class/SitemapGenerator.class.php | 540 -------------- core/class/autoload.php | 4 +- core/class/sitemap/FileSystem.class.php | 36 + core/class/sitemap/Runtime.class.php | 36 + core/class/sitemap/SitemapGenerator.class.php | 705 ++++++++++++++++++ core/core.php | 32 +- 8 files changed, 806 insertions(+), 553 deletions(-) delete mode 100755 core/class/SitemapGenerator.class.php create mode 100755 core/class/sitemap/FileSystem.class.php create mode 100755 core/class/sitemap/Runtime.class.php create mode 100755 core/class/sitemap/SitemapGenerator.class.php diff --git a/CHANGES.md b/CHANGES.md index d8eca2fe..3f5379ca 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Changelog +## version 10.4.05 +- Mise à jour : + - SiteMapGenerator 4.3.1 + ## version 10.4.04 - Correction : - Module Blog : balise non fermée dans les commentaires. diff --git a/README.md b/README.md index 7a84065d..54fc703b 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ZwiiCMS 10.4.04 +# ZwiiCMS 10.4.05 Zwii est un CMS sans base de données (flat-file) qui permet de créer et gérer facilement un site web sans aucune connaissance en programmation. diff --git a/core/class/SitemapGenerator.class.php b/core/class/SitemapGenerator.class.php deleted file mode 100755 index f15350d0..00000000 --- a/core/class/SitemapGenerator.class.php +++ /dev/null @@ -1,540 +0,0 @@ -urls = new \SplFixedArray(); - $this->baseURL = $baseURL; - $this->basePath = $basePath; - $this->document = new \DOMDocument("1.0"); - $this->document->preserveWhiteSpace = false; - $this->document->formatOutput = true; - } - - /** - * Use this to add many URL at one time. - * Each inside array can have 1 to 4 fields. - * @param $urlsArray - * @throws \InvalidArgumentException - */ - public function addUrls($urlsArray) - { - if (!is_array($urlsArray)) { - throw new \InvalidArgumentException("Array as argument should be given."); - } - foreach ($urlsArray as $url) { - $this->addUrl( - isset($url[0]) ? $url[0] : null, - isset($url[1]) ? $url[1] : null, - isset($url[2]) ? $url[2] : null, - isset($url[3]) ? $url[3] : null - ); - } - } - - /** - * Use this to add single URL to sitemap. - * @param string $url URL - * @param \DateTime $lastModified When it was modified, use ISO 8601 - * @param string $changeFrequency How often search engines should revisit this URL - * @param string $priority Priority of URL on You site - * @see http://en.wikipedia.org/wiki/ISO_8601 - * @see http://php.net/manual/en/function.date.php - * @throws \InvalidArgumentException - */ - public function addUrl($url, \DateTime $lastModified = null, $changeFrequency = null, $priority = null) - { - if ($url == null) { - throw new \InvalidArgumentException("URL is mandatory. At least one argument should be given."); - } - $urlLength = extension_loaded('mbstring') ? mb_strlen($url) : strlen($url); - if ($urlLength > 2048) { - throw new \InvalidArgumentException( - "URL length can't be bigger than 2048 characters. - Note, that precise url length check is guaranteed only using mb_string extension. - Make sure Your server allow to use mbstring extension." - ); - } - $tmp = new \SplFixedArray(1); - - $tmp[self::URL_PARAM_LOC] = $url; - - if (isset($lastModified)) { - $tmp->setSize(2); - $tmp[self::URL_PARAM_LASTMOD] = $lastModified->format(\DateTime::ATOM); - } - - if (isset($changeFrequency)) { - $tmp->setSize(3); - $tmp[self::URL_PARAM_CHANGEFREQ] = $changeFrequency; - } - - if (isset($priority)) { - $tmp->setSize(4); - $tmp[self::URL_PARAM_PRIORITY] = $priority; - } - - if ($this->urls->getSize() === 0) { - $this->urls->setSize(1); - } else { - if ($this->urls->getSize() === $this->urls->key()) { - $this->urls->setSize($this->urls->getSize() * 2); - } - } - - $this->urls[$this->urls->key()] = $tmp; - $this->urls->next(); - } - - - /** - * @throws \BadMethodCallException - * @throws \InvalidArgumentException - * @throws \LengthException - */ - public function createSitemap() - { - if (!isset($this->urls)) { - throw new \BadMethodCallException("To create sitemap, call addUrl or addUrls function first."); - } - if ($this->maxURLsPerSitemap > self::MAX_URLS_PER_SITEMAP) { - throw new \InvalidArgumentException( - "More than " . self::MAX_URLS_PER_SITEMAP . " URLs per single sitemap is not allowed." - ); - } - $generatorInfo = ''; - - - $sitemapHeader = '' . $generatorInfo . ' - - '; - - $sitemapIndexHeader = '' . $generatorInfo . ' - - '; - - - $nullUrls = 0; - foreach ($this->urls as $url) { - if (is_null($url)) { - $nullUrls++; - } - } - - $nonEmptyUrls = $this->urls->getSize() - $nullUrls; - - $chunks = ceil($nonEmptyUrls / $this->maxURLsPerSitemap); - - for ($chunkCounter = 0; $chunkCounter < $chunks; $chunkCounter++) { - $xml = new \SimpleXMLElement($sitemapHeader); - for ($urlCounter = $chunkCounter * $this->maxURLsPerSitemap; - $urlCounter < ($chunkCounter + 1) * $this->maxURLsPerSitemap && $urlCounter < $nonEmptyUrls; - $urlCounter++ - ) { - $row = $xml->addChild('url'); - - $row->addChild( - 'loc', - htmlspecialchars($this->baseURL . $this->urls[$urlCounter][self::URL_PARAM_LOC], ENT_QUOTES, 'UTF-8') - ); - - if ($this->urls[$urlCounter]->getSize() > 1) { - $row->addChild('lastmod', $this->urls[$urlCounter][self::URL_PARAM_LASTMOD]); - } - if ($this->urls[$urlCounter]->getSize() > 2) { - $row->addChild('changefreq', $this->urls[$urlCounter][self::URL_PARAM_CHANGEFREQ]); - } - if ($this->urls[$urlCounter]->getSize() > 3) { - $row->addChild('priority', $this->urls[$urlCounter][self::URL_PARAM_PRIORITY]); - } - } - if (strlen($xml->asXML()) > self::MAX_FILE_SIZE) { - throw new \LengthException( - "Sitemap size equals to " . strlen($xml->asXML()) - . " bytes is more than 10MB (" . self::MAX_FILE_SIZE . " bytes), - please decrease maxURLsPerSitemap variable." - ); - } - $this->sitemaps[] = $xml->asXML(); - } - if (count($this->sitemaps) > $this->maxSitemaps) { - throw new \LengthException( - "Sitemap index can contain {$this->maxSitemaps} sitemaps. - Perhaps You trying to submit too many maps." - ); - } - if (count($this->sitemaps) > 1) { - for ($i = 0; $i < count($this->sitemaps); $i++) { - $this->sitemaps[$i] = array( - str_replace(".xml", ($i + 1) . ".xml", $this->sitemapFileName), - $this->sitemaps[$i] - ); - } - $xml = new \SimpleXMLElement($sitemapIndexHeader); - foreach ($this->sitemaps as $sitemap) { - $row = $xml->addChild('sitemap'); - $row->addChild('loc', $this->baseURL . "/" . $this->getSitemapFileName(htmlentities($sitemap[0]))); - $row->addChild('lastmod', date('c')); - } - $this->sitemapFullURL = $this->baseURL . "/" . $this->sitemapIndexFileName; - $this->sitemapIndex = array( - $this->sitemapIndexFileName, - $xml->asXML() - ); - } else { - $this->sitemapFullURL = $this->baseURL . "/" . $this->getSitemapFileName(); - - $this->sitemaps[0] = array( - $this->sitemapFileName, - $this->sitemaps[0] - ); - } - } - - - /** - * Returns created sitemaps as array of strings. - * Use it You want to work with sitemap without saving it as files. - * @return array of strings - * @access public - */ - public function toArray() - { - if (isset($this->sitemapIndex)) { - return array_merge(array($this->sitemapIndex), $this->sitemaps); - } else { - return $this->sitemaps; - } - } - - /** - * Will write sitemaps as files. - * @access public - * @throws \BadMethodCallException - */ - public function writeSitemap() - { - if (!isset($this->sitemaps)) { - throw new \BadMethodCallException("To write sitemap, call createSitemap function first."); - } - if (isset($this->sitemapIndex)) { - $this->document->loadXML($this->sitemapIndex[1]); - $this->writeFile($this->document->saveXML(), $this->basePath, $this->sitemapIndex[0], true); - foreach ($this->sitemaps as $sitemap) { - $this->writeFile($sitemap[1], $this->basePath, $sitemap[0]); - } - } else { - $this->document->loadXML($this->sitemaps[0][1]); - $this->writeFile($this->document->saveXML(), $this->basePath, $this->sitemaps[0][0], true); - $this->writeFile($this->sitemaps[0][1], $this->basePath, $this->sitemaps[0][0]); - } - } - - - private function getSitemapFileName($name = null) - { - if (!$name) { - $name = $this->sitemapFileName; - } - if ($this->createGZipFile) { - $name .= ".gz"; - } - return $name; - } - - /** - * Save file. - * @param string $content - * @param string $filePath - * @param string $fileName - * @param bool $noGzip - * @return bool - * @access private - */ - private function writeFile($content, $filePath, $fileName, $noGzip = false) - { - if (!$noGzip && $this->createGZipFile) { - return $this->writeGZipFile($content, $filePath, $fileName); - } - $file = fopen($filePath . $fileName, 'w'); - fwrite($file, $content); - return fclose($file); - } - - /** - * Save GZipped file. - * @param string $content - * @param string $filePath - * @param string $fileName - * @return bool - * @access private - */ - private function writeGZipFile($content, $filePath, $fileName) - { - $fileName .= '.gz'; - $file = gzopen($filePath . $fileName, 'w'); - gzwrite($file, $content); - return gzclose($file); - } - - /** - * If robots.txt file exist, will update information about newly created sitemaps. - * If there is no robots.txt will, create one and put into it information about sitemaps. - * @access public - * @throws \BadMethodCallException - */ - public function updateRobots() - { - if (!isset($this->sitemaps)) { - throw new \BadMethodCallException("To update robots.txt, call createSitemap function first."); - } - $sampleRobotsFile = "User-agent: *\nAllow: /"; - if (file_exists($this->basePath . $this->robotsFileName)) { - $robotsFile = explode("\n", file_get_contents($this->basePath . $this->robotsFileName)); - $robotsFileContent = ""; - foreach ($robotsFile as $key => $value) { - if (substr($value, 0, 8) == 'Sitemap:') { - unset($robotsFile[$key]); - } else { - $robotsFileContent .= $value . "\n"; - } - } - $robotsFileContent .= "Sitemap: $this->sitemapFullURL"; - if (!isset($this->sitemapIndex)) { - $robotsFileContent .= "\nSitemap: " . $this->getSitemapFileName($this->sitemapFullURL); - } - file_put_contents($this->basePath . $this->robotsFileName, $robotsFileContent); - } else { - $sampleRobotsFile = $sampleRobotsFile . "\n\nSitemap: " . $this->sitemapFullURL; - if (!isset($this->sitemapIndex)) { - $sampleRobotsFile .= "\nSitemap: " . $this->getSitemapFileName($this->sitemapFullURL); - } - file_put_contents($this->basePath . $this->robotsFileName, $sampleRobotsFile); - } - } - - /** - * Will inform search engines about newly created sitemaps. - * Google, Ask, Bing and Yahoo will be noticed. - * If You don't pass yahooAppId, Yahoo still will be informed, - * but this method can be used once per day. If You will do this often, - * message that limit was exceeded will be returned from Yahoo. - * @param string $yahooAppId Your site Yahoo appid. - * @return array of messages and http codes from each search engine - * @access public - * @throws \BadMethodCallException - */ - public function submitSitemap($yahooAppId = null) - { - if (!isset($this->sitemaps)) { - throw new \BadMethodCallException("To submit sitemap, call createSitemap function first."); - } - if (!extension_loaded('curl')) { - throw new \BadMethodCallException("cURL library is needed to do submission."); - } - $searchEngines = $this->searchEngines; - $searchEngines[0] = isset($yahooAppId) ? - str_replace("USERID", $yahooAppId, $searchEngines[0][0]) : - $searchEngines[0][1]; - $result = array(); - for ($i = 0; $i < count($searchEngines); $i++) { - $submitSite = curl_init($searchEngines[$i] . htmlspecialchars($this->sitemapFullURL, ENT_QUOTES, 'UTF-8')); - curl_setopt($submitSite, CURLOPT_RETURNTRANSFER, true); - $responseContent = curl_exec($submitSite); - $response = curl_getinfo($submitSite); - $submitSiteShort = array_reverse(explode(".", parse_url($searchEngines[$i], PHP_URL_HOST))); - $result[] = array( - "site" => $submitSiteShort[1] . "." . $submitSiteShort[0], - "fullsite" => $searchEngines[$i] . htmlspecialchars($this->sitemapFullURL, ENT_QUOTES, 'UTF-8'), - "http_code" => $response['http_code'], - "message" => str_replace("\n", " ", strip_tags($responseContent)) - ); - } - return $result; - } - - - /** - * Returns array of URLs - * - * Converts internal SplFixedArray to array - * @return array - */ - public function getUrls() - { - $urls = $this->urls->toArray(); - - /** - * @var int $key - * @var \SplFixedArray $urlSplArr - */ - foreach ($urls as $key => $urlSplArr) { - if (!is_null($urlSplArr)) { - $urlArr = $urlSplArr->toArray(); - $url = []; - foreach ($urlArr as $paramIndex => $paramValue) { - switch ($paramIndex) { - case static::URL_PARAM_LOC: - $url['loc'] = $paramValue; - break; - case static::URL_PARAM_CHANGEFREQ: - $url['changefreq'] = $paramValue; - break; - case static::URL_PARAM_LASTMOD: - $url['lastmod'] = $paramValue; - break; - case static::URL_PARAM_PRIORITY: - $url['priority'] = $paramValue; - break; - default: - break; - } - } - $urls[$key] = $url; - } - } - - return $urls; - } - - public function countUrls() - { - return $this->urls->getSize(); - } -} diff --git a/core/class/autoload.php b/core/class/autoload.php index a9d16ed4..ac507c05 100755 --- a/core/class/autoload.php +++ b/core/class/autoload.php @@ -4,7 +4,9 @@ class autoload { public static function autoloader () { require_once 'core/class/helper.class.php'; require_once 'core/class/template.class.php'; - require_once 'core/class/SitemapGenerator.class.php'; + require_once 'core/class/sitemap/Runtime.class.php'; + require_once 'core/class/sitemap/FileSystem.class.php'; + require_once 'core/class/sitemap/SitemapGenerator.class.php'; require_once 'core/class/phpmailer/PHPMailer.class.php'; require_once 'core/class/phpmailer/Exception.class.php'; require_once 'core/class/phpmailer/SMTP.class.php'; diff --git a/core/class/sitemap/FileSystem.class.php b/core/class/sitemap/FileSystem.class.php new file mode 100755 index 00000000..261102c6 --- /dev/null +++ b/core/class/sitemap/FileSystem.class.php @@ -0,0 +1,36 @@ +\n") + private $sitemapUrlCount = 0; + private $generatedFiles = []; + + /** + * @param string $baseURL You site URL + * @param string $basePath Relative path where sitemap and robots should be stored. + * @param FileSystem|null $fs + * @param Runtime|null $runtime + */ + public function __construct(string $baseURL, string $basePath = "", FileSystem $fs = null, Runtime $runtime = null) + { + $this->urls = []; + $this->baseURL = rtrim($baseURL, '/'); + + if ($fs === null) { + $this->fs = new FileSystem(); + } else { + $this->fs = $fs; + } + + if ($runtime === null) { + $this->runtime = new Runtime(); + } else { + $this->runtime = $runtime; + } + + if ($this->runtime->is_writable($basePath) === false) { + throw new InvalidArgumentException( + sprintf('the provided basePath (%s) should be a writable directory,', $basePath) . + ' please check its existence and permissions' + ); + } + if (strlen($basePath) > 0 && substr($basePath, -1) != DIRECTORY_SEPARATOR) { + $basePath = $basePath . DIRECTORY_SEPARATOR; + } + $this->basePath = $basePath; + + $this->xmlWriter = $this->createXmlWriter(); + $this->flushedSitemapFilenameFormat = sprintf("sm-%%d-%d.xml", time()); + } + + private function createXmlWriter(): XMLWriter + { + $w = new XMLWriter(); + $w->openMemory(); + $w->setIndent(true); + return $w; + } + + /** + * @param string $filename + * @return SitemapGenerator + */ + public function setSitemapFilename(string $filename = ''): SitemapGenerator + { + if (strlen($filename) === 0) { + throw new InvalidArgumentException('sitemap filename should not be empty'); + } + if (pathinfo($filename, PATHINFO_EXTENSION) !== 'xml') { + throw new InvalidArgumentException('sitemap filename should have *.xml extension'); + } + $this->sitemapFileName = $filename; + return $this; + } + + /** + * @param string $filename + * @return $this + */ + public function setSitemapIndexFilename(string $filename = ''): SitemapGenerator + { + if (strlen($filename) === 0) { + throw new InvalidArgumentException('filename should not be empty'); + } + $this->sitemapIndexFileName = $filename; + return $this; + } + + /** + * @param string $filename + * @return $this + */ + public function setRobotsFileName(string $filename): SitemapGenerator + { + if (strlen($filename) === 0) { + throw new InvalidArgumentException('filename should not be empty'); + } + $this->robotsFileName = $filename; + return $this; + } + + /** + * @param int $value + * @return $this + */ + public function setMaxUrlsPerSitemap(int $value): SitemapGenerator + { + if ($value < 1 || self::MAX_URLS_PER_SITEMAP < $value) { + throw new OutOfRangeException( + sprintf('value %d is out of range 1-%d', $value, self::MAX_URLS_PER_SITEMAP) + ); + } + $this->maxUrlsPerSitemap = $value; + return $this; + } + + public function enableCompression(): SitemapGenerator + { + $this->isCompressionEnabled = true; + return $this; + } + + public function disableCompression(): SitemapGenerator + { + $this->isCompressionEnabled = false; + return $this; + } + + public function isCompressionEnabled(): bool + { + return $this->isCompressionEnabled; + } + + public function validate( + string $path, + DateTime $lastModified = null, + string $changeFrequency = null, + float $priority = null, + array $alternates = null, + array $extensions = []) + { + if (!(1 <= mb_strlen($path) && mb_strlen($path) <= self::MAX_URL_LEN)) { + throw new InvalidArgumentException( + sprintf("The urlPath argument length must be between 1 and %d.", self::MAX_URL_LEN) + ); + } + if ($changeFrequency !== null && !in_array($changeFrequency, $this->validChangefreqValues)) { + throw new InvalidArgumentException( + 'The change frequency argument should be one of: %s' . implode(',', $this->validChangefreqValues) + ); + } + if ($priority !== null && !in_array($priority, $this->validPriorities)) { + throw new InvalidArgumentException("Priority argument should be a float number in the range [0.0..1.0]"); + } + if ($extensions !== null && isset($extensions['google_video'])) { + GoogleVideoExtension::validate($this->baseURL . $path, $extensions['google_video']); + } + } + + /** + * Add url components. + * Instead of storing all urls in the memory, the generator will flush sets of added urls + * to the temporary files created on your disk. + * The file format is 'sm-{index}-{timestamp}.xml' + * @param string $path + * @param DateTime|null $lastModified + * @param string|null $changeFrequency + * @param float|null $priority + * @param array|null $alternates + * @param array $extensions + * @return $this + */ + public function addURL( + string $path, + DateTime $lastModified = null, + string $changeFrequency = null, + float $priority = null, + array $alternates = null, + array $extensions = [] + ): SitemapGenerator + { + $this->validate($path, $lastModified, $changeFrequency, $priority, $alternates, $extensions); + + if ($this->totalUrlCount >= self::TOTAL_MAX_URLS) { + throw new OutOfRangeException( + sprintf("Max url limit reached (%d)", self::TOTAL_MAX_URLS) + ); + } + if ($this->isSitemapStarted === false) { + $this->writeSitemapStart(); + } + + $this->writeSitemapUrl($this->baseURL . $path, $lastModified, $changeFrequency, $priority, $alternates, $extensions); + + if ($this->totalUrlCount % 1000 === 0 || $this->sitemapUrlCount >= $this->maxUrlsPerSitemap) { + $this->flushWriter(); + } + + if ($this->sitemapUrlCount === $this->maxUrlsPerSitemap) { + $this->writeSitemapEnd(); + } + + return $this; + } + + private function writeSitemapStart() + { + $this->xmlWriter->startDocument("1.0", "UTF-8"); + $this->xmlWriter->writeComment(sprintf('generator-class="%s"', get_class($this))); + $this->xmlWriter->writeComment(sprintf('generator-version="%s"', $this->classVersion)); + $this->xmlWriter->writeComment(sprintf('generated-on="%s"', date('c'))); + $this->xmlWriter->startElement('urlset'); + $this->xmlWriter->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); + $this->xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); + $this->xmlWriter->writeAttribute('xmlns:video', 'http://www.google.com/schemas/sitemap-video/1.1'); + $this->xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $this->xmlWriter->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'); + $this->isSitemapStarted = true; + } + + private function writeSitemapUrl($loc, $lastModified, $changeFrequency, $priority, $alternates, $extensions) + { + $this->xmlWriter->startElement('url'); + $this->xmlWriter->writeElement('loc', htmlspecialchars($loc, ENT_QUOTES)); + + if ($lastModified !== null) { + $this->xmlWriter->writeElement('lastmod', $lastModified->format(DateTime::ATOM)); + } + + if ($changeFrequency !== null) { + $this->xmlWriter->writeElement('changefreq', $changeFrequency); + } + + if ($priority !== null) { + $this->xmlWriter->writeElement('priority', number_format($priority, 1, ".", "")); + } + + if (is_array($alternates) && count($alternates) > 0) { + foreach ($alternates as $alternate) { + if (is_array($alternate) && isset($alternate['hreflang']) && isset($alternate['href'])) { + $this->xmlWriter->startElement('xhtml:link'); + $this->xmlWriter->writeAttribute('rel', 'alternate'); + $this->xmlWriter->writeAttribute('hreflang', $alternate['hreflang']); + $this->xmlWriter->writeAttribute('href', $alternate['href']); + $this->xmlWriter->endElement(); + } + } + } + + foreach ($extensions as $extName => $extFields) { + if ($extName === 'google_video') { + GoogleVideoExtension::writeVideoTag($this->xmlWriter, $loc, $extFields); + } + } + + $this->xmlWriter->endElement(); // url + $this->sitemapUrlCount++; + $this->totalUrlCount++; + } + + private function flushWriter() + { + $targetSitemapFilepath = $this->basePath . sprintf($this->flushedSitemapFilenameFormat, $this->flushedSitemapCounter); + $flushedString = $this->xmlWriter->outputMemory(true); + $flushedStringLen = mb_strlen($flushedString); + + if ($flushedStringLen === 0) { + return; + } + + $this->flushedSitemapSize += $flushedStringLen; + + if ($this->flushedSitemapSize > self::MAX_FILE_SIZE - $this->urlsetClosingTagLen) { + $this->writeSitemapEnd(); + $this->writeSitemapStart(); + } + $this->fs->file_put_contents($targetSitemapFilepath, $flushedString, FILE_APPEND); + } + + private function writeSitemapEnd() + { + $targetSitemapFilepath = $this->basePath . sprintf($this->flushedSitemapFilenameFormat, $this->flushedSitemapCounter); + $this->xmlWriter->endElement(); // urlset + $this->xmlWriter->endDocument(); + $this->fs->file_put_contents($targetSitemapFilepath, $this->xmlWriter->flush(true), FILE_APPEND); + $this->isSitemapStarted = false; + $this->flushedSitemaps[] = $targetSitemapFilepath; + $this->flushedSitemapCounter++; + $this->sitemapUrlCount = 0; + } + + /** + * Flush all stored urls from memory to the disk and close all necessary tags. + */ + public function flush() + { + $this->flushWriter(); + if ($this->isSitemapStarted) { + $this->writeSitemapEnd(); + } + } + + /** + * Move flushed files to their final location. Compress if necessary. + */ + public function finalize() + { + $this->generatedFiles = []; + + if (count($this->flushedSitemaps) === 1) { + $targetSitemapFilename = $this->sitemapFileName; + if ($this->isCompressionEnabled) { + $targetSitemapFilename .= '.gz'; + } + + $targetSitemapFilepath = $this->basePath . $targetSitemapFilename; + + if ($this->isCompressionEnabled) { + $this->fs->copy($this->flushedSitemaps[0], 'compress.zlib://' . $targetSitemapFilepath); + $this->fs->unlink($this->flushedSitemaps[0]); + } else { + $this->fs->rename($this->flushedSitemaps[0], $targetSitemapFilepath); + } + $this->generatedFiles['sitemaps_location'] = [$targetSitemapFilepath]; + $this->generatedFiles['sitemaps_index_url'] = $this->baseURL . '/' . $targetSitemapFilename; + } else if (count($this->flushedSitemaps) > 1) { + $ext = '.' . pathinfo($this->sitemapFileName, PATHINFO_EXTENSION); + $targetExt = $ext; + if ($this->isCompressionEnabled) { + $targetExt .= '.gz'; + } + + $sitemapsUrls = []; + $targetSitemapFilepaths = []; + foreach ($this->flushedSitemaps as $i => $flushedSitemap) { + $targetSitemapFilename = str_replace($ext, ($i + 1) . $targetExt, $this->sitemapFileName); + $targetSitemapFilepath = $this->basePath . $targetSitemapFilename; + + if ($this->isCompressionEnabled) { + $this->fs->copy($flushedSitemap, 'compress.zlib://' . $targetSitemapFilepath); + $this->fs->unlink($flushedSitemap); + } else { + $this->fs->rename($flushedSitemap, $targetSitemapFilepath); + } + $sitemapsUrls[] = htmlspecialchars($this->baseURL . '/' . $targetSitemapFilename, ENT_QUOTES); + $targetSitemapFilepaths[] = $targetSitemapFilepath; + } + + $targetSitemapIndexFilepath = $this->basePath . $this->sitemapIndexFileName; + $this->createSitemapIndex($sitemapsUrls, $targetSitemapIndexFilepath); + $this->generatedFiles['sitemaps_location'] = $targetSitemapFilepaths; + $this->generatedFiles['sitemaps_index_location'] = $targetSitemapIndexFilepath; + $this->generatedFiles['sitemaps_index_url'] = $this->baseURL . '/' . $this->sitemapIndexFileName; + } else { + throw new RuntimeException('failed to finalize, please add urls and flush first'); + } + } + + private function createSitemapIndex($sitemapsUrls, $sitemapIndexFileName) + { + $this->xmlWriter->flush(true); + $this->writeSitemapIndexStart(); + foreach ($sitemapsUrls as $sitemapsUrl) { + $this->writeSitemapIndexUrl($sitemapsUrl); + } + $this->writeSitemapIndexEnd(); + $this->fs->file_put_contents( + $sitemapIndexFileName, + $this->xmlWriter->flush(true), + FILE_APPEND + ); + } + + private function writeSitemapIndexStart() + { + $this->xmlWriter->startDocument("1.0", "UTF-8"); + $this->xmlWriter->writeComment(sprintf('generator-class="%s"', get_class($this))); + $this->xmlWriter->writeComment(sprintf('generator-version="%s"', $this->classVersion)); + $this->xmlWriter->writeComment(sprintf('generated-on="%s"', date('c'))); + $this->xmlWriter->startElement('sitemapindex'); + $this->xmlWriter->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); + $this->xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $this->xmlWriter->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'); + } + + private function writeSitemapIndexUrl($url) + { + $this->xmlWriter->startElement('sitemap'); + $this->xmlWriter->writeElement('loc', htmlspecialchars($url, ENT_QUOTES)); + $this->xmlWriter->writeElement('lastmod', date('c')); + $this->xmlWriter->endElement(); // sitemap + } + + private function writeSitemapIndexEnd() + { + $this->xmlWriter->endElement(); // sitemapindex + $this->xmlWriter->endDocument(); + } + + /** + * @return array Array of previously generated files + */ + public function getGeneratedFiles(): array + { + return $this->generatedFiles; + } + + /** + * Will inform search engines about newly created sitemaps. + * Google, Ask, Bing and Yahoo will be noticed. + * If You don't pass yahooAppId, Yahoo still will be informed, + * but this method can be used once per day. If You will do this often, + * message that limit was exceeded will be returned from Yahoo. + * @param string $yahooAppId Your site Yahoo appid. + * @return array of messages and http codes from each search engine + * @access public + * @throws BadMethodCallException + */ + public function submitSitemap($yahooAppId = null): array + { + if (count($this->generatedFiles) === 0) { + throw new BadMethodCallException("To update robots.txt, call finalize() first."); + } + if (!$this->runtime->extension_loaded('curl')) { + throw new BadMethodCallException("cURL extension is needed to do submission."); + } + $searchEngines = $this->searchEngines; + $searchEngines[0] = isset($yahooAppId) ? + str_replace("USERID", $yahooAppId, $searchEngines[0][0]) : + $searchEngines[0][1]; + $result = []; + for ($i = 0; $i < count($searchEngines); $i++) { + $submitUrl = $searchEngines[$i] . htmlspecialchars($this->generatedFiles['sitemaps_index_url'], ENT_QUOTES); + $submitSite = $this->runtime->curl_init($submitUrl); + $this->runtime->curl_setopt($submitSite, CURLOPT_RETURNTRANSFER, true); + $responseContent = $this->runtime->curl_exec($submitSite); + $response = $this->runtime->curl_getinfo($submitSite); + $submitSiteShort = array_reverse(explode(".", parse_url($searchEngines[$i], PHP_URL_HOST))); + $result[] = [ + "site" => $submitSiteShort[1] . "." . $submitSiteShort[0], + "fullsite" => $submitUrl, + "http_code" => $response['http_code'], + "message" => str_replace("\n", " ", strip_tags($responseContent)), + ]; + } + return $result; + } + + /** + * Adds sitemap url to robots.txt file located in basePath. + * If robots.txt file exists, + * the function will append sitemap url to file. + * If robots.txt does not exist, + * the function will create new robots.txt file with sample content and sitemap url. + * @access public + * @throws BadMethodCallException + * @throws RuntimeException + */ + public function updateRobots(): SitemapGenerator + { + if (count($this->generatedFiles) === 0) { + throw new BadMethodCallException("To update robots.txt, call finalize() first."); + } + + $robotsFilePath = $this->basePath . $this->robotsFileName; + + $robotsFileContent = $this->createNewRobotsContentFromFile($robotsFilePath); + + $this->fs->file_put_contents($robotsFilePath, $robotsFileContent); + + return $this; + } + + /** + * @param $filepath + * @return string + */ + private function createNewRobotsContentFromFile($filepath): string + { + if ($this->fs->file_exists($filepath)) { + $robotsFileContent = ""; + $robotsFile = explode(PHP_EOL, $this->fs->file_get_contents($filepath)); + foreach ($robotsFile as $key => $value) { + if (substr($value, 0, 8) == 'Sitemap:') { + unset($robotsFile[$key]); + } else { + $robotsFileContent .= $value . PHP_EOL; + } + } + } else { + $robotsFileContent = $this->getSampleRobotsContent(); + } + + $robotsFileContent .= "Sitemap: {$this->generatedFiles['sitemaps_index_url']}"; + + return $robotsFileContent; + } + + /** + * @return string + * @access private + */ + private function getSampleRobotsContent(): string + { + return implode(PHP_EOL, $this->sampleRobotsLines) . PHP_EOL; + } +} diff --git a/core/core.php b/core/core.php index 66b8fbdc..cc5953d6 100755 --- a/core/core.php +++ b/core/core.php @@ -44,7 +44,7 @@ class common { const ACCESS_TIMER = 1800; // Numéro de version - const ZWII_VERSION = '10.4.04'; + const ZWII_VERSION = '10.4.05'; const ZWII_UPDATE_CHANNEL = "v10"; public static $actions = []; @@ -740,22 +740,26 @@ class common { $timezone = $this->getData(['config','timezone']); - $sitemap = new \Icamys\SitemapGenerator\SitemapGenerator(helper::baseurl()); + $outputDir = getcwd(); + + $sitemap = new \Icamys\SitemapGenerator\SitemapGenerator(helper::baseurl(false),$outputDir); // will create also compressed (gzipped) sitemap - $sitemap->createGZipFile = true; + $sitemap->enableCompression(); // determine how many urls should be put into one file // according to standard protocol 50000 is maximum value (see http://www.sitemaps.org/protocol.html) - $sitemap->maxURLsPerSitemap = 50000; + $sitemap->setMaxUrlsPerSitemap(50000); // sitemap file name - $sitemap->sitemapFileName = "sitemap.xml"; + $sitemap->setSitemapFileName("sitemap.xml"); + + // Set the sitemap index file name + $sitemap->setSitemapIndexFileName("sitemap-index.xml"); $datetime = new DateTime(date('c')); $datetime->format(DateTime::ATOM); // Updated ISO8601 - // sitemap index file name - $sitemap->sitemapIndexFileName = "sitemap-index.xml"; + foreach($this->getHierarchy(null, null, null) as $parentPageId => $childrenPageIds) { // Exclure les barres et les pages non publiques et les pages masquées if ($this->getData(['page',$parentPageId,'group']) !== 0 || @@ -797,11 +801,17 @@ class common { } - // generating internally a sitemap - $sitemap->createSitemap(); + // Flush all stored urls from memory to the disk and close all necessary tags. + $sitemap->flush(); - // writing early generated sitemap to file - $sitemap->writeSitemap(); + // Move flushed files to their final location. Compress if the option is enabled. + $sitemap->finalize(); + + // Update robots.txt file in output directory or create a new one + $sitemap->updateRobots(); + + // Submit your sitemaps to Google, Yahoo, Bing and Ask.com + $sitemap->submitSitemap(); return(file_exists('sitemap.xml')); From c48bb166551dfe42dd1bc5292099a17cefb17622 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 22 Feb 2021 09:54:52 +0100 Subject: [PATCH 52/61] =?UTF-8?q?zindex=20bouton=20de=20remont=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/layout/common.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/layout/common.css b/core/layout/common.css index 3a7f49da..9ca3abfa 100755 --- a/core/layout/common.css +++ b/core/layout/common.css @@ -960,7 +960,7 @@ footer #footerSocials .zwiico-github:hover { /* Remonter en haut */ #backToTop { position: fixed; - z-index: 30; + z-index: 50; right: 30px; bottom: 50px; padding: 13px 16px 16px; From 22bd4aa037abcdf1dc1309142308bb59550841ec Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 22 Feb 2021 09:56:57 +0100 Subject: [PATCH 53/61] backtotop plus haut --- core/layout/common.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/layout/common.css b/core/layout/common.css index 9ca3abfa..3f2ee721 100755 --- a/core/layout/common.css +++ b/core/layout/common.css @@ -962,7 +962,7 @@ footer #footerSocials .zwiico-github:hover { position: fixed; z-index: 50; right: 30px; - bottom: 50px; + bottom: 100px; padding: 13px 16px 16px; /* Paramétré dans le thème (9.2.21) From c10ad5d5dac6b8074610c66ae7db1a3c336a7dd6 Mon Sep 17 00:00:00 2001 From: SylvainLelievre Date: Thu, 25 Feb 2021 07:53:57 +0100 Subject: [PATCH 54/61] Modification de la constante UPDATE --- core/class/helper.class.php | 2 +- core/module/addon/addon.php | 25 +++++++++++++++---------- module/blog/blog.php | 3 +-- module/form/form.php | 4 ++-- module/gallery/gallery.php | 4 ++-- module/news/news.php | 4 ++-- module/redirection/redirection.php | 4 ++-- module/search/search.php | 2 +- 8 files changed, 26 insertions(+), 22 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 8701bfa6..503ea941 100755 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -161,7 +161,7 @@ class helper { if (array_key_exists('UPDATE', $class_constants)) { $update = $value::UPDATE; } else { - $update = true; + $update = '0.0'; } // Constante DELETE if (array_key_exists('DELETE', $class_constants)) { diff --git a/core/module/addon/addon.php b/core/module/addon/addon.php index da819d60..a1521575 100644 --- a/core/module/addon/addon.php +++ b/core/module/addon/addon.php @@ -159,7 +159,8 @@ class addon extends common { // Lecture de la version et de la validation d'update du module pour validation de la mise à jour // Pour une version <= version installée l'utilisateur doit cocher 'Mise à jour forcée' $version = '0.0'; - $update = false; + $update = '0.0'; + $valUpdate = false; $file = file_get_contents( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php'); $file = str_replace(' ','',$file); $file = str_replace("\t",'',$file); @@ -171,13 +172,12 @@ class addon extends common { } $pos1 = strpos($file, 'constUPDATE'); if( $pos1 !== false){ - $posdeb = strpos($file, "=", $pos1); - $posend = strpos($file, ";", $posdeb + 1); - $strUpdate = substr($file, $posdeb + 1, $posend - $posdeb - 1); - if( strpos( $strUpdate,"true",0) !== false){ - $update = true; - } + $posdeb = strpos($file, "'", $pos1); + $posend = strpos($file, "'", $posdeb + 1); + $update = substr($file, $posdeb + 1, $posend - $posdeb - 1); } + // Si version actuelle >= version indiquée dans UPDATE la mise à jour est validée + if( $infoModules[$moduleName]['update'] >= $update ) $valUpdate = true; // Module déjà installé ? $moduleInstal = false; @@ -193,7 +193,7 @@ class addon extends common { $valInstalVersion = floatval( $infoModules[$moduleName]['version'] ); $newVersion = false; if( $valNewVersion > $valInstalVersion ) $newVersion = true; - $validMaj = $update && ( $newVersion || $checkValidMaj); + $validMaj = $valUpdate && ( $newVersion || $checkValidMaj); // Nouvelle installation ou mise à jour du module if( ! $moduleInstal || $validMaj ){ @@ -215,8 +215,13 @@ class addon extends common { else{ $notification = ' Version détectée '.$version.' < à celle installée '.$infoModules[$moduleName]['version']; } - if( $update === false){ - $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; + if( $valUpdate === false){ + if( $infoModules[$moduleName]['update'] === $update ){ + $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; + } + else{ + $notification = ' Mise à jour par ce procédé interdite, votre version est trop ancienne'; + } } } } diff --git a/module/blog/blog.php b/module/blog/blog.php index a7cbe478..560086b3 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -18,7 +18,7 @@ class blog extends common { const VERSION = '4.4'; const REALNAME = 'Blog'; const DELETE = true; - const UPDATE = true; + const UPDATE = '0.0'; const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) const EDIT_OWNER = 'owner'; @@ -763,4 +763,3 @@ class blog extends common { } } } - diff --git a/module/form/form.php b/module/form/form.php index 21daf0bc..77d416d8 100755 --- a/module/form/form.php +++ b/module/form/form.php @@ -19,7 +19,7 @@ class form extends common { const VERSION = '2.8'; const REALNAME = 'Formulaire'; const DELETE = true; - const UPDATE = true; + const UPDATE = '0.0'; const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ @@ -290,7 +290,7 @@ class form extends common { if( $this->getData(['module', $this->getUrl(0), 'config', 'captcha']) // AND $this->getInput('formcaptcha', helper::FILTER_INT) !== $this->getInput('formcaptchaFirstNumber', helper::FILTER_INT) + $this->getInput('formcaptchaSecondNumber', helper::FILTER_INT)) - AND password_verify($this->getInput('formCaptcha', helper::FILTER_INT), $this->getInput('formCaptchaResult') ) === false ) + AND password_verify($this->getInput('formCaptcha', helper::FILTER_INT), $this->getInput('formCaptchaResult') ) === false ) { self::$inputNotices['formCaptcha'] = 'Incorrect'; diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 53c2b091..9434387f 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -20,7 +20,7 @@ class gallery extends common { const VERSION = '2.6'; const REALNAME = 'Galerie'; const DELETE = true; - const UPDATE = true; + const UPDATE = '0.0'; const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) const SORT_ASC = 'SORT_ASC'; @@ -698,4 +698,4 @@ class galleriesHelper extends helper { } return $dirContent; } -} \ No newline at end of file +} diff --git a/module/news/news.php b/module/news/news.php index f0685aab..6675ec37 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -18,7 +18,7 @@ class news extends common { const VERSION = '2.1'; const REALNAME = 'Actualités'; const DELETE = true; - const UPDATE = true; + const UPDATE = '0.0'; const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ @@ -334,4 +334,4 @@ class news extends common { return $this->getData(['user', $userId, 'firstname']); } } -} \ No newline at end of file +} diff --git a/module/redirection/redirection.php b/module/redirection/redirection.php index 58c4e1b7..0d1a704d 100755 --- a/module/redirection/redirection.php +++ b/module/redirection/redirection.php @@ -18,7 +18,7 @@ class redirection extends common { const VERSION = '1.5'; const REALNAME = 'Redirection'; const DELETE = true; - const UPDATE = true; + const UPDATE = '0.0'; const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ @@ -76,4 +76,4 @@ class redirection extends common { ]); } } -} \ No newline at end of file +} diff --git a/module/search/search.php b/module/search/search.php index 894df277..ed9a5815 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -21,7 +21,7 @@ class search extends common { const VERSION = '1.3'; const REALNAME = 'Recherche'; const DELETE = true; - const UPDATE = true; + const UPDATE = '0.0'; const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ From 21c70e7eab02135212c67e2ae9078f1a1bf1c3e2 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Thu, 25 Feb 2021 21:19:27 +0100 Subject: [PATCH 55/61] Test footer fixe marges --- CHANGES.md | 7 +++++-- core/core.php | 7 ++++--- core/layout/common.css | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3f5379ca..18e3d849 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,11 +3,14 @@ ## version 10.4.05 - Mise à jour : - SiteMapGenerator 4.3.1 +- Modifications : + - Bouton de remontée, position plus haute et zindex augmenté. + - Éviter le chevauchement du pied de age fixe au-dessus du corps de page. ## version 10.4.04 - Correction : - Module Blog : balise non fermée dans les commentaires. -- Modifications : +- Modifications : -Constantes de modules. ## version 10.4.03 @@ -23,7 +26,7 @@ - Thème : rétablissement du contrôle de l'import d'une version ancienne d'un thème. - Éditeur de texte : couleur de fond parasite quand une image en arrière-plan est sélectionnée. -## version 10.4.01 +## version 10.4.01 Corrections : - Module form, erreur de syntaxe. - Chargement d'un thème, désactivation du contrôle des clés. diff --git a/core/core.php b/core/core.php index cc5953d6..1e241bc4 100755 --- a/core/core.php +++ b/core/core.php @@ -1784,7 +1784,8 @@ class core extends common { $css .= 'footer a{color:' . $this->getData(['theme', 'footer', 'textColor']) . '}'; $css .= 'footer #footersite > div {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}'; - $css .= 'footer #footerbody > div {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}'; + $css .= 'footer #footerbody {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}'; + $css .= '@media (max-width: 768px) {footer #footerbody > div { padding: 2px }}'; $css .= '#footerSocials{text-align:' . $this->getData(['theme', 'footer', 'socialsAlign']) . '}'; $css .= '#footerText > p {text-align:' . $this->getData(['theme', 'footer', 'textAlign']) . '}'; $css .= '#footerCopyright{text-align:' . $this->getData(['theme', 'footer', 'copyrightAlign']) . '}'; @@ -1792,8 +1793,8 @@ class core extends common { // Marge supplémentaire lorsque le pied de page est fixe if ( $this->getData(['theme', 'footer', 'fixed']) === true && $this->getData(['theme', 'footer', 'position']) === 'body') { - $css .= "@media (min-width: 769px) { #site {margin-bottom: 100px;} }"; - $css .= "@media (max-width: 768px) { #site {margin-bottom: 150px;} }"; + $css .= '@media (min-width: 769px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 31 ) . 'px}}'; + $css .= '@media (max-width: 768px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 93 ) . 'px}}'; } // Enregistre la personnalisation diff --git a/core/layout/common.css b/core/layout/common.css index 3f2ee721..0afcdc1c 100755 --- a/core/layout/common.css +++ b/core/layout/common.css @@ -46,7 +46,7 @@ body { } #site { - margin: 0px auto; + /*margin: 0px auto;*/ } body>header { From 606c67ae7e9bf34fae3c5ae47e27f768fe40f33d Mon Sep 17 00:00:00 2001 From: fredtempez Date: Fri, 26 Feb 2021 09:59:58 +0100 Subject: [PATCH 56/61] Aide page de config --- core/module/config/view/index/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/module/config/view/index/index.php b/core/module/config/view/index/index.php index 42b8b8ae..f7c50a18 100755 --- a/core/module/config/view/index/index.php +++ b/core/module/config/view/index/index.php @@ -90,7 +90,7 @@ 'Aucune'] , helper::arrayCollumn($pages, 'title', 'SORT_ASC') ) , [ 'label' => 'Recherche dans le site', 'selected' => $this->getData(['locale', 'searchPageId']), - 'help' => 'Sélectionner la page "Recherche" ou une page contenant le module "Recherche" permet d\'activer un lien dans le pied de page. ' + 'help' => 'Sélectionner la page "Recherche" ou une page contenant le module "Recherche". Une option du pied de page ajoute un lien discret vers cette page.' ]); ?> From 96a6b9ff27043cb658277bdb741eeab679f88769 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Fri, 26 Feb 2021 21:04:44 +0100 Subject: [PATCH 57/61] Ajustement des marges footer --- core/core.php | 30 +++++++++++++++++++----------- core/layout/common.css | 9 +++++---- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/core/core.php b/core/core.php index 1e241bc4..f46f1e49 100755 --- a/core/core.php +++ b/core/core.php @@ -1691,8 +1691,23 @@ class core extends common { //$css .= '.button.buttonGrey,.button.buttonGrey:hover{color:' . $this->getData(['theme', 'text', 'textColor']) . '}'; $css .= '.container{max-width:' . $this->getData(['theme', 'site', 'width']) . '}'; $margin = $this->getData(['theme', 'site', 'margin']) ? '0' : '20px'; - $css .= $this->getData(['theme', 'site', 'width']) === '100%' ? '#site.light{margin:5% auto !important;}#site{margin:0 auto !important;} body{margin:0 auto !important;} #bar{margin:0 auto !important;} body > header{margin:0 auto !important;} body > nav {margin: 0 auto !important;} body > footer {margin:0 auto !important;}': "#site.light{margin: 5% auto !important;}#site{margin: " . $margin . " auto !important;} body{margin:0px 10px;} #bar{margin: 0 -10px;} body > header{margin: 0 -10px;} body > nav {margin: 0 -10px;} body > footer {margin: 0 -10px;} "; - $css .= $this->getData(['theme', 'site', 'width']) === '750px' ? '.button, button{font-size:0.8em;}' : ''; + // Marge supplémentaire lorsque le pied de page est fixe + if ( $this->getData(['theme', 'footer', 'fixed']) === true && + $this->getData(['theme', 'footer', 'position']) === 'body') { + //$css .= '@media (min-width: 769px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 31 ) . 'px}}'; + //$css .= '@media (max-width: 768px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 93 ) . 'px}}'; + $marginBottomLarge = ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 31 ) . 'px'; + $marginBottomSmall = ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 93 ) . 'px'; + } else { + $marginBottomSmall = $margin; + $marginBottomLarge = $margin; + } + $css .= $this->getData(['theme', 'site', 'width']) === '100%' + ? '@media (min-width: 769px) {#site{margin:0 auto 0 ' . $marginBottomLarge . ' !important;}}@media (max-width: 768px) {#site{margin:0 auto 0 ' . $marginBottomSmall . ' !important;}}#site.light{margin:5% auto !important;} body{margin:0 auto !important;} #bar{margin:0 auto !important;} body > header{margin:0 auto !important;} body > nav {margin: 0 auto !important;} body > footer {margin:0 auto !important;}' + : '@media (min-width: 769px) {#site{margin: ' . $margin . ' auto ' . $marginBottomLarge . ' auto !important;}}@media (max-width: 768px) {#site{margin: ' . $margin . ' auto ' . $marginBottomSmall . ' auto !important;}}#site.light{margin: 5% auto !important;} body{margin:0px 10px;} #bar{margin: 0 -10px;} body > header{margin: 0 -10px;} body > nav {margin: 0 -10px;} body > footer {margin: 0 -10px;} '; + $css .= $this->getData(['theme', 'site', 'width']) === '750px' + ? '.button, button{font-size:0.8em;}' + : ''; $css .= '#site{background-color:' . $this->getData(['theme', 'site', 'backgroundColor']) . ';border-radius:' . $this->getData(['theme', 'site', 'radius']) . ';box-shadow:' . $this->getData(['theme', 'site', 'shadow']) . ' #212223;}'; $colors = helper::colorVariants($this->getData(['theme', 'button', 'backgroundColor'])); $css .= '.speechBubble,.button,.button:hover,button[type=\'submit\'],.pagination a,.pagination a:hover,input[type=\'checkbox\']:checked + label:before,input[type=\'radio\']:checked + label:before,.helpContent{background-color:' . $colors['normal'] . ';color:' . $colors['text'] . '}'; @@ -1780,23 +1795,16 @@ class core extends common { } $css .= 'footer span, #footerText > p {color:' . $this->getData(['theme', 'footer', 'textColor']) . ';font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'footer', 'font'])) . '",sans-serif;font-weight:' . $this->getData(['theme', 'footer', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'footer', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'footer', 'textTransform']) . '}'; - $css .= 'footer{background-color:' . $colors['normal'] . ';color:' . $this->getData(['theme', 'footer', 'textColor']) . '}'; + $css .= 'footer {background-color:' . $colors['normal'] . ';color:' . $this->getData(['theme', 'footer', 'textColor']) . '}'; $css .= 'footer a{color:' . $this->getData(['theme', 'footer', 'textColor']) . '}'; $css .= 'footer #footersite > div {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}'; - $css .= 'footer #footerbody {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}'; + $css .= 'footer #footerbody > div {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}'; $css .= '@media (max-width: 768px) {footer #footerbody > div { padding: 2px }}'; $css .= '#footerSocials{text-align:' . $this->getData(['theme', 'footer', 'socialsAlign']) . '}'; $css .= '#footerText > p {text-align:' . $this->getData(['theme', 'footer', 'textAlign']) . '}'; $css .= '#footerCopyright{text-align:' . $this->getData(['theme', 'footer', 'copyrightAlign']) . '}'; - // Marge supplémentaire lorsque le pied de page est fixe - if ( $this->getData(['theme', 'footer', 'fixed']) === true && - $this->getData(['theme', 'footer', 'position']) === 'body') { - $css .= '@media (min-width: 769px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 31 ) . 'px}}'; - $css .= '@media (max-width: 768px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 93 ) . 'px}}'; - } - // Enregistre la personnalisation file_put_contents(self::DATA_DIR.'theme.css', $css); // Effacer le cache pour tenir compte de la couleur de fond TinyMCE diff --git a/core/layout/common.css b/core/layout/common.css index 0afcdc1c..65241857 100755 --- a/core/layout/common.css +++ b/core/layout/common.css @@ -44,11 +44,11 @@ body { body { margin: 0px; } - +/* #site { - /*margin: 0px auto;*/ + margin: 0px auto; } - +*/ body>header { margin: 0px 0px; } @@ -476,12 +476,13 @@ td>.col12 { #site { overflow: hidden; } - +/* Dans theme.css @media (min-width:768px) { #site { margin: 20px auto; } } +*/ /* Bannière */ From 766a89ee5643d938655e06e6df82c8a5c3760655 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Fri, 26 Feb 2021 21:09:45 +0100 Subject: [PATCH 58/61] change --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 18e3d849..26b836db 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,8 @@ - Modifications : - Bouton de remontée, position plus haute et zindex augmenté. - Éviter le chevauchement du pied de age fixe au-dessus du corps de page. +- Corrections : + - Marges du pied de page fixe placé en dehors du site.change ## version 10.4.04 - Correction : From b668b586bf25a19be87d8cb0c18a3679679c9f39 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Fri, 26 Feb 2021 21:37:19 +0100 Subject: [PATCH 59/61] =?UTF-8?q?TinyMCE=20Arri=C3=A8re-plan=20du=20s?= =?UTF-8?q?=C3=A9lecteur=20de=20block=20identique=20au=20site=20+=20couleu?= =?UTF-8?q?r=20du=20lien=20dans=20les=20blocs=20H4=20des=20pages=20adminis?= =?UTF-8?q?tration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 4 +++- core/core.php | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 26b836db..0fa943c7 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,7 +7,9 @@ - Bouton de remontée, position plus haute et zindex augmenté. - Éviter le chevauchement du pied de age fixe au-dessus du corps de page. - Corrections : - - Marges du pied de page fixe placé en dehors du site.change + - Marges du pied de page fixe placé en dehors du site. + - TinyMCE couleurs du sélecteur de paragraphe et de headers lorsque le fond est transparent. + - Thème administration, couleur du lien dans un bloc H4. ## version 10.4.04 - Correction : diff --git a/core/core.php b/core/core.php index f46f1e49..fd396300 100755 --- a/core/core.php +++ b/core/core.php @@ -1663,14 +1663,14 @@ class core extends common { $css .= 'body{font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'text', 'font'])) . '",sans-serif}'; if($themeBodyImage = $this->getData(['theme', 'body', 'image'])) { // Image dans html pour éviter les déformations. - $css .= 'html{background-image:url("../file/source/' . $themeBodyImage . '");background-position:' . $this->getData(['theme', 'body', 'imagePosition']) . ';background-attachment:' . $this->getData(['theme', 'body', 'imageAttachment']) . ';background-size:' . $this->getData(['theme', 'body', 'imageSize']) . ';background-repeat:' . $this->getData(['theme', 'body', 'imageRepeat']) . '}'; + $css .= 'html, .mce-menu.mce-in.mce-animate {background-image:url("../file/source/' . $themeBodyImage . '");background-position:' . $this->getData(['theme', 'body', 'imagePosition']) . ';background-attachment:' . $this->getData(['theme', 'body', 'imageAttachment']) . ';background-size:' . $this->getData(['theme', 'body', 'imageSize']) . ';background-repeat:' . $this->getData(['theme', 'body', 'imageRepeat']) . '}'; // Couleur du body transparente - $css .= 'body{background-color: rgba(0,0,0,0)}'; + $css .= 'body, .mce-menu.mce-in.mce-animate{background-color: rgba(0,0,0,0)}'; } else { // Pas d'image couleur du body - $css .= 'html{background-color:' . $colors['normal'] . ';}'; + $css .= 'html, .mce-menu.mce-in.mce-animate{background-color:' . $colors['normal'] . ';}'; // Même couleur dans le fond de l'éditeur - $css .= 'div.mce-edit-area{background-color:' . $colors['normal'] . ' !important}'; + $css .= 'div.mce-edit-area {background-color:' . $colors['normal'] . ' !important}'; } // Icône BacktoTop $css .= '#backToTop {background-color:' .$this->getData(['theme', 'body', 'toTopbackgroundColor']). ';color:'.$this->getData(['theme', 'body', 'toTopColor']).';}'; @@ -1678,7 +1678,7 @@ class core extends common { $colors = helper::colorVariants($this->getData(['theme', 'text', 'linkColor'])); $css .= 'a{color:' . $colors['normal'] . '}'; // Couleurs de site dans TinyMCe - $css .= 'div.mce-edit-area{font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'text', 'font'])) . '",sans-serif}'; + $css .= 'div.mce-edit-area {font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'text', 'font'])) . '",sans-serif}'; // Site dans TinyMCE $css .= '.editorWysiwyg {background-color:' . $this->getData(['theme', 'site', 'backgroundColor']) . ';}'; //$css .= 'a:hover:not(.inputFile, button){color:' . $colors['darken'] . '}'; @@ -1822,7 +1822,7 @@ class core extends common { $colors = helper::colorVariants($this->getData(['admin','backgroundColor'])); $css .= '#site{background-color:' . $colors['normal']. ';}'; $css .= '.row > div {font:' . $this->getData(['admin','fontSize']) . ' "' . $this->getData(['admin','fontText']) . '", sans-serif;}'; - $css .= 'body h1, h2, h3, h4, h5, h6 {font-family:' . $this->getData(['admin','fontTitle' ]) . ', sans-serif;color:' . $this->getData(['admin','colorTitle' ]) . ';}'; + $css .= 'body h1, h2, h3, h4 a, h5, h6 {font-family:' . $this->getData(['admin','fontTitle' ]) . ', sans-serif;color:' . $this->getData(['admin','colorTitle' ]) . ';}'; $css .= 'body:not(.editorWysiwyg),span .zwiico-help {color:' . $this->getData(['admin','colorText']) . ';}'; $colors = helper::colorVariants($this->getData(['admin','backgroundColorButton'])); $css .= 'input[type="checkbox"]:checked + label::before,.speechBubble{background-color:' . $colors['normal'] . ';color:' . $colors['text'] . ';}'; From 5fb09bd80236464e8a8fa1920cfcb6f9a9185971 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Fri, 26 Feb 2021 21:42:30 +0100 Subject: [PATCH 60/61] =?UTF-8?q?Mise=20=C3=A0=20jour=20des=20th=C3=A8mes?= =?UTF-8?q?=20dans=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/core.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/core.php b/core/core.php index fd396300..8d0fe0ae 100755 --- a/core/core.php +++ b/core/core.php @@ -1573,10 +1573,15 @@ class common { $this->setData(['core', 'dataVersion', 10400]); - /** - * mettre à jour defaultdata - */ + } + // Version 10.4.05 + if ($this->getData(['core', 'dataVersion']) < 10405) { + // Mise à jour forcée des thèmes + unlink (self::DATA_DIR . 'admin.css'); + unlink (self::DATA_DIR . 'theme.css'); + + $this->setData(['core', 'dataVersion', 10405]); } } } From 4d49ea0974ba6fd309c49529aee6042cfe4a2958 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Wed, 3 Mar 2021 08:41:32 +0100 Subject: [PATCH 61/61] change --- CHANGES.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 0fa943c7..5de31615 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,6 @@ - SiteMapGenerator 4.3.1 - Modifications : - Bouton de remontée, position plus haute et zindex augmenté. - - Éviter le chevauchement du pied de age fixe au-dessus du corps de page. - Corrections : - Marges du pied de page fixe placé en dehors du site. - TinyMCE couleurs du sélecteur de paragraphe et de headers lorsque le fond est transparent.