From 4d4512fcc6ad0e2ad9b82b85de5b3d3d809e8a00 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Sun, 5 Feb 2023 19:10:42 +0100 Subject: [PATCH 001/186] dataVersion OKAY autoupdate actif in config WIP --- CHANGES.md | 10 +++++++--- LISEZMOI.md | 2 +- README.md | 2 +- core/core.php | 14 +++++++++----- core/module/config/config.php | 4 ++-- core/module/config/view/setup/setup.php | 5 ++--- core/module/install/ressource/defaultdata.php | 2 +- core/module/translate/translate.php | 6 +++--- 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 708682bd..7c2ef9fd 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,13 @@ # Changelog +## Version 12.2.04 +### Amélioration : +- Prise en charge des mises à jour en ligne + ## Version 12.2.03 - Corrections de bugs consécutifs au changement de format de languages.json -## Version 12.2.02 +## Version 12.2.02 (version non publiée) ### Corrections : - Gestion des plugins (modules) : - Corrige un bug dans l'acquisition des données du store. @@ -11,13 +15,13 @@ - Corrige un bug dans l'installation d'un module (dataDirectory). - Langues étrangères (v4) : corrige l'absence de spécificateur %s dans les traductions occasionnant des plantages lorsqu'une langue étrangère est active. -## Version 12.2.01 +## Version 12.2.01 (version non publiée) ### Correction : - Bug majeur lors de l'installation d'une version fraiche, erreur lors de la création de la base de données des langues. ### Amélioration : - Gestion des erreurs d'écritures à l'aide d'un contrôle des données écrites sur le disque. Cinq tentatives se terminent par un arrêt en cas d'impossibilité d'enregistrer les données. -## Version 12.2.00 +## Version 12.2.00 (version non publiée) ### Nouveautés : - Traduction des modules en anglais, grec, espagnol, italien et portugais. ### Amélioration : diff --git a/LISEZMOI.md b/LISEZMOI.md index eb9ae38b..32aead6f 100644 --- a/LISEZMOI.md +++ b/LISEZMOI.md @@ -1,4 +1,4 @@ -# ZwiiCMS 12.2.03 +# ZwiiCMS 12.2.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/README.md b/README.md index 7646da87..09ba5d81 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ZwiiCMS 12.2.03 +# ZwiiCMS 12.2.04 Zwii is a database-less (flat-file) CMS that allows you to easily create and manage a web site without any programming knowledge. diff --git a/core/core.php b/core/core.php index 0d532ff3..e497a079 100644 --- a/core/core.php +++ b/core/core.php @@ -53,7 +53,8 @@ class common const ZWII_UI_URL = 'https://forge.chapril.org/ZwiiCMS-Team/zwiicms-translations/raw/branch/master/'; // Numéro de version et branche pour l'auto-update - const ZWII_VERSION = '12.2.03'; + const ZWII_VERSION = '12.2.04'; + const ZWII_DATAVERSION = 12000; const ZWII_UPDATE_CHANNEL = "v12"; public static $actions = []; @@ -471,9 +472,12 @@ class common } } - // Mise à jour des données core - if ($this->getData(['core', 'dataVersion']) !== intval(str_replace('.', '', self::ZWII_VERSION))) + // Mise à jour des données core selon la version du jeu de données + if ( $this->getData(['core', 'dataVersion']) < common::ZWII_DATAVERSION ) { + die(); include('core/include/update.inc.php'); + } + // Données de proxy $proxy = $this->getData(['config', 'proxyType']) . $this->getData(['config', 'proxyUrl']) . ':' . $this->getData(['config', 'proxyPort']); @@ -2270,11 +2274,11 @@ class common 'help' => 'Utilisateurs', 'href' => helper::baseUrl() . 'user' ]) . ''; - + // Mise à jour automatique $today = mktime(0, 0, 0); $checkUpdate = (int) $this->getData(['core', 'lastAutoUpdate']); - // Recherche d'une mise à jour si active, si une mise à jour n'est pas déjà disponible et le délais journalier est dépassé. + // Recherche d'une mise à jour si active, si une mise à jour n'est pas déjà disponible et le délai journalier est dépassé. if ( $this->getData(['config', 'autoUpdate']) === true and $this->getData(['core', 'updateAvailable']) === false diff --git a/core/module/config/config.php b/core/module/config/config.php index 3b0d3977..a89929b3 100644 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -420,7 +420,6 @@ class config extends common $this->setData(['core', 'lastAutoUpdate', 0]); } - // Sauvegarder la configuration $this->setData([ 'config', @@ -545,7 +544,8 @@ class config extends common // Variable de version self::$onlineVersion = helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/version'); - if (self::$onlineVersion > common::ZWII_VERSION) { + if (version_compare(self::$onlineVersion, common::ZWII_VERSION ) == 1) { + $this->setData(['core', 'updateAvailable', true]); self::$updateButtonText = helper::translate('Mettre à jour'); } diff --git a/core/module/config/view/setup/setup.php b/core/module/config/view/setup/setup.php index 4a440f95..9a7f991f 100644 --- a/core/module/config/view/setup/setup.php +++ b/core/module/config/view/setup/setup.php @@ -84,8 +84,8 @@
- Version installée : ' . common::ZWII_VERSION . ''; ?> - Version en ligne : ' . $module::$onlineVersion . '' : ''; ?> +
Version installée : 
+
Version en ligne  : 
helper::baseUrl() . 'install/update', 'value' => $module::$updateButtonText, 'class' => 'buttonRed', - 'disabled' => !$module::$onlineVersion ]); ?>
diff --git a/core/module/install/ressource/defaultdata.php b/core/module/install/ressource/defaultdata.php index 45aeca0b..c6f95698 100644 --- a/core/module/install/ressource/defaultdata.php +++ b/core/module/install/ressource/defaultdata.php @@ -44,7 +44,7 @@ class init extends common ] ], 'core' => [ - 'dataVersion' => 11600, + 'dataVersion' => 12000, 'lastBackup' => 0, 'lastClearTmp' => 0, 'lastAutoUpdate' => 0, diff --git a/core/module/translate/translate.php b/core/module/translate/translate.php index f6da3842..9ce8deb8 100644 --- a/core/module/translate/translate.php +++ b/core/module/translate/translate.php @@ -82,7 +82,7 @@ class translate extends common // Upload et sauver le fichier de langue $response = json_decode(helper::getUrlContents(common::ZWII_UI_URL . $lang . '.json'), true); if ($response !== false) { - $response = file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + $response = file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); // Mettre à jour le descripteur $enumsStore = json_decode(helper::getUrlContents(common::ZWII_UI_URL . 'languages.json'), true); $enums = $this->getData(['languages']); @@ -91,7 +91,7 @@ class translate extends common ]); $response = (bool) $response && $this->setData(['languages', $enums]); } - + // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . 'translate', @@ -272,7 +272,7 @@ class translate extends common } } - + // Valeurs en sortie $this->addOutput([ 'title' => helper::translate('Multilingue'), From 5dc317b131b75da3c4245f10e27621170a33ab33 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Mon, 6 Feb 2023 20:11:31 +0100 Subject: [PATCH 002/186] 1204 Wrong class displayNone --- module/gallery/view/add/add.php | 2 +- module/gallery/view/option/option.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/gallery/view/add/add.php b/module/gallery/view/add/add.php index c3d66a21..d0d1830d 100644 --- a/module/gallery/view/add/add.php +++ b/module/gallery/view/add/add.php @@ -22,7 +22,7 @@ ]); ?>
-
+
true // Désactivé à cause des modifications en ajax ]); ?> diff --git a/module/gallery/view/option/option.php b/module/gallery/view/option/option.php index 83337ab3..31728834 100644 --- a/module/gallery/view/option/option.php +++ b/module/gallery/view/option/option.php @@ -67,7 +67,7 @@ ]); ?>
-
+
$this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(3), 'config', 'directory']), 'noDirty' => true // Désactivé à cause des modifications en ajax From 623d5e775bdb48c77d26e01e9f51ef51f31cfe98 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Mon, 6 Feb 2023 21:43:40 +0100 Subject: [PATCH 003/186] =?UTF-8?q?12204=20autoupdate=20param=C3=A8tres=20?= =?UTF-8?q?manquants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/class/helper.class.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/class/helper.class.php b/core/class/helper.class.php index 5935ef45..fe2ea52d 100644 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -361,9 +361,9 @@ class helper * Renvoie le numéro de version de Zwii est en ligne * @return string */ - public static function getOnlineVersion() + public static function getOnlineVersion($channel) { - return (helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/version')); + return (helper::getUrlContents(common::ZWII_UPDATE_URL . $channel . '/version')); } @@ -371,9 +371,9 @@ class helper * Check si une nouvelle version de Zwii est disponible * @return bool */ - public static function checkNewVersion() + public static function checkNewVersion($channel) { - $version = helper::getOnlineVersion(); + $version = helper::getOnlineVersion($channel); if (!empty($version)) { return ((version_compare(common::ZWII_VERSION, $version)) === -1); } else { From ebc7b59b20ee67cf1155b0f146df442cbdef9786 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Mon, 6 Feb 2023 21:45:03 +0100 Subject: [PATCH 004/186] =?UTF-8?q?12204=20Supprime=20Tahoma=20en=20double?= =?UTF-8?q?=20R=C3=A9=C3=A9crit=20la=20fonction=20de=20contr=C3=B4le=20d'u?= =?UTF-8?q?ne=20mise=20=C3=A0=20joru=20en=20ligne?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/core.php | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/core/core.php b/core/core.php index e497a079..8e866a51 100644 --- a/core/core.php +++ b/core/core.php @@ -48,14 +48,20 @@ class common // URL autoupdate const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; + const ZWII_UPDATE_CHANNEL = "v12"; + + // Constantes de test + //const ZWII_UPDATE_CHANNEL = "test"; + //const ZWII_UPDATE_URL = 'http://localhost/update/'; // URL langues de l'UI en ligne const ZWII_UI_URL = 'https://forge.chapril.org/ZwiiCMS-Team/zwiicms-translations/raw/branch/master/'; // Numéro de version et branche pour l'auto-update const ZWII_VERSION = '12.2.04'; + const ZWII_DATAVERSION = 12000; - const ZWII_UPDATE_CHANNEL = "v12"; + public static $actions = []; public static $coreModuleIds = [ @@ -283,11 +289,6 @@ class common 'font-family' => '\'Trebuchet MS\', Arial, Helvetica, sans-serif', 'resource' => 'websafe' ], - 'tahoma' => [ - 'name' => 'Tahoma', - 'font-family' => 'Tahoma, Geneva, sans-serif', - 'resource' => 'websafe' - ], 'verdana' => [ 'name' => 'Verdana', 'font-family' => 'Verdana, Geneva, sans-serif;', @@ -474,7 +475,6 @@ class common // Mise à jour des données core selon la version du jeu de données if ( $this->getData(['core', 'dataVersion']) < common::ZWII_DATAVERSION ) { - die(); include('core/include/update.inc.php'); } @@ -621,7 +621,7 @@ class common * Lire les données de la page * @param string pageId * @param string langue - * @param return contenu de la page + * @return string contenu de la page */ public function getPage($page, $lang) { @@ -641,7 +641,7 @@ class common * Ecrire les données de la page * @param string pageId * @param string contenu de la page - * @param return nombre d'octets écrits ou erreur + * @return int nombre d'octets écrits ou erreur */ public function setPage($page, $value, $lang) { @@ -654,7 +654,7 @@ class common /** * Effacer les données de la page * @param string pageId - * @param return statut de l'effacement + * @return bool statut de l'effacement */ public function deletePage($page, $lang) { @@ -2277,23 +2277,28 @@ class common // Mise à jour automatique $today = mktime(0, 0, 0); - $checkUpdate = (int) $this->getData(['core', 'lastAutoUpdate']); + $checkUpdate = $this->getData(['core', 'lastAutoUpdate']); // Recherche d'une mise à jour si active, si une mise à jour n'est pas déjà disponible et le délai journalier est dépassé. if ( - $this->getData(['config', 'autoUpdate']) === true - and $this->getData(['core', 'updateAvailable']) === false - and $today > $checkUpdate + 86400 - ) { - $this->setData(['core', 'updateAvailable', helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL)]); + $this->getData(['config', 'autoUpdate']) + ) { + if ( + $today > $checkUpdate + 86400 + ) { + // Dernier auto controle + $this->setData(['core', 'lastAutoUpdate', $today]); + if ( + helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL) + ) { + $this->setData(['core', 'updateAvailable', true]); + } + } } - // Dernier auto controle - $this->setData(['core', 'lastAutoUpdate', $today]); + + // Afficher le bouton : Mise à jour détectée + activée - if ( - $this->getData(['core', 'updateAvailable']) === true && - $this->getData(['config', 'autoUpdate']) === true - ) { - $rightItems .= '
  • ' . template::ico('update colorRed') . '
  • '; + if ($this->getData(['core', 'updateAvailable']) ) { + $rightItems .= '
  • ' . template::ico('update colorRed') . '
  • '; } } if ($this->getUser('group') >= self::GROUP_MODERATOR) { From 52ea9f66fa799d787a65aa4d96cda82a6388c099 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Mon, 6 Feb 2023 21:45:41 +0100 Subject: [PATCH 005/186] 12204 Autoupdate : Optimisation des variables --- core/module/config/config.php | 3 +-- core/module/config/view/setup/setup.php | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/module/config/config.php b/core/module/config/config.php index a89929b3..cd380dde 100644 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -543,8 +543,7 @@ class config extends common } // Variable de version - self::$onlineVersion = helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/version'); - if (version_compare(self::$onlineVersion, common::ZWII_VERSION ) == 1) { + if (helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL)) { $this->setData(['core', 'updateAvailable', true]); self::$updateButtonText = helper::translate('Mettre à jour'); } diff --git a/core/module/config/view/setup/setup.php b/core/module/config/view/setup/setup.php index 9a7f991f..d11f42bc 100644 --- a/core/module/config/view/setup/setup.php +++ b/core/module/config/view/setup/setup.php @@ -71,21 +71,21 @@ $this->getData(['config', 'autoUpdate']), 'help' => 'La vérification est quotidienne. Option désactivée si la configuration du serveur ne le permet pas.', - 'disabled' => !$module::$onlineVersion + 'disabled' => empty(helper::getOnlineVersion(common::ZWII_UPDATE_CHANNEL)) ]); ?>
    $this->getData(['config', 'autoUpdateHtaccess']), 'help' => 'Lors d\'une mise à jour automatique, conserve le fichier htaccess de la racine du site.', - 'disabled' => !$module::$onlineVersion + 'disabled' => empty(helper::getOnlineVersion(common::ZWII_UPDATE_CHANNEL)) ]); ?>
    Version installée : 
    -
    Version en ligne  : 
    +
    Version en ligne  : 
    Date: Tue, 7 Feb 2023 08:36:19 +0100 Subject: [PATCH 006/186] 12204 sort const --- core/core.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/core.php b/core/core.php index 8e866a51..8811f24b 100644 --- a/core/core.php +++ b/core/core.php @@ -46,22 +46,22 @@ class common // Contrôle d'édition temps maxi en secondes avant déconnexion 30 minutes const ACCESS_TIMER = 1800; + // Numéro de version et branche pour l'auto-update + const ZWII_VERSION = '12.2.04'; + + const ZWII_DATAVERSION = 12000; + // URL autoupdate const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; const ZWII_UPDATE_CHANNEL = "v12"; // Constantes de test - //const ZWII_UPDATE_CHANNEL = "test"; //const ZWII_UPDATE_URL = 'http://localhost/update/'; + //const ZWII_UPDATE_CHANNEL = "test"; // URL langues de l'UI en ligne const ZWII_UI_URL = 'https://forge.chapril.org/ZwiiCMS-Team/zwiicms-translations/raw/branch/master/'; - // Numéro de version et branche pour l'auto-update - const ZWII_VERSION = '12.2.04'; - - const ZWII_DATAVERSION = 12000; - public static $actions = []; public static $coreModuleIds = [ From c5b15578cc3e8146107044ec5a2253c4d6002263 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 11:21:21 +0100 Subject: [PATCH 007/186] =?UTF-8?q?12204=20Ajoute=20une=20option=20de=20fr?= =?UTF-8?q?=C3=A9quence=20de=20la=20recherche=20auto=20Fait=20correspondre?= =?UTF-8?q?=20le=20num=C3=A9ro=20de=20version=20des=20langues=20avec=20la?= =?UTF-8?q?=20version=20des=20donn=C3=A9es=20Mise=20=C3=A0=20jour=20des=20?= =?UTF-8?q?langues=20prenant=20con=20compte=20la=20nouvelle=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 7 +++-- core/core.php | 12 ++++---- core/include/update.inc.php | 8 ++++++ core/module/config/config.php | 28 ++++++++++++++++++- core/module/config/view/setup/setup.php | 10 +++++-- core/module/install/ressource/i18n/en_EN.json | 5 +++- core/module/install/ressource/i18n/es.json | 5 +++- core/module/install/ressource/i18n/fr_FR.json | 5 +++- core/module/install/ressource/i18n/gr_GR.json | 5 +++- core/module/install/ressource/i18n/it.json | 5 +++- .../install/ressource/i18n/languages.json | 24 ++++++++-------- core/module/install/ressource/i18n/pt_PT.json | 5 +++- 12 files changed, 90 insertions(+), 29 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7c2ef9fd..9c745409 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,11 @@ # Changelog ## Version 12.2.04 -### Amélioration : -- Prise en charge des mises à jour en ligne +### Améliorations : +- Amélioration de la prise en charge des mises à jour en ligne. +- Activation du bouton de mise à jour dans la barre d'administration lorsque le menu de configuration est ouvert est qu'une mise à jour en ligne est détectée. +### Nouveautés : +- Paramètrage du délai de recherche automatique d'une mise à jour, tous les jours, deux jours, quatre jours, toutes les semaines, tous les mois. ## Version 12.2.03 - Corrections de bugs consécutifs au changement de format de languages.json diff --git a/core/core.php b/core/core.php index 8811f24b..3c29c86b 100644 --- a/core/core.php +++ b/core/core.php @@ -49,15 +49,15 @@ class common // Numéro de version et branche pour l'auto-update const ZWII_VERSION = '12.2.04'; - const ZWII_DATAVERSION = 12000; + const ZWII_DATAVERSION = 12204; // URL autoupdate - const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; - const ZWII_UPDATE_CHANNEL = "v12"; + //const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; + //const ZWII_UPDATE_CHANNEL = "v12"; // Constantes de test - //const ZWII_UPDATE_URL = 'http://localhost/update/'; - //const ZWII_UPDATE_CHANNEL = "test"; + const ZWII_UPDATE_URL = 'http://localhost/update/'; + const ZWII_UPDATE_CHANNEL = "test"; // URL langues de l'UI en ligne const ZWII_UI_URL = 'https://forge.chapril.org/ZwiiCMS-Team/zwiicms-translations/raw/branch/master/'; @@ -2283,7 +2283,7 @@ class common $this->getData(['config', 'autoUpdate']) ) { if ( - $today > $checkUpdate + 86400 + $today > $checkUpdate + $this->getData(['config', 'autoUpdateDelay', 86400]) ) { // Dernier auto controle $this->setData(['core', 'lastAutoUpdate', $today]); diff --git a/core/include/update.inc.php b/core/include/update.inc.php index 8b1542f7..7a81e776 100644 --- a/core/include/update.inc.php +++ b/core/include/update.inc.php @@ -914,3 +914,11 @@ if ($this->getData(['core', 'dataVersion']) < 12000) { // Mise à jour $this->setData(['core', 'dataVersion', 12000]); } + +// Version 12.2.04 +if ($this->getData(['core', 'dataVersion']) < 12204) { + // Valeur par défaut du délai de recherche de mise à joru en ligne + $this->setData(['config', 'autoUpdateDelay', 86400]); + // Mise à jour + $this->setData(['core', 'dataVersion', 12204]); +} \ No newline at end of file diff --git a/core/module/config/config.php b/core/module/config/config.php index cd380dde..8f1a77de 100644 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -189,6 +189,13 @@ class config extends common 'num' => 'Chiffres', 'alpha' => 'Lettres' ]; + public static $updateDelay = [ + 86400 => '1', + 172800 => '2', + 345600 => '4', + 604800 => '7', + 1209600 => '14', + ]; // Langue traduite courante public static $i18nSite = 'fr_FR'; @@ -435,6 +442,7 @@ class config extends common 'proxyType' => $this->getInput('configProxyType'), 'proxyUrl' => $this->getInput('configProxyUrl'), 'proxyPort' => $this->getInput('configProxyPort', helper::FILTER_INT), + 'autoUpdateDelay' => $this->getInput('configAutoUpdateDelay', helper::FILTER_INT), 'social' => [ 'facebookId' => $this->getInput('socialFacebookId'), 'linkedinId' => $this->getInput('socialLinkedinId'), @@ -542,12 +550,30 @@ class config extends common ]); } + // Activation du bouton de mise à jour + if ( + helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL) + && $this->getData(['core', 'updateAvailable']) === false + && $this->getData(['config', 'autoUpdate']) + ) { + $this->setData(['core', 'updateAvailable', true]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'config', + ]); + + } + // Variable de version if (helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL)) { - $this->setData(['core', 'updateAvailable', true]); self::$updateButtonText = helper::translate('Mettre à jour'); } + // Sélecteur de délais, compléter avec la traduction en jours + foreach(self::$updateDelay as $key => $value) { + self::$updateDelay[$key] = $key === 86400 ? $value . ' ' . helper::translate('jour') : $value . ' ' . helper::translate('jours'); + } + // Valeurs en sortie $this->addOutput([ 'title' => helper::translate('Configuration'), diff --git a/core/module/config/view/setup/setup.php b/core/module/config/view/setup/setup.php index d11f42bc..3c25a371 100644 --- a/core/module/config/view/setup/setup.php +++ b/core/module/config/view/setup/setup.php @@ -83,11 +83,17 @@
    -
    +
    + 'Fréquence de recherche', + 'selected' => $this->getData(['config', 'autoUpdateDelay']), + ]); ?> +
    +
    Version installée : 
    Version en ligne  : 
    -
    +
    'download-cloud', 'href' => helper::baseUrl() . 'install/update', diff --git a/core/module/install/ressource/i18n/en_EN.json b/core/module/install/ressource/i18n/en_EN.json index 3918822d..147eefab 100644 --- a/core/module/install/ressource/i18n/en_EN.json +++ b/core/module/install/ressource/i18n/en_EN.json @@ -494,5 +494,8 @@ "Éditeur de script %s": "Script editor %s", "Éditeur de script dans Body": "Script editor in Body", "Éditeur de script dans Head": "Script editor in Head", - "Étiquettes des pages spéciales": "Special pages labels" + "Étiquettes des pages spéciales": "Special pages labels", + "Fréquence de recherche": "Search frequency", + "jour" : "day", + "jours" : "days" } \ No newline at end of file diff --git a/core/module/install/ressource/i18n/es.json b/core/module/install/ressource/i18n/es.json index 0291f2db..521d30ae 100644 --- a/core/module/install/ressource/i18n/es.json +++ b/core/module/install/ressource/i18n/es.json @@ -494,5 +494,8 @@ "Éditeur de script %s": "Editor de script %s", "Éditeur de script dans Body": "Éditor del script en el Body", "Éditeur de script dans Head": "Éditor del script en el Head", - "Étiquettes des pages spéciales": "Etiquetas de página especiales" + "Étiquettes des pages spéciales": "Etiquetas de página especiales", + "Fréquence de recherche": "Frecuencia de búsqueda", + "jour" : "día", + "jours" : "días" } \ No newline at end of file diff --git a/core/module/install/ressource/i18n/fr_FR.json b/core/module/install/ressource/i18n/fr_FR.json index 6807c1cd..1ca8f691 100644 --- a/core/module/install/ressource/i18n/fr_FR.json +++ b/core/module/install/ressource/i18n/fr_FR.json @@ -494,5 +494,8 @@ "Éditeur de script %s": "", "Éditeur de script dans Body": "", "Éditeur de script dans Head": "", - "Étiquettes des pages spéciales": "" + "Étiquettes des pages spéciales": "", + "Fréquence de recherche": "", + "jour" : "", + "jours" : "" } \ No newline at end of file diff --git a/core/module/install/ressource/i18n/gr_GR.json b/core/module/install/ressource/i18n/gr_GR.json index 73d16595..8bcc189a 100644 --- a/core/module/install/ressource/i18n/gr_GR.json +++ b/core/module/install/ressource/i18n/gr_GR.json @@ -494,5 +494,8 @@ "Éditeur de script %s": "Συντάκτης του script %s", "Éditeur de script dans Body": "Επεξεργαστής script στο Body", "Éditeur de script dans Head": "Επεξεργαστής script στο Head", - "Étiquettes des pages spéciales": "Ειδικές ετικέτες σελίδων" + "Étiquettes des pages spéciales": "Ειδικές ετικέτες σελίδων", + "Fréquence de recherche": "Συχνότητα αναζήτησης", + "jour" : "ημέρα", + "jours" : "ημέρες" } \ No newline at end of file diff --git a/core/module/install/ressource/i18n/it.json b/core/module/install/ressource/i18n/it.json index df3bdbc1..6848f7b6 100644 --- a/core/module/install/ressource/i18n/it.json +++ b/core/module/install/ressource/i18n/it.json @@ -494,5 +494,8 @@ "Éditeur de script %s": "Script Editor %s", "Éditeur de script dans Body": "Editor di script in Body", "Éditeur de script dans Head": "Editor di script in Head.", - "Étiquettes des pages spéciales": "Etichette di pagina speciali" + "Étiquettes des pages spéciales": "Etichette di pagina speciali", + "Fréquence de recherche": "Frequenza di ricerca", + "jour" : "giorno", + "jours" : "giorni" } \ No newline at end of file diff --git a/core/module/install/ressource/i18n/languages.json b/core/module/install/ressource/i18n/languages.json index 3bffac16..da972645 100644 --- a/core/module/install/ressource/i18n/languages.json +++ b/core/module/install/ressource/i18n/languages.json @@ -1,28 +1,28 @@ { "languages": { "fr_FR": { - "version": "4", - "date": 1675459590 + "version": "12204", + "date": 1675759709 }, "es": { - "version": "4", - "date": 1675459590 + "version": "12204", + "date": 1675759709 }, "it": { - "version": "4", - "date": 1675459590 + "version": "12204", + "date": 1675759709 }, "pt_PT": { - "version": "4", - "date": 1675459590 + "version": "12204", + "date": 1675759709 }, "en_EN": { - "version": "4", - "date": 1675459590 + "version": "12204", + "date": 1675759709 }, "gr_GR": { - "version": "4", - "date": 1675459590 + "version": "12204", + "date": 1675759709 } } } \ No newline at end of file diff --git a/core/module/install/ressource/i18n/pt_PT.json b/core/module/install/ressource/i18n/pt_PT.json index 80b2d7a7..8c8c587f 100644 --- a/core/module/install/ressource/i18n/pt_PT.json +++ b/core/module/install/ressource/i18n/pt_PT.json @@ -494,5 +494,8 @@ "Éditeur de script %s": "Editor de script %s", "Éditeur de script dans Body": "Éditor do script no Body", "Éditeur de script dans Head": "Éditor do script no Head", - "Étiquettes des pages spéciales": "Tags de página especiais" + "Étiquettes des pages spéciales": "Tags de página especiais", + "Fréquence de recherche": "Frequência de pesquisa", + "jour" : "dia", + "jours" : "dias" } \ No newline at end of file From 7be2729eb6b7ac0dc42c6735f2e471f489384a48 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 11:26:18 +0100 Subject: [PATCH 008/186] =?UTF-8?q?s=C3=A9active=20le=20mode=20test=20des?= =?UTF-8?q?=20mises=20=C3=A0=20jour?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/core.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/core.php b/core/core.php index 3c29c86b..0ee513d0 100644 --- a/core/core.php +++ b/core/core.php @@ -52,12 +52,12 @@ class common const ZWII_DATAVERSION = 12204; // URL autoupdate - //const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; - //const ZWII_UPDATE_CHANNEL = "v12"; + const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; + const ZWII_UPDATE_CHANNEL = "v12"; // Constantes de test - const ZWII_UPDATE_URL = 'http://localhost/update/'; - const ZWII_UPDATE_CHANNEL = "test"; + //const ZWII_UPDATE_URL = 'http://localhost/update/'; + //const ZWII_UPDATE_CHANNEL = "test"; // URL langues de l'UI en ligne const ZWII_UI_URL = 'https://forge.chapril.org/ZwiiCMS-Team/zwiicms-translations/raw/branch/master/'; From 0fcc2b511e54c4fd6cfa72170903987adff70034 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 13:29:20 +0100 Subject: [PATCH 009/186] 12204 Languafe database version is int --- core/module/install/ressource/i18n/languages.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/module/install/ressource/i18n/languages.json b/core/module/install/ressource/i18n/languages.json index da972645..cc0922a6 100644 --- a/core/module/install/ressource/i18n/languages.json +++ b/core/module/install/ressource/i18n/languages.json @@ -1,27 +1,27 @@ { "languages": { "fr_FR": { - "version": "12204", + "version": 12204, "date": 1675759709 }, "es": { - "version": "12204", + "version": 12204, "date": 1675759709 }, "it": { - "version": "12204", + "version": 12204, "date": 1675759709 }, "pt_PT": { - "version": "12204", + "version": 12204, "date": 1675759709 }, "en_EN": { - "version": "12204", + "version": 12204, "date": 1675759709 }, "gr_GR": { - "version": "12204", + "version": 12204, "date": 1675759709 } } From a5b79b16890f0053e97c49d8cbc4f5da1f594ae5 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 13:31:11 +0100 Subject: [PATCH 010/186] 12204 Delete useless makeUiLanguages Update UI languagues from template when install --- core/module/install/install.php | 74 ++++++++++++++------------------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/core/module/install/install.php b/core/module/install/install.php index 3dce2f3c..89063819 100644 --- a/core/module/install/install.php +++ b/core/module/install/install.php @@ -31,7 +31,7 @@ class install extends common ]; // Thèmes proposés à l'installation - public static $themes = []; + public static $themes = []; public static $newVersion; @@ -144,9 +144,9 @@ class install extends common $userMail, 'Installation de votre site', 'Bonjour' . ' ' . $userFirstname . ' ' . $userLastname . ',

    ' . - 'Voici les détails de votre installation.

    ' . - 'URL du site : ' . helper::baseUrl(false) . '
    ' . - 'Identifiant du compte : ' . $this->getInput('installId') . '
    ', + 'Voici les détails de votre installation.

    ' . + 'URL du site : ' . helper::baseUrl(false) . '
    ' . + 'Identifiant du compte : ' . $this->getInput('installId') . '
    ', null ); @@ -240,7 +240,7 @@ class install extends common $this->addOutput([ 'redirect' => helper::baseUrl(false), 'notification' => $sent === true ? helper::translate('Installation terminée') : $sent, - 'state' => ($sent === true && $success === true) ? true : null + 'state' => ($sent === true && $success === true) ? true : null ]); } } @@ -267,7 +267,7 @@ class install extends common public function steps() { switch ($this->getInput('step', helper::FILTER_INT)) { - // Préparation + // Préparation case 1: $success = true; // RAZ la mise à jour auto @@ -294,7 +294,7 @@ class install extends common ] ]); break; - // Téléchargement + // Téléchargement case 2: file_put_contents(self::TEMP_DIR . 'update.tar.gz', helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/update.tar.gz')); $md5origin = helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/update.md5'); @@ -309,7 +309,7 @@ class install extends common ] ]); break; - // Installation + // Installation case 3: $success = true; // Check la réécriture d'URL avant d'écraser les fichiers @@ -340,15 +340,15 @@ class install extends common ] ]); break; - // Configuration + // Configuration case 4: $success = true; $rewrite = $this->getInput('data'); // Réécriture d'URL - if ($rewrite === "true") { // Ajout des lignes dans le .htaccess + if ($rewrite === "true") { // Ajout des lignes dans le .htaccess $fileContent = file_get_contents('.htaccess'); - $rewriteData = PHP_EOL . - '# URL rewriting' . PHP_EOL . + $rewriteData = PHP_EOL . + '# URL rewriting' . PHP_EOL . '' . PHP_EOL . "\tRewriteEngine on" . PHP_EOL . "\tRewriteBase " . helper::baseUrl(false, false) . PHP_EOL . @@ -373,6 +373,25 @@ class install extends common // Effacer le backup unlink('.htaccess.bak'); } + + /** + * Met à jour les dictionnaires des langues depuis les modèles installés + */ + + // Langues installées + $installedUI = $this->getData(['languages']); + + // Langues disponibles avec la mise à jour + $store = json_decode(file_get_contents('core\module\install\ressource\i18n\languages.json'), true); + $store = $store['languages']; + + foreach ($installedUI as $key => $value) { + if ($store[$key]['version'] > $value['version']) { + echo copy('core/module/install/ressource/i18n/' . $key . '.json', self::I18N_DIR . $key . '.json'); + $this->setData(['languages', $key, $store[$key]]); + } + } + // Valeurs en sortie $this->addOutput([ 'display' => self::DISPLAY_JSON, @@ -381,7 +400,6 @@ class install extends common 'data' => null ] ]); - break; } } @@ -400,32 +418,4 @@ class install extends common ]); } - /** - * Génère un fichier d'énumération des langues de l'UI - */ - private function makeUiLanguages() - { - // Générer une énumération absente - if (empty($enums)) { - if (is_dir(self::I18N_DIR) === false) { - mkdir(self::I18N_DIR); - } - $dir = getcwd(); - chdir(self::I18N_DIR); - $files = glob('*.json'); - chdir($dir); - $enums = []; - foreach ($files as $file => $value) { - if (basename($value, '.json') === 'languages') { - continue; - } - $enums[basename($value, '.json')] = [ - 'version' => "?", - 'date' => 1672052400 - ]; - } - $this->setData(['languages', $enums]); - } - - } -} +} \ No newline at end of file From 821d18518dc7662bc51aef1126e84d00bd9f70b0 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 13:31:58 +0100 Subject: [PATCH 011/186] 12204 Update UI languages when open translates setup --- core/module/translate/translate.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/module/translate/translate.php b/core/module/translate/translate.php index 9ce8deb8..61fc96a1 100644 --- a/core/module/translate/translate.php +++ b/core/module/translate/translate.php @@ -168,6 +168,24 @@ class translate extends common public function index() { + /** + * Met à jour les dictionnaires des langues depuis les modèles installés + */ + + // Langues installées + $installedUI = $this->getData(['languages']); + + // Langues disponibles avec la mise à jour + $store = json_decode(file_get_contents('core\module\install\ressource\i18n\languages.json'), true); + $store = $store['languages']; + + foreach($installedUI as $key => $value) { + if ($store[$key]['version'] > $value['version']) { + echo copy('core/module/install/ressource/i18n/' . $key . '.json', self::I18N_DIR . $key . '.json'); + $this->setData(['languages', $key, $store[$key]]); + } + } + // Préparation du formulaire // ------------------------- From 00e4a7ae245ba488a999683ace5d183feaca6d2c Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 13:38:53 +0100 Subject: [PATCH 012/186] =?UTF-8?q?12204=20D=C3=A9sactive=20l'=C3=A9dition?= =?UTF-8?q?=20d'une=20langue=20de=20l'UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 4 ++++ core/module/translate/translate.php | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9c745409..d531beca 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,10 @@ ### Améliorations : - Amélioration de la prise en charge des mises à jour en ligne. - Activation du bouton de mise à jour dans la barre d'administration lorsque le menu de configuration est ouvert est qu'une mise à jour en ligne est détectée. +- Gestion des langues : + - Le numéro de version d'une langue est le numéro de version de base de données + - A l'installation ou lors de l'accès à la fenêtre des langues, les dialogues sont actualisés. + - La fonction d'édition des langues de l'UI est neutralisée. ### Nouveautés : - Paramètrage du délai de recherche automatique d'une mise à jour, tous les jours, deux jours, quatre jours, toutes les semaines, tous les mois. diff --git a/core/module/translate/translate.php b/core/module/translate/translate.php index 61fc96a1..dcbaf4a2 100644 --- a/core/module/translate/translate.php +++ b/core/module/translate/translate.php @@ -202,7 +202,7 @@ class translate extends common } self::$languagesInstalled[] = [ template::flag($key, '20 %') . ' ' . $value . ' (' . $key . ')', - $messageLocale, + $messageLocale, template::button('translateContentLanguageLocaleEdit' . $key, [ 'class' => file_exists(self::DATA_DIR . $key . '/locale.json') ? '' : ' disabled', 'href' => helper::baseUrl() . $this->getUrl(0) . '/locale/' . $key, @@ -249,12 +249,14 @@ class translate extends common helper::dateUTF8('%d/%m/%Y', $value['date']), //self::$i18nUI === $file ? helper::translate('Interface') : '', '', + /* template::button('translateContentLanguageUIEdit' . $file, [ 'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $file, 'value' => template::ico('pencil'), 'help' => 'Éditer', 'disabled' => 'fr_FR' === $file ]), + */ template::button('translateContentLanguageUIDownload' . $file, [ 'class' => version_compare($installedUI[$file]['version'], $storeUI[$file]['version']) < 0 ? 'buttonGreen' : '', 'href' => helper::baseUrl() . $this->getUrl(0) . '/update/' . $file . '/' . $_SESSION['csrf'], From cd3ccb0fc716c9cebb4008d70ee904c550718874 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 13:39:10 +0100 Subject: [PATCH 013/186] =?UTF-8?q?12204=20D=C3=A9sactive=20l'=C3=A9dition?= =?UTF-8?q?=20d'une=20langue=20de=20l'UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/translate/view/index/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/module/translate/view/index/index.php b/core/module/translate/view/index/index.php index fe06c612..b9d5ae3e 100644 --- a/core/module/translate/view/index/index.php +++ b/core/module/translate/view/index/index.php @@ -38,7 +38,7 @@ - +
    From 1661fae39892c53475c284564a61bc693231189b Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 14:05:03 +0100 Subject: [PATCH 014/186] 12204 supprime la fonction getUILanguages --- core/module/translate/translate.php | 30 ----------------------------- 1 file changed, 30 deletions(-) diff --git a/core/module/translate/translate.php b/core/module/translate/translate.php index dcbaf4a2..15e04283 100644 --- a/core/module/translate/translate.php +++ b/core/module/translate/translate.php @@ -627,34 +627,4 @@ class translate extends common ]); } - /** - * Génère un fichier d'énumération des langues de l'UI - */ - private function getUiLanguages() - { - $enums = $this->getData(['languages']); - - // Générer une énumération absente - if (empty($enums)) { - if (is_dir(self::I18N_DIR) === false) { - mkdir(self::I18N_DIR); - } - $dir = getcwd(); - chdir(self::I18N_DIR); - $files = glob('*.json'); - chdir($dir); - $enums = []; - foreach ($files as $file => $value) { - if (basename($value, '.json') === 'languages') { - continue; - } - $enums[basename($value, '.json')] = [ - 'version' => "?", - 'date' => 1672052400 - ]; - } - $this->setData(['languages', $enums]); - } - return ($enums); - } } \ No newline at end of file From 65f5dd7c606ea0ff51f983b19daba2800031966c Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Tue, 7 Feb 2023 14:21:15 +0100 Subject: [PATCH 015/186] 12204 Norme interface graphique (bouton retour) --- core/module/config/view/restore/restore.php | 5 ++--- core/module/config/view/script/script.php | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/module/config/view/restore/restore.php b/core/module/config/view/restore/restore.php index 8bfded6c..8559d5f0 100644 --- a/core/module/config/view/restore/restore.php +++ b/core/module/config/view/restore/restore.php @@ -1,11 +1,10 @@
    -
    +
    'buttonGrey', 'href' => helper::baseUrl() . 'config', - 'ico' => 'left', - 'value' => 'Retour' + 'value' => template::ico('left') ]); ?>
    diff --git a/core/module/config/view/script/script.php b/core/module/config/view/script/script.php index 83aaac9b..29b0446b 100644 --- a/core/module/config/view/script/script.php +++ b/core/module/config/view/script/script.php @@ -1,11 +1,10 @@
    -
    +
    'buttonGrey', 'href' => helper::baseUrl() . 'config', - 'ico' => 'left', - 'value' => 'Retour' + 'value' => template::ico('left') ]); ?>
    From e486c9344ac0ebaf90bef8c2556b6150fab09e57 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Wed, 8 Feb 2023 19:51:00 +0100 Subject: [PATCH 016/186] bloque PHP 8.2 --- index.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.php b/index.php index 9c8aedc1..a1f15346 100644 --- a/index.php +++ b/index.php @@ -25,8 +25,12 @@ session_start(); /** * Vérification de la version de PHP */ -if(version_compare(PHP_VERSION, '7.2.0', '<')) { - exit('PHP 7.2+ required.'); +if(version_compare(PHP_VERSION, '7.2.0', '<') ) { + exit('PHP 7.2+ mini required'); +} + +if ( version_compare(PHP_VERSION, '8.1.999', '>') ) { + exit('PHP 8.2 not yet supported, install PHP 7.n or PHP 8.1.n'); } /* From 1fe07405539bddca3d3bc5b6e7781bdbab778139 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Thu, 9 Feb 2023 10:36:52 +0100 Subject: [PATCH 017/186] 12204 checkup module --- CHANGES.md | 3 ++- core/include/checkup.php | 41 ++++++++++++++++++++++++++++++++++++++++ index.php | 12 ++---------- 3 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 core/include/checkup.php diff --git a/CHANGES.md b/CHANGES.md index d531beca..8e8db34f 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,8 +8,9 @@ - Le numéro de version d'une langue est le numéro de version de base de données - A l'installation ou lors de l'accès à la fenêtre des langues, les dialogues sont actualisés. - La fonction d'édition des langues de l'UI est neutralisée. +- Contrôle des prérequis, Zwii ne démarre pas si la version de PHP n'est pas conforme ou si un module PHP nécessaire n'est pas installé. ### Nouveautés : -- Paramètrage du délai de recherche automatique d'une mise à jour, tous les jours, deux jours, quatre jours, toutes les semaines, tous les mois. +- Paramétrage du délai de recherche automatique d'une mise à jour, tous les jours, deux jours, quatre jours, toutes les semaines, tous les mois. ## Version 12.2.03 - Corrections de bugs consécutifs au changement de format de languages.json diff --git a/core/include/checkup.php b/core/include/checkup.php new file mode 100644 index 00000000..4e1b6afb --- /dev/null +++ b/core/include/checkup.php @@ -0,0 +1,41 @@ +') ) { + exit('PHP 8.2 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.2 not yet supported, install PHP 7.n or PHP 8.1.n'); +} + +/** + * Check les modules installés + */ + +$e = [ + 'gd', + 'json', + 'date', + 'mbstring', + 'zip', + 'intl', + 'exif', + 'Phar', + 'fileinfo', + 'session' +]; +$m = get_loaded_extensions(); +$b = false; +foreach ($e as $k => $v) { + if (array_search($v,$m) === false) { + $b = true; + echo '

    Module ' . $v . ' manquant - Module ' . $v . ' missing.

    '; + } +} +if ($b) + exit('

    ZwiiCMS ne peut pas démarrer ; activez les extensions requises - ZwiiCMS cannot run, enabled missing extensions.

    '); diff --git a/index.php b/index.php index a1f15346..008d82f3 100644 --- a/index.php +++ b/index.php @@ -22,16 +22,8 @@ ini_set('session.use_trans_sid', FALSE); // Démarre la session session_start(); -/** - * Vérification de la version de PHP - */ -if(version_compare(PHP_VERSION, '7.2.0', '<') ) { - exit('PHP 7.2+ mini required'); -} - -if ( version_compare(PHP_VERSION, '8.1.999', '>') ) { - exit('PHP 8.2 not yet supported, install PHP 7.n or PHP 8.1.n'); -} +// Contrôle des conditions de fonctionnement +include_once('core/include/checkup.php'); /* *Localisation From 27dd70953cbbc81345be26a68fb50044e951174f Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 09:58:38 +0100 Subject: [PATCH 018/186] 12204 Add pre-required checkup php and modules Add pre-checkup to manage databases outside framework clean time date var dateUTF8 WIP remove utf8_encode --- core/core.php | 95 ++++++++++++++++++------------------- core/include/checkup.php | 4 +- core/include/pre-update.php | 23 +++++++++ index.php | 7 ++- 4 files changed, 77 insertions(+), 52 deletions(-) create mode 100644 core/include/pre-update.php diff --git a/core/core.php b/core/core.php index 0ee513d0..f8ec7c75 100644 --- a/core/core.php +++ b/core/core.php @@ -54,7 +54,7 @@ class common // URL autoupdate const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; const ZWII_UPDATE_CHANNEL = "v12"; - + // Constantes de test //const ZWII_UPDATE_URL = 'http://localhost/update/'; //const ZWII_UPDATE_CHANNEL = "test"; @@ -166,6 +166,8 @@ class common public static $dialog; // Langue de l'interface sélectionnée public static $i18nUI = 'fr_FR'; + // Langues de contenu + public static $i18nContent = 'fr_FR'; public static $languages = [ 'az_AZ' => 'Azərbaycan dili', 'bg_BG' => 'български език', @@ -206,8 +208,6 @@ class common // source: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes ]; - // Langues de contenu - public static $i18nContent = 'fr_FR'; // Zone de temps public static $timezone; @@ -315,35 +315,7 @@ class common if (isset($this->input['_COOKIE']['ZWII_CONTENT'])) { // Déterminé par le cookie self::$i18nContent = $this->input['_COOKIE']['ZWII_CONTENT']; - \setlocale(LC_TIME, self::$i18nContent . '.UTF8'); - } else { - // Absence du cookie, la langue par défaut est fr - self::$i18nContent = 'fr_FR'; - \setlocale(LC_TIME, self::$i18nContent . '.UTF8'); - } - /** - * Mise à jour à partir de la version 11.5.12 - * */ - $version = json_decode(file_get_contents('site/data/core.json'), true); - if ($version['core']['dataVersion'] < 12000) { - // Correspondance pour les dossiers de langue à convertir - $languages = [ - 'fr' => 'fr_FR', - 'en' => 'en_EN', - 'pt' => 'pt_PT' - ]; - // Convertit les dossiers vers la nouvelle structure - foreach ($languages as $key => $value) { - if ( - is_dir(self::DATA_DIR . $key) && - !is_dir(self::DATA_DIR . $value) - ) { - rename(self::DATA_DIR . $key, self::DATA_DIR . $value); - } - } - self::$i18nUI = 'fr_FR'; - self::$i18nContent = 'fr_FR'; - \setlocale(LC_TIME, self::$i18nContent . '.UTF8'); + \setlocale(LC_ALL, self::$i18nContent . '.UTF8'); } // Instanciation de la classe des entrées / sorties @@ -377,15 +349,12 @@ class common // Langue sélectionnée dans le compte self::$i18nUI = $this->getData(['user', $this->getUser('id'), 'language']); // Validation de la langue - self::$i18nUI = (empty(self::$i18nUI) || is_null(self::$i18nUI)) ? 'fr_FR' : self::$i18nUI; + self::$i18nUI = (empty(self::$i18nUI) || is_null(self::$i18nUI)) + && !file_exists(self::I18N_DIR . self::$i18nUI . '.json') + ? 'fr_FR' + : self::$i18nUI; } - // Le fichier existe-t-il ? - if (!file_exists(self::I18N_DIR . self::$i18nUI . '.json')) { - self::$i18nUI = 'fr_FR'; - } - \setlocale(LC_TIME, self::$i18nUI . '.UTF-8'); - // Stocker le cookie de langue pour l'éditeur de texte setcookie('ZWII_UI', self::$i18nUI, time() + 3600, '/', '', false, false); @@ -474,10 +443,10 @@ class common } // Mise à jour des données core selon la version du jeu de données - if ( $this->getData(['core', 'dataVersion']) < common::ZWII_DATAVERSION ) { + if ($this->getData(['core', 'dataVersion']) < common::ZWII_DATAVERSION) { include('core/include/update.inc.php'); } - + // Données de proxy $proxy = $this->getData(['config', 'proxyType']) . $this->getData(['config', 'proxyUrl']) . ':' . $this->getData(['config', 'proxyPort']); @@ -499,6 +468,7 @@ class common ); stream_context_set_default($context); } + } @@ -1299,6 +1269,35 @@ class common $zip->close(); } + /** + * Summary of dateUTF8 + * @param mixed $format + * @param mixed $date time() + * @param mixed $scope UI ou Content + * @return string Date formatée + */ + public static function showDate($format, $date, $scope = "UI") + { + $d = new DateTime(time()); + $d->format($format); + + /* + $d = datefmt_create( + self::$i18nUI, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + self::$timezone, + IntlDateFormatter::GREGORIAN, + $format + ); + exit (datefmt_format($d, $date)); + //return datefmt_format($d, $date); + */ + + } + + + // Layout remplace la classe précédente /** @@ -1957,7 +1956,7 @@ class common /** * Générer un menu pour la barre latérale * Uniquement texte - * @param onlyChildren n'affiche les sous-pages de la page actuelle + * @param $onlyChildren n'affiche les sous-pages de la page actuelle */ private function showMenuSide($onlyChildren = null) { @@ -2274,17 +2273,17 @@ class common 'help' => 'Utilisateurs', 'href' => helper::baseUrl() . 'user' ]) . ''; - + // Mise à jour automatique $today = mktime(0, 0, 0); - $checkUpdate = $this->getData(['core', 'lastAutoUpdate']); + $checkUpdate = $this->getData(['core', 'lastAutoUpdate']); // Recherche d'une mise à jour si active, si une mise à jour n'est pas déjà disponible et le délai journalier est dépassé. if ( $this->getData(['config', 'autoUpdate']) - ) { - if ( + ) { + if ( $today > $checkUpdate + $this->getData(['config', 'autoUpdateDelay', 86400]) - ) { + ) { // Dernier auto controle $this->setData(['core', 'lastAutoUpdate', $today]); if ( @@ -2297,7 +2296,7 @@ class common // Afficher le bouton : Mise à jour détectée + activée - if ($this->getData(['core', 'updateAvailable']) ) { + if ($this->getData(['core', 'updateAvailable'])) { $rightItems .= '
  • ' . template::ico('update colorRed') . '
  • '; } } diff --git a/core/include/checkup.php b/core/include/checkup.php index 4e1b6afb..d208fdf5 100644 --- a/core/include/checkup.php +++ b/core/include/checkup.php @@ -9,8 +9,8 @@ if(version_compare(PHP_VERSION, '7.2.0', '<') ) { } -if ( version_compare(PHP_VERSION, '8.1.999', '>') ) { - exit('PHP 8.2 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.2 not yet supported, install PHP 7.n or PHP 8.1.n'); +if ( version_compare(PHP_VERSION, '8.2.999', '>') ) { + exit('PHP 8.3 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.3 not yet supported, install PHP 7.n or PHP 8.1.n'); } /** diff --git a/core/include/pre-update.php b/core/include/pre-update.php new file mode 100644 index 00000000..da94079f --- /dev/null +++ b/core/include/pre-update.php @@ -0,0 +1,23 @@ + 'fr_FR', + 'en' => 'en_EN', + 'pt' => 'pt_PT' + ]; + // Convertit les dossiers vers la nouvelle structure + foreach ($languages as $key => $value) { + if ( + is_dir('site/data/' . $key) && + !is_dir('site/data/' . $value) + ) { + rename('site/data/' . $key, self::DATA_DIR . $value); + } + } +} \ No newline at end of file diff --git a/index.php b/index.php index 008d82f3..86d43daf 100644 --- a/index.php +++ b/index.php @@ -25,8 +25,11 @@ session_start(); // Contrôle des conditions de fonctionnement include_once('core/include/checkup.php'); +// Mise à jour du système de BDD +include_once('core/include/pre-update.php'); + /* - *Localisation + *Localisation par défaut * Locales : * french : free.fr @@ -34,7 +37,7 @@ include_once('core/include/checkup.php'); * fr_FR.utf8 : la majorité */ date_default_timezone_set('Europe/Paris'); -setlocale (LC_ALL,'french','fr_Fr','fr_FR.utf8'); +setlocale (LC_ALL, 'fr_FR.UTF8', 'fr_FR', 'french'); /** * Chargement des classes From 514d49bb15cfdaac3d3c024370b9b9ec772c0b46 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 09:58:55 +0100 Subject: [PATCH 019/186] 12204 Add pre-required checkup php and modules Add pre-checkup to manage databases outside framework clean time date var dateUTF8 WIP remove utf8_encode --- core/class/helper.class.php | 4 +- core/core.php | 95 ++++++++++++++++++------------------- core/include/checkup.php | 4 +- core/include/pre-update.php | 23 +++++++++ index.php | 7 ++- 5 files changed, 80 insertions(+), 53 deletions(-) create mode 100644 core/include/pre-update.php diff --git a/core/class/helper.class.php b/core/class/helper.class.php index fe2ea52d..e1d86923 100644 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -53,9 +53,11 @@ class helper public static function dateUTF8($format, $date) { require_once 'core/class/strftime/php-8.1-strftime.class.php'; - return mb_detect_encoding(\PHP81_BC\strftime($format, $date), 'UTF-8', true) + /*return mb_detect_encoding(\PHP81_BC\strftime($format, $date), 'UTF-8', true) ? \PHP81_BC\strftime($format, $date) : utf8_encode(\PHP81_BC\strftime($format, $date)); + */ + return \PHP81_BC\strftime($format, $date); } /** diff --git a/core/core.php b/core/core.php index 0ee513d0..f8ec7c75 100644 --- a/core/core.php +++ b/core/core.php @@ -54,7 +54,7 @@ class common // URL autoupdate const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/'; const ZWII_UPDATE_CHANNEL = "v12"; - + // Constantes de test //const ZWII_UPDATE_URL = 'http://localhost/update/'; //const ZWII_UPDATE_CHANNEL = "test"; @@ -166,6 +166,8 @@ class common public static $dialog; // Langue de l'interface sélectionnée public static $i18nUI = 'fr_FR'; + // Langues de contenu + public static $i18nContent = 'fr_FR'; public static $languages = [ 'az_AZ' => 'Azərbaycan dili', 'bg_BG' => 'български език', @@ -206,8 +208,6 @@ class common // source: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes ]; - // Langues de contenu - public static $i18nContent = 'fr_FR'; // Zone de temps public static $timezone; @@ -315,35 +315,7 @@ class common if (isset($this->input['_COOKIE']['ZWII_CONTENT'])) { // Déterminé par le cookie self::$i18nContent = $this->input['_COOKIE']['ZWII_CONTENT']; - \setlocale(LC_TIME, self::$i18nContent . '.UTF8'); - } else { - // Absence du cookie, la langue par défaut est fr - self::$i18nContent = 'fr_FR'; - \setlocale(LC_TIME, self::$i18nContent . '.UTF8'); - } - /** - * Mise à jour à partir de la version 11.5.12 - * */ - $version = json_decode(file_get_contents('site/data/core.json'), true); - if ($version['core']['dataVersion'] < 12000) { - // Correspondance pour les dossiers de langue à convertir - $languages = [ - 'fr' => 'fr_FR', - 'en' => 'en_EN', - 'pt' => 'pt_PT' - ]; - // Convertit les dossiers vers la nouvelle structure - foreach ($languages as $key => $value) { - if ( - is_dir(self::DATA_DIR . $key) && - !is_dir(self::DATA_DIR . $value) - ) { - rename(self::DATA_DIR . $key, self::DATA_DIR . $value); - } - } - self::$i18nUI = 'fr_FR'; - self::$i18nContent = 'fr_FR'; - \setlocale(LC_TIME, self::$i18nContent . '.UTF8'); + \setlocale(LC_ALL, self::$i18nContent . '.UTF8'); } // Instanciation de la classe des entrées / sorties @@ -377,15 +349,12 @@ class common // Langue sélectionnée dans le compte self::$i18nUI = $this->getData(['user', $this->getUser('id'), 'language']); // Validation de la langue - self::$i18nUI = (empty(self::$i18nUI) || is_null(self::$i18nUI)) ? 'fr_FR' : self::$i18nUI; + self::$i18nUI = (empty(self::$i18nUI) || is_null(self::$i18nUI)) + && !file_exists(self::I18N_DIR . self::$i18nUI . '.json') + ? 'fr_FR' + : self::$i18nUI; } - // Le fichier existe-t-il ? - if (!file_exists(self::I18N_DIR . self::$i18nUI . '.json')) { - self::$i18nUI = 'fr_FR'; - } - \setlocale(LC_TIME, self::$i18nUI . '.UTF-8'); - // Stocker le cookie de langue pour l'éditeur de texte setcookie('ZWII_UI', self::$i18nUI, time() + 3600, '/', '', false, false); @@ -474,10 +443,10 @@ class common } // Mise à jour des données core selon la version du jeu de données - if ( $this->getData(['core', 'dataVersion']) < common::ZWII_DATAVERSION ) { + if ($this->getData(['core', 'dataVersion']) < common::ZWII_DATAVERSION) { include('core/include/update.inc.php'); } - + // Données de proxy $proxy = $this->getData(['config', 'proxyType']) . $this->getData(['config', 'proxyUrl']) . ':' . $this->getData(['config', 'proxyPort']); @@ -499,6 +468,7 @@ class common ); stream_context_set_default($context); } + } @@ -1299,6 +1269,35 @@ class common $zip->close(); } + /** + * Summary of dateUTF8 + * @param mixed $format + * @param mixed $date time() + * @param mixed $scope UI ou Content + * @return string Date formatée + */ + public static function showDate($format, $date, $scope = "UI") + { + $d = new DateTime(time()); + $d->format($format); + + /* + $d = datefmt_create( + self::$i18nUI, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + self::$timezone, + IntlDateFormatter::GREGORIAN, + $format + ); + exit (datefmt_format($d, $date)); + //return datefmt_format($d, $date); + */ + + } + + + // Layout remplace la classe précédente /** @@ -1957,7 +1956,7 @@ class common /** * Générer un menu pour la barre latérale * Uniquement texte - * @param onlyChildren n'affiche les sous-pages de la page actuelle + * @param $onlyChildren n'affiche les sous-pages de la page actuelle */ private function showMenuSide($onlyChildren = null) { @@ -2274,17 +2273,17 @@ class common 'help' => 'Utilisateurs', 'href' => helper::baseUrl() . 'user' ]) . ''; - + // Mise à jour automatique $today = mktime(0, 0, 0); - $checkUpdate = $this->getData(['core', 'lastAutoUpdate']); + $checkUpdate = $this->getData(['core', 'lastAutoUpdate']); // Recherche d'une mise à jour si active, si une mise à jour n'est pas déjà disponible et le délai journalier est dépassé. if ( $this->getData(['config', 'autoUpdate']) - ) { - if ( + ) { + if ( $today > $checkUpdate + $this->getData(['config', 'autoUpdateDelay', 86400]) - ) { + ) { // Dernier auto controle $this->setData(['core', 'lastAutoUpdate', $today]); if ( @@ -2297,7 +2296,7 @@ class common // Afficher le bouton : Mise à jour détectée + activée - if ($this->getData(['core', 'updateAvailable']) ) { + if ($this->getData(['core', 'updateAvailable'])) { $rightItems .= '
  • ' . template::ico('update colorRed') . '
  • '; } } diff --git a/core/include/checkup.php b/core/include/checkup.php index 4e1b6afb..d208fdf5 100644 --- a/core/include/checkup.php +++ b/core/include/checkup.php @@ -9,8 +9,8 @@ if(version_compare(PHP_VERSION, '7.2.0', '<') ) { } -if ( version_compare(PHP_VERSION, '8.1.999', '>') ) { - exit('PHP 8.2 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.2 not yet supported, install PHP 7.n or PHP 8.1.n'); +if ( version_compare(PHP_VERSION, '8.2.999', '>') ) { + exit('PHP 8.3 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.3 not yet supported, install PHP 7.n or PHP 8.1.n'); } /** diff --git a/core/include/pre-update.php b/core/include/pre-update.php new file mode 100644 index 00000000..da94079f --- /dev/null +++ b/core/include/pre-update.php @@ -0,0 +1,23 @@ + 'fr_FR', + 'en' => 'en_EN', + 'pt' => 'pt_PT' + ]; + // Convertit les dossiers vers la nouvelle structure + foreach ($languages as $key => $value) { + if ( + is_dir('site/data/' . $key) && + !is_dir('site/data/' . $value) + ) { + rename('site/data/' . $key, self::DATA_DIR . $value); + } + } +} \ No newline at end of file diff --git a/index.php b/index.php index 008d82f3..86d43daf 100644 --- a/index.php +++ b/index.php @@ -25,8 +25,11 @@ session_start(); // Contrôle des conditions de fonctionnement include_once('core/include/checkup.php'); +// Mise à jour du système de BDD +include_once('core/include/pre-update.php'); + /* - *Localisation + *Localisation par défaut * Locales : * french : free.fr @@ -34,7 +37,7 @@ include_once('core/include/checkup.php'); * fr_FR.utf8 : la majorité */ date_default_timezone_set('Europe/Paris'); -setlocale (LC_ALL,'french','fr_Fr','fr_FR.utf8'); +setlocale (LC_ALL, 'fr_FR.UTF8', 'fr_FR', 'french'); /** * Chargement des classes From 50a664638d67f9aac5379c3da8c4bab51aecb532 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 10:08:33 +0100 Subject: [PATCH 020/186] 12204 fix pre-update --- core/include/pre-update.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/pre-update.php b/core/include/pre-update.php index da94079f..458f3083 100644 --- a/core/include/pre-update.php +++ b/core/include/pre-update.php @@ -17,7 +17,7 @@ if ($version['core']['dataVersion'] < 12000) { is_dir('site/data/' . $key) && !is_dir('site/data/' . $value) ) { - rename('site/data/' . $key, self::DATA_DIR . $value); + rename('site/data/' . $key, 'site/data/' . $value); } } } \ No newline at end of file From eb9a894c0a9a63fd2f1e89466dbce221f5eb577f Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 10:29:00 +0100 Subject: [PATCH 021/186] =?UTF-8?q?12204=20mise=20=C3=A0=20jour=20depuis?= =?UTF-8?q?=2011.5.12=20sleep(2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/include/pre-update.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/include/pre-update.php b/core/include/pre-update.php index 458f3083..3fae170e 100644 --- a/core/include/pre-update.php +++ b/core/include/pre-update.php @@ -1,7 +1,7 @@ Date: Fri, 10 Feb 2023 10:41:57 +0100 Subject: [PATCH 022/186] =?UTF-8?q?compatibilit=C3=A9=20php=208.1=20max?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/include/checkup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/checkup.php b/core/include/checkup.php index d208fdf5..c362fcb3 100644 --- a/core/include/checkup.php +++ b/core/include/checkup.php @@ -9,7 +9,7 @@ if(version_compare(PHP_VERSION, '7.2.0', '<') ) { } -if ( version_compare(PHP_VERSION, '8.2.999', '>') ) { +if ( version_compare(PHP_VERSION, '8.1.999', '>') ) { exit('PHP 8.3 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.3 not yet supported, install PHP 7.n or PHP 8.1.n'); } From bc43689d41ad97e542254a272e6839d589908a3c Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 10:42:42 +0100 Subject: [PATCH 023/186] checkup exit message --- core/include/checkup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/checkup.php b/core/include/checkup.php index c362fcb3..4e1b6afb 100644 --- a/core/include/checkup.php +++ b/core/include/checkup.php @@ -10,7 +10,7 @@ if(version_compare(PHP_VERSION, '7.2.0', '<') ) { } if ( version_compare(PHP_VERSION, '8.1.999', '>') ) { - exit('PHP 8.3 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.3 not yet supported, install PHP 7.n or PHP 8.1.n'); + exit('PHP 8.2 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.2 not yet supported, install PHP 7.n or PHP 8.1.n'); } /** From c48da3d7f9bcabb1e8966bec6cd455a11e26c564 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 11:25:05 +0100 Subject: [PATCH 024/186] Responsive File Manage imagecreatetruecolor imagefilledrectangle required int and not float UTF8_encode --- core/vendor/filemanager/UploadHandler.php | 1 + core/vendor/filemanager/include/php_image_magician.php | 10 +++++----- core/vendor/filemanager/include/utils.php | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/vendor/filemanager/UploadHandler.php b/core/vendor/filemanager/UploadHandler.php index 2f685593..98f8ffbc 100644 --- a/core/vendor/filemanager/UploadHandler.php +++ b/core/vendor/filemanager/UploadHandler.php @@ -14,6 +14,7 @@ class UploadHandler { protected $options; + protected $response; // PHP File Upload error message codes: // http://php.net/manual/en/features.file-upload.errors.php diff --git a/core/vendor/filemanager/include/php_image_magician.php b/core/vendor/filemanager/include/php_image_magician.php index 9ec8e001..43d1b545 100644 --- a/core/vendor/filemanager/include/php_image_magician.php +++ b/core/vendor/filemanager/include/php_image_magician.php @@ -353,8 +353,8 @@ class imageLib { // *** Get optimal width and height - based on $option $dimensionsArray = $this->getDimensions($newWidth, $newHeight, $option); - $optimalWidth = $dimensionsArray['optimalWidth']; - $optimalHeight = $dimensionsArray['optimalHeight']; + $optimalWidth = (int) $dimensionsArray['optimalWidth']; + $optimalHeight = (int) $dimensionsArray['optimalHeight']; // *** Resample - create image canvas of x, y size $this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight); @@ -463,7 +463,7 @@ class imageLib { else { $color = imagecolorallocate($im, $this->fillColorArray['r'], $this->fillColorArray['g'], $this->fillColorArray['b']); - imagefilledrectangle($im, 0, 0, $width, $height, $color); + imagefilledrectangle($im, 0, 0, (int)$width, (int)$height, $color); } } @@ -483,8 +483,8 @@ class imageLib { // *** Get cropping co-ordinates $cropArray = $this->getCropPlacing($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos); - $cropStartX = $cropArray['x']; - $cropStartY = $cropArray['y']; + $cropStartX = (int)$cropArray['x']; + $cropStartY = (int)$cropArray['y']; // *** Crop this bad boy $crop = imagecreatetruecolor($newWidth, $newHeight); diff --git a/core/vendor/filemanager/include/utils.php b/core/vendor/filemanager/include/utils.php index 9275eaaf..60cd4a61 100644 --- a/core/vendor/filemanager/include/utils.php +++ b/core/vendor/filemanager/include/utils.php @@ -735,8 +735,9 @@ function fix_filename($str, $config, $is_folder = false) } if ($config['transliteration']) { + // Le site est en UTF8 if (!mb_detect_encoding($str, 'UTF-8', true)) { - $str = utf8_encode($str); + $str = mb_convert_encoding($str, 'UTF-8', mb_list_encodings()); } if (function_exists('transliterator_transliterate')) { $str = transliterator_transliterate('Any-Latin; Latin-ASCII', $str); From 056ce8421a1851d92eee292f7e6cc528a70f4e4c Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 11:25:42 +0100 Subject: [PATCH 025/186] utf8 encode replacement --- 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 e1d86923..d5995ab5 100644 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -57,7 +57,7 @@ class helper ? \PHP81_BC\strftime($format, $date) : utf8_encode(\PHP81_BC\strftime($format, $date)); */ - return \PHP81_BC\strftime($format, $date); + return mb_convert_encoding(\PHP81_BC\strftime($format, $date), 'UTF-8', mb_list_encodings()); } /** From c8a546f6e994f049cfb7e092b32cea6cdb87e447 Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 11:25:52 +0100 Subject: [PATCH 026/186] php 8.2 testing --- core/include/checkup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/checkup.php b/core/include/checkup.php index 4e1b6afb..ecb9ea63 100644 --- a/core/include/checkup.php +++ b/core/include/checkup.php @@ -9,7 +9,7 @@ if(version_compare(PHP_VERSION, '7.2.0', '<') ) { } -if ( version_compare(PHP_VERSION, '8.1.999', '>') ) { +if ( version_compare(PHP_VERSION, '8.2.999', '>') ) { exit('PHP 8.2 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.2 not yet supported, install PHP 7.n or PHP 8.1.n'); } From 566f123c2dd43c4e783ed2bf197d05df7f210c5d Mon Sep 17 00:00:00 2001 From: Fred Tempez Date: Fri, 10 Feb 2023 14:15:01 +0100 Subject: [PATCH 027/186] 12204 Nettoyage de commentaires --- core/class/helper.class.php | 4 - module/download/changes.md | 10 + module/download/download.php | 1345 +++++++++++++++++ module/download/enum.json | 1 + module/download/ressource/feed-icon-16.gif | Bin 0 -> 652 bytes module/download/vendor/FeedWriter/ATOM.php | 38 + module/download/vendor/FeedWriter/Feed.php | 1017 +++++++++++++ .../FeedWriter/InvalidOperationException.php | 33 + module/download/vendor/FeedWriter/Item.php | 413 +++++ module/download/vendor/FeedWriter/README.md | 42 + module/download/vendor/FeedWriter/RSS1.php | 37 + module/download/vendor/FeedWriter/RSS2.php | 37 + module/download/view/add/add.css | 18 + module/download/view/add/add.js.php | 54 + module/download/view/add/add.php | 184 +++ .../download/view/categories/categories.css | 18 + .../view/categories/categories.js.php | 23 + .../download/view/categories/categories.php | 40 + .../view/categoryEdit/categoryEdit.css | 18 + .../view/categoryEdit/categoryEdit.php | 30 + module/download/view/comment/comment.css | 18 + module/download/view/comment/comment.js.php | 62 + module/download/view/comment/comment.php | 22 + module/download/view/config/config.css | 18 + module/download/view/config/config.js.php | 21 + module/download/view/config/config.php | 40 + module/download/view/edit/edit.css | 18 + module/download/view/edit/edit.js.php | 77 + module/download/view/edit/edit.php | 195 +++ module/download/view/index/index.css | 69 + module/download/view/index/index.php | 65 + module/download/view/item/item.css | 67 + module/download/view/item/item.js.php | 50 + module/download/view/item/item.php | 226 +++ module/download/view/list/list.php | 1 + module/download/view/rss/rss.php | 1 + module/download/view/setup/setup.css | 18 + module/download/view/setup/setup.php | 47 + module/download/view/stats/stats.css | 18 + module/download/view/stats/stats.js.php | 22 + module/download/view/stats/stats.php | 36 + module/registration/changes.md | 2 + module/registration/registration.php | 388 +++++ module/registration/view/config/config.css | 15 + module/registration/view/config/config.php | 92 ++ module/registration/view/edit/edit.css | 16 + module/registration/view/edit/edit.js.php | 19 + module/registration/view/edit/edit.php | 111 ++ module/registration/view/index/index.js.php | 47 + module/registration/view/index/index.php | 82 + module/registration/view/user/user.css | 16 + module/registration/view/user/user.js.php | 21 + module/registration/view/user/user.php | 15 + .../registration/view/validate/validate.php | 2 + module/slider/enum.json | 1 + module/slider/slider.php | 460 ++++++ module/slider/vendor/slider/inc.json | 3 + module/slider/vendor/slider/slider.js | 10 + module/slider/view/config/config.css | 22 + module/slider/view/config/config.php | 54 + module/slider/view/index/black.gif | Bin 0 -> 359 bytes module/slider/view/index/index.css | 236 +++ module/slider/view/index/index.js.php | 61 + module/slider/view/index/index.php | 26 + module/slider/view/index/white.gif | Bin 0 -> 1219 bytes module/slider/view/theme/theme.css | 17 + module/slider/view/theme/theme.js.php | 51 + module/slider/view/theme/theme.php | 78 + module/slider/view/update/update.css | 22 + module/slider/view/update/update.js.php | 52 + module/slider/view/update/update.php | 36 + 71 files changed, 6404 insertions(+), 4 deletions(-) create mode 100644 module/download/changes.md create mode 100644 module/download/download.php create mode 100644 module/download/enum.json create mode 100644 module/download/ressource/feed-icon-16.gif create mode 100644 module/download/vendor/FeedWriter/ATOM.php create mode 100644 module/download/vendor/FeedWriter/Feed.php create mode 100644 module/download/vendor/FeedWriter/InvalidOperationException.php create mode 100644 module/download/vendor/FeedWriter/Item.php create mode 100644 module/download/vendor/FeedWriter/README.md create mode 100644 module/download/vendor/FeedWriter/RSS1.php create mode 100644 module/download/vendor/FeedWriter/RSS2.php create mode 100644 module/download/view/add/add.css create mode 100644 module/download/view/add/add.js.php create mode 100644 module/download/view/add/add.php create mode 100644 module/download/view/categories/categories.css create mode 100644 module/download/view/categories/categories.js.php create mode 100644 module/download/view/categories/categories.php create mode 100644 module/download/view/categoryEdit/categoryEdit.css create mode 100644 module/download/view/categoryEdit/categoryEdit.php create mode 100644 module/download/view/comment/comment.css create mode 100644 module/download/view/comment/comment.js.php create mode 100644 module/download/view/comment/comment.php create mode 100644 module/download/view/config/config.css create mode 100644 module/download/view/config/config.js.php create mode 100644 module/download/view/config/config.php create mode 100644 module/download/view/edit/edit.css create mode 100644 module/download/view/edit/edit.js.php create mode 100644 module/download/view/edit/edit.php create mode 100644 module/download/view/index/index.css create mode 100644 module/download/view/index/index.php create mode 100644 module/download/view/item/item.css create mode 100644 module/download/view/item/item.js.php create mode 100644 module/download/view/item/item.php create mode 100644 module/download/view/list/list.php create mode 100644 module/download/view/rss/rss.php create mode 100644 module/download/view/setup/setup.css create mode 100644 module/download/view/setup/setup.php create mode 100644 module/download/view/stats/stats.css create mode 100644 module/download/view/stats/stats.js.php create mode 100644 module/download/view/stats/stats.php create mode 100644 module/registration/changes.md create mode 100644 module/registration/registration.php create mode 100644 module/registration/view/config/config.css create mode 100644 module/registration/view/config/config.php create mode 100644 module/registration/view/edit/edit.css create mode 100644 module/registration/view/edit/edit.js.php create mode 100644 module/registration/view/edit/edit.php create mode 100644 module/registration/view/index/index.js.php create mode 100644 module/registration/view/index/index.php create mode 100644 module/registration/view/user/user.css create mode 100644 module/registration/view/user/user.js.php create mode 100644 module/registration/view/user/user.php create mode 100644 module/registration/view/validate/validate.php create mode 100644 module/slider/enum.json create mode 100644 module/slider/slider.php create mode 100644 module/slider/vendor/slider/inc.json create mode 100644 module/slider/vendor/slider/slider.js create mode 100644 module/slider/view/config/config.css create mode 100644 module/slider/view/config/config.php create mode 100644 module/slider/view/index/black.gif create mode 100644 module/slider/view/index/index.css create mode 100644 module/slider/view/index/index.js.php create mode 100644 module/slider/view/index/index.php create mode 100644 module/slider/view/index/white.gif create mode 100644 module/slider/view/theme/theme.css create mode 100644 module/slider/view/theme/theme.js.php create mode 100644 module/slider/view/theme/theme.php create mode 100644 module/slider/view/update/update.css create mode 100644 module/slider/view/update/update.js.php create mode 100644 module/slider/view/update/update.php diff --git a/core/class/helper.class.php b/core/class/helper.class.php index d5995ab5..efc39b64 100644 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -53,10 +53,6 @@ class helper public static function dateUTF8($format, $date) { require_once 'core/class/strftime/php-8.1-strftime.class.php'; - /*return mb_detect_encoding(\PHP81_BC\strftime($format, $date), 'UTF-8', true) - ? \PHP81_BC\strftime($format, $date) - : utf8_encode(\PHP81_BC\strftime($format, $date)); - */ return mb_convert_encoding(\PHP81_BC\strftime($format, $date), 'UTF-8', mb_list_encodings()); } diff --git a/module/download/changes.md b/module/download/changes.md new file mode 100644 index 00000000..5a7e05e2 --- /dev/null +++ b/module/download/changes.md @@ -0,0 +1,10 @@ +# Version 3.2 +- Compatibilité PHP 8.2 +# Version 3.1 +- Liste export du catalogue non json +# Version 3 +- Uniformisation interface graphique +- Corrige un bug de création de catégorie +# Version 2.6 +- Saisie obligatoire d'un contenu +- Nouvelle structure 'posts' plutôt que 'items' pour permettre la recherche dans les descriptions avec le module Search diff --git a/module/download/download.php b/module/download/download.php new file mode 100644 index 00000000..60fe60e1 --- /dev/null +++ b/module/download/download.php @@ -0,0 +1,1345 @@ + + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +class download extends common +{ + + const VERSION = '3.2'; + const REALNAME = 'Téléchargement'; + const DELETE = true; + const UPDATE = '0.0'; + const DATADIRECTORY = ''; // Contenu localisé inclus par défaut (page.json et module.json) + + // Constantes du module + const EDIT_OWNER = 'owner'; + const EDIT_GROUP = 'group'; + const EDIT_ALL = 'all'; + + public static $actions = [ + 'add' => self::GROUP_MODERATOR, + 'comment' => self::GROUP_MODERATOR, + 'commentApprove' => self::GROUP_MODERATOR, + 'commentDelete' => self::GROUP_MODERATOR, + 'commentDeleteAll' => self::GROUP_MODERATOR, + 'config' => self::GROUP_MODERATOR, + 'setup' => self::GROUP_MODERATOR, + 'delete' => self::GROUP_MODERATOR, + 'edit' => self::GROUP_MODERATOR, + 'stats' => self::GROUP_MODERATOR, + 'statsDeleteAll' => self::GROUP_MODERATOR, + 'categories' => self::GROUP_MODERATOR, + 'categoryEdit' => self::GROUP_MODERATOR, + 'categoryDelete' => self::GROUP_MODERATOR, + 'index' => self::GROUP_VISITOR, + 'rss' => self::GROUP_VISITOR, + 'downloadFile' => self::GROUP_VISITOR, + 'list' => self::GROUP_VISITOR + ]; + + public static $items = []; + + // Signature de l'item + public static $itemSignature = ''; + + // Signature du commentaire + public static $editCommentSignature = ''; + + public static $comments = []; + + public static $nbCommentsApproved = 0; + + public static $commentsDelete; + + // Signatures des commentaires déjà saisis + public static $commentsSignature = []; + + public static $pages; + + // Nombre de téléchargements + public static $statSum = 0; + + public static $states = [ + false => 'Brouillon', + true => 'Publié' + ]; + + // Liste des catégories + public static $categories = []; + + public static $allCategories = ''; + + public static $pictureSizes = [ + '20' => 'Très petite', + '30' => 'Petite', + '40' => 'Grande', + '50' => 'Très Grande', + '100' => 'Pleine largeur', + ]; + + public static $picturePositions = [ + 'left' => 'À gauche', + 'right' => 'À droite ', + ]; + + //Paramètre longueur maximale des commentaires en nb de caractères + public static $commentLength = [ + '500' => '500', + '1000' => '1000', + '2000' => '2000', + '5000' => '5000', + '10000' => '10000' + ]; + + // Nombre d'objets par page + public static $ItemsList = [ + 4 => '4 articles', + 8 => '8 articles', + 12 => '12 articles', + 16 => '16 articles', + 22 => '22 articles' + ]; + + // Permissions d'un item + public static $itemConsent = [ + self::EDIT_ALL => 'Tous les groupes', + self::EDIT_GROUP => 'Groupe du propriétaire', + self::EDIT_OWNER => 'Propriétaire' + ]; + + + public static $licenses = [ + 'none' => 'Non définie', + 'cc' => 'Licence libre Creative Common, partage autorisé', + 'gnu' => 'Licence libre GNU, partage autorisé', + 'mit' => 'Licence libre MIT, partage autorisé', + 'owner' => 'Licence Propriétaire' + ]; + + public static $ressourceType = [ + 'file' => 'Fichier', + 'url' => 'URL', + 'content' => 'Intégrée' + ]; + + public static $users = []; + + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() + { + if ($this->getData(['module', $this->getUrl(0), 'config', 'versionData'])) { + // Version 1.2 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '1.1', '<')) { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 8]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData', '1.2']); + } + // Version 2.6 + // Modification de structure du module download + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '2.6', '<')) { + $tempData = $this->getData(['module', $this->getUrl(0), 'items']); + $this->setData(['module', $this->getUrl(0), 'posts', $tempData]); + $this->deleteData(['module', $this->getUrl(0), 'items']); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData', '2.6']); + } + } else { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 8]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData', self::VERSION]); + $this->setData(['module', $this->getUrl(0), 'categories', []]); + } + + } + + /** + * Flux RSS + */ + public function rss() + { + // Inclure les classes + include_once 'module/download/vendor/FeedWriter/Item.php'; + include_once 'module/download/vendor/FeedWriter/Feed.php'; + include_once 'module/download/vendor/FeedWriter/RSS2.php'; + include_once 'module/download/vendor/FeedWriter/InvalidOperationException.php'; + + date_default_timezone_set('UTC'); + $feeds = new \FeedWriter\RSS2(); + + // En-tête + $feeds->setTitle($this->getData(['page', $this->getUrl(0), 'title'])); + $feeds->setLink(helper::baseUrl() . $this->getUrl(0)); + $feeds->setDescription($this->getData(['page', $this->getUrl(0), 'metaDescription'])); + $feeds->setChannelElement('language', 'fr-FR'); + $feeds->setDate(date('r', time())); + $feeds->addGenerator(); + // Corps des items + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC'); + foreach ($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if ($itemPublishedOn <= time() and $itemIdsStates[$itemId]) { + // Miniature + $parts = explode('/', $this->getData(['module', $this->getUrl(0), 'posts', $itemId, 'thumb'])); + $thumb = str_replace($parts[(count($parts) - 1)], 'mini_' . $parts[(count($parts) - 1)], $this->getData(['module', $this->getUrl(0), 'posts', $itemId, 'thumb'])); + // Créer les items du flux + $newsitem = $feeds->createNewItem(); + // Signature de l'item + $author = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $itemId, 'userId'])); + $newsitem->addElementArray([ + 'title' => $this->getData(['module', $this->getUrl(0), 'posts', $itemId, 'title']), + 'link' => helper::baseUrl() . $this->getUrl(0) . '/' . $itemId, + 'description' => '' . $this->getData(['module', $this->getUrl(0), 'posts', $itemId, 'title'])
+					. '' . + $this->getData(['module', $this->getUrl(0), 'posts', $itemId, 'content']), + ]); + $newsitem->setAuthor($author, 'no@mail.com'); + $newsitem->setId(helper::baseUrl() . $this->getUrl(0) . '/' . $itemId); + $newsitem->setDate(date('r', $this->getData(['module', $this->getUrl(0), 'posts', $itemId, 'publishedOn']))); + $imageData = getimagesize(helper::baseUrl(false) . self::FILE_DIR . 'thumb/' . $thumb); + $newsitem->addEnclosure( + helper::baseUrl(false) . self::FILE_DIR . 'thumb/' . $thumb, + $imageData[0] * $imageData[1], + $imageData['mime'] + ); + $feeds->addItem($newsitem); + } + } + + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_RSS, + 'content' => $feeds->generateFeed(), + 'view' => 'rss' + ]); + } + + /** + * Édition + */ + public function add() + { + // Soumission du formulaire + if ($this->isPost()) { + // Modification de l'userId + if ($this->getUser('group') === self::GROUP_ADMIN) { + $newuserid = $this->getInput('downloadAddUserId', helper::FILTER_STRING_SHORT, true); + } else { + $newuserid = $this->getUser('id'); + } + // Incrémente l'id de l'item + $itemId = helper::increment($this->getInput('downloadAddTitle', helper::FILTER_ID), $this->getData(['page'])); + $itemId = helper::increment($itemId, (array) $this->getData(['module', $this->getUrl(0)])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + // Crée l'item + $this->setData([ + 'module', + $this->getUrl(0), + 'posts', + $itemId, + [ + 'comment' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment']), + 'content' => $this->getInput('downloadAddContent', null, true), + 'thumb' => $this->getInput('downloadAddThumb', helper::FILTER_STRING_SHORT, true), + 'ressourceType' => $this->getInput('downloadAddRessourceType', helper::FILTER_STRING_SHORT), + 'file' => $this->getInput('downloadAddFile', helper::FILTER_STRING_SHORT), + 'url' => $this->getInput('downloadAddUrl', helper::FILTER_STRING_SHORT), + 'version' => $this->getInput('downloadAddVersion', helper::FILTER_STRING_SHORT), + 'versionDate' => $this->getInput('downloadAddversionDate', helper::FILTER_DATETIME), + 'license' => $this->getInput('downloadAddLicense', helper::FILTER_STRING_SHORT, true), + 'category' => $this->getInput('downloadAddCategorie', helper::FILTER_STRING_SHORT), + 'author' => $this->getInput('downloadAddAuthor', helper::FILTER_STRING_SHORT, true), + 'stats' => [], + 'publishedOn' => $this->getInput('downloadAddPublishedOn', helper::FILTER_DATETIME, true), + 'state' => $this->getInput('downloadAddState', helper::FILTER_BOOLEAN), + 'title' => $this->getInput('downloadAddTitle', helper::FILTER_STRING_SHORT, true), + 'userId' => $newuserid, + 'editConsent' => $this->getInput('downloadAddConsent') === self::EDIT_GROUP ? $this->getUser('group') : $this->getInput('downloadAddConsent'), + 'commentMaxlength' => $this->getInput('downloadAddCommentMaxlength'), + 'commentApproved' => $this->getInput('downloadAddCommentApproved', helper::FILTER_BOOLEAN), + 'commentClose' => $this->getInput('downloadAddCommentClose', helper::FILTER_BOOLEAN), + 'commentNotification' => $this->getInput('downloadAddCommentNotification', helper::FILTER_BOOLEAN), + 'commentGroupNotification' => $this->getInput('downloadAddCommentGroupNotification', helper::FILTER_INT) + ] + ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Nouvel item créé', + 'state' => true + ]); + } + // Liste des utilisateurs + self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname'); + ksort(self::$users); + foreach (self::$users as $userId => &$userFirstname) { + $userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']); + } + unset($userFirstname); + // Liste des catégories + /* + if ($this->getData(['module', $this->getUrl(0), 'categories' ]) === NULL OR + $this->getData(['module', $this->getUrl(0), 'categories' ]) === [] ) { + // Stocke une catégorie vide + $this->setData(['module', + $this->getUrl(0), + 'categories', + 'none', + 'Aucune' + ]); + // Alimente le formulaire + self::$categories = ['none' => 'Aucune']; + } else { + self::$categories = $this->getData(['module', $this->getUrl(0), 'categories' ]); + } + arsort(self::$categories); + */ + if ($this->getData(['module', $this->getUrl(0), 'categories']) !== NULL) { + self::$categories = $this->getData(['module', $this->getUrl(0), 'categories']); + arsort(self::$categories); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Nouvelle ressource', + 'vendor' => [ + 'flatpickr', + 'tinymce' + ], + 'view' => 'add' + ]); + } + + /** + * Liste des commentaires + */ + public function comment() + { + $comments = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment']); + self::$commentsDelete = template::button('downloadCommentDeleteAll', [ + 'class' => 'downloadCommentDeleteAll buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentDeleteAll/' . $this->getUrl(2) . '/' . $_SESSION['csrf'], + 'ico' => 'cancel', + 'value' => 'Tout effacer' + ]); + // Ids des commentaires par ordre de création + $commentIds = array_keys(helper::arrayCollumn($comments, 'createdOn', 'SORT_DESC')); + // Pagination + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // Commentaires en fonction de la pagination + for ($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Met en forme le tableau + $comment = $comments[$commentIds[$i]]; + // Bouton d'approbation + $buttonApproval = ''; + // Compatibilité avec les commentaires des versions précédentes, les valider + $comment['approval'] = array_key_exists('approval', $comment) === false ? true : $comment['approval']; + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentApproved']) === true) { + $buttonApproval = template::button('downloadCommentApproved' . $commentIds[$i], [ + 'class' => $comment['approval'] === true ? 'downloadCommentRejected buttonGreen' : 'downloadCommentApproved buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentApprove/' . $this->getUrl(2) . '/' . $commentIds[$i] . '/' . $_SESSION['csrf'], + 'value' => $comment['approval'] === true ? 'A' : 'R' + ]); + } + self::$comments[] = [ + helper::dateUTF8('%d %B %Y - %H:%M',$comment['createdOn']), + $comment['content'], + $comment['userId'] ? $this->getData(['user', $comment['userId'], 'firstname']) . ' ' . $this->getData(['user', $comment['userId'], 'lastname']) : $comment['author'], + $buttonApproval, + template::button('downloadCommentDelete' . $commentIds[$i], [ + 'class' => 'downloadCommentDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentDelete/' . $this->getUrl(2) . '/' . $commentIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + ]; + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Gestion des commentaires : ' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'title']), + 'view' => 'comment' + ]); + } + + /** + * Suppression de commentaire + */ + public function commentDelete() + { + // Le commentaire n'existe pas + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(4) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action interdite' + ]); + } + // Suppression + else { + $this->deleteData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment/' . $this->getUrl(2), + 'notification' => 'Commentaire supprimé', + 'state' => true + ]); + } + } + + /** + * Suppression de tous les commentaires de l'item $this->getUrl(2) + */ + public function commentDeleteAll() + { + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action interdite' + ]); + } + // Suppression + else { + $this->setData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', []]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment', + 'notification' => 'Commentaires supprimés', + 'state' => true + ]); + } + } + + /** + * Approbation oou désapprobation de commentaire + */ + public function commentApprove() + { + // Le commentaire n'existe pas + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(4) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action interdite' + ]); + } + // Inversion du statut + else { + $approved = !$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3), 'approval']); + $this->setData([ + 'module', $this->getUrl(0), + 'posts', $this->getUrl(2), + 'comment', $this->getUrl(3), + [ + 'author' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3), 'author']), + 'content' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3), 'content']), + 'createdOn' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3), 'createdOn']), + 'userId' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment', $this->getUrl(3), 'userId']), + 'approval' => $approved + ] + ]); + + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment/' . $this->getUrl(2), + 'notification' => $approved ? 'Commentaire approuvé' : 'Commentaire rejeté', + 'state' => $approved + ]); + } + } + + /** + * Configuration + */ + public function config() + { + // Mise à jour des données de module + $this->update(); + + // Ids des items par ordre de publication + $itemIds = array_keys(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC')); + // Gestion des droits d'accès + $filterData = []; + foreach ($itemIds as $key => $value) { + if ( + ( // Propriétaire + $this->getData([ + 'module', $this->getUrl(0), + 'posts', + $value, + 'editConsent' + ]) === self::EDIT_OWNER + and ($this->getData([ + 'module', $this->getUrl(0), + 'posts', + $value, + 'userId' + ]) === $this->getUser('id') + or $this->getUser('group') === self::GROUP_ADMIN) + ) + + or ( + // Groupe + $this->getData([ + 'module', $this->getUrl(0), + 'posts', + $value, + 'editConsent' + ]) !== self::EDIT_OWNER + and $this->getUser('group') >= $this->getData([ + 'module', + $this->getUrl(0), + 'posts', + $value, + 'editConsent' + ]) + ) + or ( + // Tout le monde + $this->getData([ + 'module', $this->getUrl(0), + 'posts', + $value, + 'editConsent' + ]) === self::EDIT_ALL + ) + ) { + $filterData[] = $value; + } + } + $itemIds = $filterData; + // Filtrage des catégories selon le second élément de l'URL si valide + if ( + $this->getUrl(2) + and array_key_exists( + $this->getUrl(2), + $this->getData([ + 'module', + $this->getUrl(0), + 'categories' + ]) + ) + ) { + $filterData = []; + foreach ($itemIds as $key => $value) { + if ($this->getData(['module', $this->getUrl(0), 'posts', $value, 'category']) === $this->getUrl(2)) { + $filterData[] = $value; + } + } + $itemIds = $filterData; + } + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // items en fonction de la pagination + for ($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Nombre de commentaires à approuver et approuvés + $approvals = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'comment']), 'approval', 'SORT_DESC'); + if (is_array($approvals)) { + $a = array_values($approvals); + $toApprove = count(array_keys($a, false)); + $approved = count(array_keys($a, true)); + } else { + $toApprove = 0; + $approved = count($this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'comment'])); + } + // Met en forme le tableau + $date = helper::dateUTF8('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'versionDate'])); + $stat = count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'stats']), 'time')) === 0 + ? '0' + : '' . + count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'stats']), 'time')) . + ''; + // Lien toutes les catégories quand le filtre est actif + if ($this->getUrl(2)) { + self::$allCategories = '(toutes)'; + } + // Tableau des items + self::$items[] = [ + '' . + $this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'title']) . + '', + '' . + $this->getData(['module', $this->getUrl(0), 'categories', $this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'category'])]) . + '', + $this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'version']), + //$date .' à '. $heure, + $date, + $stat, + self::$states[$this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i], 'state'])], + // Bouton pour afficher les commentaires de l'item + template::button('downloadConfigComment' . $itemIds[$i], [ + 'class' => ($toApprove || $approved) > 0 ? 'buttonBlue' : 'buttonGrey', + 'href' => ($toApprove || $approved) > 0 ? helper::baseUrl() . $this->getUrl(0) . '/comment/' . $itemIds[$i] : '', + 'value' => $toApprove > 0 ? $toApprove . '/' . $approved : $approved + ]), + template::button('downloadConfigEdit' . $itemIds[$i], [ + 'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $itemIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('pencil') + ]), + template::button('downloadConfigDelete' . $itemIds[$i], [ + 'class' => 'downloadConfigDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/delete/' . $itemIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + ]; + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Ressources du module', + 'view' => 'config' + ]); + + } + + public function setup() + { + // Soumission du formulaire + if ($this->isPost()) { + $this->setData([ + 'module', $this->getUrl(0), + 'config', + [ + 'feeds' => $this->getInput('downloadConfigShowFeeds', helper::FILTER_BOOLEAN), + 'feedsLabel' => $this->getInput('downloadConfigFeedslabel', helper::FILTER_STRING_SHORT), + 'itemsperPage' => $this->getInput('blogConfigItemsperPage', helper::FILTER_INT, true), + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']) + ] + ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/setup', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Options', + 'view' => 'setup' + ]); + + } + + /** + * Suppression + */ + public function delete() + { + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action interdite' + ]); + } + // Suppression + else { + $this->deleteData(['module', $this->getUrl(0), 'posts', $this->getUrl(2)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Item supprimé', + 'state' => true + ]); + } + } + + /** + * Édition + */ + public function edit() + { + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // L'item n'existe pas + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // L'item existe + else { + // Soumission du formulaire + if ($this->isPost()) { + if ($this->getUser('group') === self::GROUP_ADMIN) { + $newuserid = $this->getInput('downloadEditUserId', helper::FILTER_STRING_SHORT, true); + } else { + $newuserid = $this->getUser('id'); + } + $itemId = $this->getInput('downloadEditTitle', helper::FILTER_ID, true); + // Incrémente le nouvel id de l'item + if ($itemId !== $this->getUrl(2)) { + $itemId = helper::increment($itemId, $this->getData(['page'])); + $itemId = helper::increment($itemId, $this->getData(['module', $this->getUrl(0), 'posts'])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + } + $this->setData([ + 'module', + $this->getUrl(0), + 'posts', + $itemId, + [ + 'comment' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'comment']), + 'content' => $this->getInput('downloadEditContent', null), + 'ressourceType' => $this->getInput('downloadEditRessourceType', helper::FILTER_STRING_SHORT), + 'file' => $this->getInput('downloadEditFile', helper::FILTER_STRING_SHORT), + 'url' => $this->getInput('downloadEditUrl', helper::FILTER_STRING_SHORT), + 'thumb' => $this->getInput('downloadEditThumb', helper::FILTER_STRING_SHORT, true), + 'version' => $this->getInput('downloadEditVersion', helper::FILTER_STRING_SHORT), + 'versionDate' => $this->getInput('downloadEditversionDate', helper::FILTER_DATETIME), + 'stats' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'stats']), + 'license' => $this->getInput('downloadEditLicense', helper::FILTER_STRING_SHORT, true), + 'category' => $this->getInput('downloadEditCategorie', helper::FILTER_STRING_SHORT), + 'author' => $this->getInput('downloadEditAuthor', helper::FILTER_STRING_SHORT, true), + 'publishedOn' => $this->getInput('downloadEditPublishedOn', helper::FILTER_DATETIME, true), + 'state' => $this->getInput('downloadEditState', helper::FILTER_BOOLEAN), + 'title' => $this->getInput('downloadEditTitle', helper::FILTER_STRING_SHORT, true), + 'userId' => $newuserid, + 'editConsent' => $this->getInput('downloadEditConsent') === self::EDIT_GROUP ? $this->getUser('group') : $this->getInput('downloadEditConsent'), + 'commentMaxlength' => $this->getInput('downloadEditCommentMaxlength'), + 'commentApproved' => $this->getInput('downloadEditCommentApproved', helper::FILTER_BOOLEAN), + 'commentClose' => $this->getInput('downloadEditCommentClose', helper::FILTER_BOOLEAN), + 'commentNotification' => $this->getInput('downloadEditCommentNotification', helper::FILTER_BOOLEAN), + 'commentGroupNotification' => $this->getInput('downloadEditCommentGroupNotification', helper::FILTER_INT) + ] + ]); + // Supprime l'ancien item + if ($itemId !== $this->getUrl(2)) { + $this->deleteData(['module', $this->getUrl(0), 'posts', $this->getUrl(2)]); + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } + // Liste des utilisateurs + self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname'); + ksort(self::$users); + foreach (self::$users as $userId => &$userFirstname) { + // Les membres ne sont pas éditeurs, les exclure de la liste + if ($this->getData(['user', $userId, 'group']) < self::GROUP_MODERATOR) { + unset(self::$users[$userId]); + } + $userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']) . ' (' . self::$groupEdits[$this->getData(['user', $userId, 'group'])] . ')'; + } + unset($userFirstname); + // Liste des catégories + self::$categories = $this->getData(['module', $this->getUrl(0), 'categories']); + arsort(self::$categories); + // Valeurs en sortie + $this->addOutput([ + 'title' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'title']), + 'vendor' => [ + 'flatpickr', + 'tinymce' + ], + 'view' => 'edit' + ]); + } + } + + /** + * Accueil (deux affichages en un pour éviter une url à rallonge) + */ + public function index() + { + // Mise à jour des données de module + $this->update(); + // Affichage d'un item + if ( + $this->getUrl(1) + // Protection pour la pagination, un ID ne peut pas être un entier, une page oui + and intval($this->getUrl(1)) === 0 + // Ne pas exclure la catégorie + and $this->getData(['module', $this->getUrl(0), 'categories', $this->getUrl(1)]) === null + ) { + // L'item ou la catégorie n'existent pas + if ( + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1)]) === null + ) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } else { + // Soumission du formulaire + if ($this->isPost()) { + // Check la captcha + if ( + $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') + //AND $this->getInput('downloaditemcaptcha', helper::FILTER_INT) !== $this->getInput('downloaditemcaptchaFirstNumber', helper::FILTER_INT) + $this->getInput('downloaditemcaptchaSecondNumber', helper::FILTER_INT)) + and password_verify($this->getInput('downloadItemCaptcha', helper::FILTER_INT), $this->getInput('downloadItemCaptchaResult')) === false + ) { + self::$inputNotices['downloadItemCaptcha'] = 'Incorrect'; + } + // Crée le commentaire + $commentId = helper::increment(uniqid(), $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'comment'])); + $content = $this->getInput('downloadItemContent', false); + $this->setData([ + 'module', $this->getUrl(0), + 'posts', $this->getUrl(1), + 'comment', + $commentId, + [ + 'author' => $this->getInput('downloadItemAuthor', helper::FILTER_STRING_SHORT, empty($this->getInput('downloadItemUserId')) ? TRUE : FALSE), + 'content' => $content, + 'createdOn' => time(), + 'userId' => $this->getInput('downloadItemUserId'), + 'approval' => !$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentApproved']) // true commentaire publié false en attente de publication + ] + ]); + // Envoi d'une notification aux administrateurs + // Init tableau + $to = []; + // Liste des destinataires + foreach ($this->getData(['user']) as $userId => $user) { + if ($user['group'] >= $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentGroupNotification'])) { + $to[] = $user['mail']; + $firstname[] = $user['firstname']; + $lastname[] = $user['lastname']; + } + } + // Envoi du mail $sent code d'erreur ou de réussite + $notification = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentApproved']) === true ? 'Commentaire déposé en attente d\'approbation' : 'Commentaire déposé'; + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentNotification']) === true) { + $error = 0; + foreach ($to as $key => $adress) { + $sent = $this->sendMail( + $adress, + 'Nouveau commentaire déposé', + 'Bonjour' . ' ' . $firstname[$key] . ' ' . $lastname[$key] . ',

    ' . + 'L\'item ' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'title']) . ' a reçu un nouveau commentaire.

    ', + '' + ); + if ($sent === false) + $error++; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl() . '#comment', + 'notification' => ($error === 0 ? $notification . '
    Une notification a été envoyée.' : $notification . '
    Erreur de notification : ' . $sent), + 'state' => ($sent === true ? true : null) + ]); + + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl() . '#comment', + 'notification' => $notification, + 'state' => true + ]); + } + + } + // Ids des commentaires approuvés par ordre de publication + $commentsApproved = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'comment']); + if ($commentsApproved) { + foreach ($commentsApproved as $key => $value) { + if ($value['approval'] === false) + unset($commentsApproved[$key]); + } + // Ligne suivante si affichage du nombre total de commentaires approuvés sous l'item + self::$nbCommentsApproved = count($commentsApproved); + } + $commentIds = array_keys(helper::arrayCollumn($commentsApproved, 'createdOn', 'SORT_DESC')); + // Pagination + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']), '#comment'); + // Nombre de téléchargements + self::$statSum = count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'stats']), 'time')) === 0 + ? '0' + : count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'stats']), 'time')); + // Liste des pages + self::$pages = $pagination['pages']; + // Signature de l'item + self::$itemSignature = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'userId'])); + // Signature du commentaire édité + if ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')) { + self::$editCommentSignature = $this->signature($this->getUser('id')); + } + // Commentaires en fonction de la pagination + for ($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Signatures des commentaires + $e = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'comment', $commentIds[$i], 'userId']); + if ($e) { + self::$commentsSignature[$commentIds[$i]] = $this->signature($e); + } else { + self::$commentsSignature[$commentIds[$i]] = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'comment', $commentIds[$i], 'author']); + } + // Données du commentaire si approuvé + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'comment', $commentIds[$i], 'approval']) === true) { + self::$comments[$commentIds[$i]] = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'comment', $commentIds[$i]]); + } + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'title' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'title']), + 'vendor' => [ + 'tinymce' + ], + 'view' => 'item' + ]); + } + } + // Liste des items + else { + // Ids des items par ordre de publication + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC'); + $itemIds = []; + foreach ($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if ($itemPublishedOn <= time() and $itemIdsStates[$itemId]) { + $itemIds[] = $itemId; + } + } + // Filtrage des catégories + // Une catégorie et pas un article + if ( + $this->getUrl(1) + and array_key_exists( + $this->getUrl(1), + $this->getData([ + 'module', + $this->getUrl(0), + 'categories' + ]) + ) + ) { + $filterData = []; + foreach ($itemIds as $key => $value) { + if ($this->getData(['module', $this->getUrl(0), 'posts', $value, 'category']) === $this->getUrl(1)) { + $filterData[] = $value; + } + } + $itemIds = $filterData; + } + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // Items en fonction de la pagination + for ($i = $pagination['first']; $i < $pagination['last']; $i++) { + self::$items[$itemIds[$i]] = $this->getData(['module', $this->getUrl(0), 'posts', $itemIds[$i]]); + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'showPageContent' => true, + 'view' => 'index' + ]); + } + } + + /** + * Retourne la signature d'un utilisateur + */ + private function signature($userId) + { + switch ($this->getData(['user', $userId, 'signature'])) { + case 1: + return $userId; + break; + case 2: + return $this->getData(['user', $userId, 'pseudo']); + break; + case 3: + return $this->getData(['user', $userId, 'firstname']) . ' ' . $this->getData(['user', $userId, 'lastname']); + break; + case 4: + return $this->getData(['user', $userId, 'lastname']) . ' ' . $this->getData(['user', $userId, 'firstname']); + break; + default: + return $this->getData(['user', $userId, 'firstname']); + } + } + + /** + * Initie un téléchargement protégé + */ + public function downloadFile() + { + + if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Action interdite' + ]); + } + // Téléchargement + else { + $fileName = self::FILE_DIR . 'source/' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'file']); + if (file_exists($fileName)) { + // Statistiques de téléchargement + $statId = helper::increment(uniqid(), $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'stats'])); + $this->setData([ + 'module', + $this->getUrl(0), + 'posts', + $this->getUrl(2), + 'stats', + $statId, + [ + 'time' => time(), + 'ip' => helper::getIp() + ] + ]); + // Formatage http + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename="' . basename($fileName) . '"'); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: ' . filesize($fileName)); + readfile($fileName); + exit; + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Le fichier n\'existe pas', + 'state' => false + ]); + } + } + } + + /** + * Ecran de consultation des données statistiques + */ + + public function stats() + { + + // Construction de la page des statistiques + $itemIds = array_keys($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'stats'])); + // Total des téléchargements + self::$statSum = count($itemIds); + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage'])); + + // Liste des pages + self::$pages = $pagination['pages']; + + for ($i = $pagination['first']; $i < $pagination['last']; $i++) { + + // Format des variables + $date = helper::dateUTF8('%d %B %Y - %H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'stats', $itemIds[$i], 'time'])); + // Met en forme le tableau + self::$items[] = [ + $date, + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'stats', $itemIds[$i], 'ip']) + ]; + + } + $this->addOutput([ + 'title' => 'Statistiques de téléchargement', + 'view' => 'stats' + ]); + } + + public function statsDeleteAll() + { + // Validité de la page demandée + if ($this->getData(['module', $this->getUrl(0), 'posts']) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Action interdite' + ]); + } + // Téléchargement + else { + $this->setData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'stats', []]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/stats/' . $this->getUrl(2), + 'notification' => 'Purge des statistiques', + 'state' => true + ]); + } + } + + /*** + * Retourne une chaîne json contenant la liste des téléchargements disponibles + */ + public function list() + { + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC'); + $itemIds = []; + foreach ($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if ($itemPublishedOn <= time() and $itemIdsStates[$itemId]) { + $itemIds[] = $itemId; + } + } + foreach ($itemIds as $key) { + self::$items[$key] = [ + 'title' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'title']), + 'content' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'content']), + 'thumb' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'thumb']), + 'file' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'file']), + 'version' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'version']), + 'versionDate' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'versionDate']), + 'author' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'author']), + 'license' => $this->getData(['module', $this->getUrl(0), 'posts', $key, 'license']), + 'category' => $this->getData([ + 'module', $this->getUrl(0), + 'categories', + $this->getData(['module', $this->getUrl(0), 'posts', $key, 'category']) + ]) + ]; + } + $this->addOutput([ + 'display' => self::DISPLAY_JSON, + 'content' => json_encode(self::$items) + ]); + } + + /** + * Gestion des catégories d'objets + */ + public function categories() + { + // Soumission du formulaire + if ($this->isPost()) { + // Empêche les doublons de libellés + if ( + array_key_exists($this->getInput('categoriesTitle', helper::FILTER_ID), $this->getData(['module', $this->getUrl(0), 'categories'])) == false + ) { + // Incrémente l'id de l'item + $itemId = helper::increment($this->getInput('categoriesTitle', helper::FILTER_ID), $this->getData(['module', $this->getUrl(0), 'categories'])); + $itemId = helper::increment($itemId, $this->getData(['page'])); + $itemId = helper::increment($itemId, (array) $this->getData(['module', $this->getUrl(0)])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + // Crée l'item + $this->setData([ + 'module', + $this->getUrl(0), + 'categories', + $itemId, + $this->getInput('categoriesTitle', helper::FILTER_STRING_SHORT, true) + ]); + $notification = 'Nouvelle catégorie créé.'; + $success = true; + } else { + $notification = 'Cette catégorie existe déjà !'; + $success = false; + } + + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/categories', + 'notification' => $notification, + 'state' => $success + ]); + } + if ($this->getData(['module', $this->getUrl(0), 'categories'])) { + $categories = $this->getData(['module', $this->getUrl(0), 'categories']); + // Ids des catégories par ordre alpha + $categoriesIds = array_keys($categories); + // Pagination + $pagination = helper::pagination($categoriesIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + for ($i = $pagination['first']; $i < $pagination['last']; $i++) { + self::$categories[$categoriesIds[$i]] = [ + $this->getData(['module', $this->getUrl(0), 'categories', $categoriesIds[$i]]), + helper::baseUrl() . $this->getUrl(0) . '/' . $categoriesIds[$i], + template::button('categoriesEdit' . $categoriesIds[$i], [ + 'class' => 'categoriesEdit', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/categoryEdit/' . $categoriesIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('pencil') + ]), + template::button('categoriesDelete' . $categoriesIds[$i], [ + 'class' => 'categoriesDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/categoryDelete/' . $categoriesIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + ]; + } + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Catégories', + 'view' => 'categories' + ]); + } + + /** + * Edition d'une catégorie + */ + public function categoryEdit() + { + // Soumission du formulaire + if ($this->isPost()) { + // Id de la catégorie précédente + $oldItemId = $this->getUrl(2); + // Empêche les doublons de clé + $itemTitle = helper::increment($this->getInput('categoryEditTitle', helper::FILTER_STRING_SHORT), $this->getData(['module', $this->getUrl(0), 'categories'])); + if ($itemTitle === $this->getInput('categoryEditTitle', helper::FILTER_STRING_SHORT)) { + // Incrémente l'id de l'item + $itemId = helper::increment($this->getInput('categoryEditTitle', helper::FILTER_ID), $this->getData(['module', $this->getUrl(0), 'categories'])); + $itemId = helper::increment($itemId, $this->getData(['page'])); + $itemId = helper::increment($itemId, (array) $this->getData(['module', $this->getUrl(0)])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + // Crée la catégorie + $this->setData([ + 'module', + $this->getUrl(0), + 'categories', + $itemId, + $this->getInput('categoryEditTitle', helper::FILTER_STRING_SHORT, true) + ]); + // Effacer la catégorie + $this->deleteData([ + 'module', + $this->getUrl(0), + 'categories', + $this->getUrl(2) + ]); + $notification = 'La catégorie a été éditée.'; + $success = true; + + // Répercuter le changement d'Id + if ($oldItemId !== $itemId) { + $i = 0; + // Mettre à jour les catégories dans items + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); + foreach ($itemIdsPublishedOns as $key => $value) { + if ($this->getData(['module', $this->getUrl(0), 'posts', $key, 'category']) === $oldItemId) { + $this->setData(['module', $this->getUrl(0), 'posts', $key, 'category', $itemId]); + $i++; + } + } + $notification .= ' ' . $i . ' items ont été actualisés.'; + } + } else { + $notification = 'Cette catégorie existe déjà !'; + $success = false; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/categories', + 'notification' => $notification, + 'state' => $success + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Éditer une catégorie', + 'view' => 'categoryEdit' + ]); + } + + /** + * Effacement d'une catégorie + */ + public function categoryDelete() + { + // La catégorie n'existe pas + if ($this->getData(['module', $this->getUrl(0), 'categories', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Contrôle du jeton + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/categories', + 'notification' => 'Action interdite' + ]); + } else { + // Mettre à jour les catégories dans items + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); + $success = true; + $i = 0; + foreach ($itemIdsPublishedOns as $key => $value) { + if ($this->getData(['module', $this->getUrl(0), 'posts', $key, 'category']) === $this->getUrl(2)) { + $i++; + $success = false; + } + } + if ($success) { + // Effacer la catégorie + $this->deleteData([ + 'module', + $this->getUrl(0), + 'categories', + $this->getUrl(2) + ]); + $notification = 'La catégorie a été supprimée'; + } else { + $notification = 'Suppression impossible, la catégorie est affectée à ' . $i . ' items.'; + } + + // valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/categories', + 'notification' => $notification, + 'state' => $success + ]); + } + } +} \ No newline at end of file diff --git a/module/download/enum.json b/module/download/enum.json new file mode 100644 index 00000000..c60acbdc --- /dev/null +++ b/module/download/enum.json @@ -0,0 +1 @@ +{"name":"download","realName":"Téléchargement","version":"3.1","update":"0.0","delete":true,"dataDirectory":""} \ No newline at end of file diff --git a/module/download/ressource/feed-icon-16.gif b/module/download/ressource/feed-icon-16.gif new file mode 100644 index 0000000000000000000000000000000000000000..26fa274454d016fdafa1b371e6d172030b61ac7d GIT binary patch literal 652 zcmZ?wbhEHb6krfwI9AB;Wun>ZdZS-+EPv0n`Z3e;&({zCe|~<~YVxAe@L9d_w<+eI zdQG2|=)Y_={m^OhuGRS8k57;D^!|N%b}LTnd4>L)F0+RfhHn~;9%Sjhsx^FEY4o_# z@aJ5|7tJR3Qg!}*e0DEi|9+vtokZ=wx3)ekF?ii+`l8kJ-}g^XOY|O<89r|`zE@!I zw8rQ~lgXb$Ew9>5@8;=0sWy6AYxJ_i?AMyOU+0$pSfBZBqR*FQ>F;Kx{5&!HWu4`h zy)%Byb9vwE_-=LQzc;sjE)9COY3j%A(|_+Qe^BcBc}e>FxhY@P6#u!o_50e)zxNOR z`}pkB;X?tj(k`Srkzulr~IeR}rieAnO4Zv4Ey|51V2uYJwG*T+4nasRbB>(}MY z-=|yroMriSlKIDO(^nhX|C0g~f3h%gG1N2YFaQB4P8irutD!|K07BTzlA_-oNcc1hVb)@I$C@&8w%Mnm^}*x>=-$uWM@XE3q3K( z+n30}qshBGH{_PjB8AT4CPx+_eKXyakCM*VXfpa8x!9!W!fBS3&{_Cd#ZQtY`q7^c z42zs*YqCAMQjx5}C&}jgh(nMu*=?1A*RH1rgcN%xD+z}kc=+HAgLSinO~;G`HX#{d V-YAuXg^H}50tyKne}y?1tN}38S(N|) literal 0 HcmV?d00001 diff --git a/module/download/vendor/FeedWriter/ATOM.php b/module/download/vendor/FeedWriter/ATOM.php new file mode 100644 index 00000000..fa33776e --- /dev/null +++ b/module/download/vendor/FeedWriter/ATOM.php @@ -0,0 +1,38 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating ATOM feeds + * + * @package UniversalFeedWriter + */ +class ATOM extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::ATOM); + } + +} diff --git a/module/download/vendor/FeedWriter/Feed.php b/module/download/vendor/FeedWriter/Feed.php new file mode 100644 index 00000000..506094f1 --- /dev/null +++ b/module/download/vendor/FeedWriter/Feed.php @@ -0,0 +1,1017 @@ + + * Copyright (C) 2010-2016 Michael Bemmerl + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Universal Feed Writer class + * + * Generate RSS 1.0, RSS2.0 and ATOM Feeds + * + * @package UniversalFeedWriter + * @author Anis uddin Ahmad + * @link http://www.ajaxray.com/projects/rss + */ +abstract class Feed +{ + // RSS 0.90 Officially obsoleted by 1.0 + // RSS 0.91, 0.92, 0.93 and 0.94 Officially obsoleted by 2.0 + // So, define constants for RSS 1.0, RSS 2.0 and ATOM + + const RSS1 = 'RSS 1.0'; + const RSS2 = 'RSS 2.0'; + const ATOM = 'ATOM'; + + const VERSION = '1.1.0'; + + /** + * Collection of all channel elements + */ + private $channels = array(); + + /** + * Collection of items as object of \FeedWriter\Item class. + */ + private $items = array(); + + /** + * Collection of other version wise data. + * + * Currently used to store the 'rdf:about' attribute and image element of the channel (both RSS1 only). + */ + private $data = array(); + + /** + * The tag names which have to encoded as CDATA + */ + private $CDATAEncoding = array(); + + /** + * Collection of XML namespaces + */ + private $namespaces = array(); + + /** + * Contains the format of this feed. + */ + private $version = null; + + /** + * Constructor + * + * If no version is given, a feed in RSS 2.0 format will be generated. + * + * @param string $version the version constant (RSS1/RSS2/ATOM). + */ + protected function __construct($version = Feed::RSS2) + { + $this->version = $version; + + // Setting default encoding + $this->encoding = 'utf-8'; + + // Setting default value for essential channel element + $this->setTitle($version . ' Feed'); + + // Add some default XML namespaces + $this->namespaces['content'] = 'http://purl.org/rss/1.0/modules/content/'; + $this->namespaces['wfw'] = 'http://wellformedweb.org/CommentAPI/'; + $this->namespaces['atom'] = 'http://www.w3.org/2005/Atom'; + $this->namespaces['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + $this->namespaces['rss1'] = 'http://purl.org/rss/1.0/'; + $this->namespaces['dc'] = 'http://purl.org/dc/elements/1.1/'; + $this->namespaces['sy'] = 'http://purl.org/rss/1.0/modules/syndication/'; + + // Tag names to encode in CDATA + $this->addCDATAEncoding(array('description', 'content:encoded', 'summary')); + } + + // Start # public functions --------------------------------------------- + + /** + * Set the URLs for feed pagination. + * + * See RFC 5005, chapter 3. At least one page URL must be specified. + * + * @param string $nextURL The URL to the next page of this feed. Optional. + * @param string $previousURL The URL to the previous page of this feed. Optional. + * @param string $firstURL The URL to the first page of this feed. Optional. + * @param string $lastURL The URL to the last page of this feed. Optional. + * @link http://tools.ietf.org/html/rfc5005#section-3 + * @return self + * @throws \LogicException if none of the parameters are set. + */ + public function setPagination($nextURL = null, $previousURL = null, $firstURL = null, $lastURL = null) + { + if (empty($nextURL) && empty($previousURL) && empty($firstURL) && empty($lastURL)) + throw new \LogicException('At least one URL must be specified for pagination to work.'); + + if (!empty($nextURL)) + $this->setAtomLink($nextURL, 'next'); + + if (!empty($previousURL)) + $this->setAtomLink($previousURL, 'previous'); + + if (!empty($firstURL)) + $this->setAtomLink($firstURL, 'first'); + + if (!empty($lastURL)) + $this->setAtomLink($lastURL, 'last'); + + return $this; + } + + /** + * Add a channel element indicating the program used to generate the feed. + * + * @return self + * @throws InvalidOperationException if this method is called on an RSS1 feed. + */ + public function addGenerator() + { + if ($this->version == Feed::ATOM) + $this->setChannelElement('atom:generator', 'FeedWriter', array('uri' => 'https://github.com/mibe/FeedWriter')); + else if ($this->version == Feed::RSS2) + $this->setChannelElement('generator', 'FeedWriter'); + else + throw new InvalidOperationException('The generator element is not supported in RSS1 feeds.'); + + return $this; + } + + /** + * Add a XML namespace to the internal list of namespaces. After that, + * custom channel elements can be used properly to generate a valid feed. + * + * @access public + * @param string $prefix namespace prefix + * @param string $uri namespace name (URI) + * @return self + * @link http://www.w3.org/TR/REC-xml-names/ + * @throws \InvalidArgumentException if the prefix or uri is empty or NULL. + */ + public function addNamespace($prefix, $uri) + { + if (empty($prefix)) + throw new \InvalidArgumentException('The prefix may not be emtpy or NULL.'); + if (empty($uri)) + throw new \InvalidArgumentException('The uri may not be empty or NULL.'); + + $this->namespaces[$prefix] = $uri; + + return $this; + } + + /** + * Add a channel element to the feed. + * + * @access public + * @param string $elementName name of the channel tag + * @param string $content content of the channel tag + * @param array array of element attributes with attribute name as array key + * @param bool TRUE if this element can appear multiple times + * @return self + * @throws \InvalidArgumentException if the element name is not a string, empty or NULL. + */ + public function setChannelElement($elementName, $content, array $attributes = null, $multiple = false) + { + if (empty($elementName)) + throw new \InvalidArgumentException('The element name may not be empty or NULL.'); + if (!is_string($elementName)) + throw new \InvalidArgumentException('The element name must be a string.'); + + $entity['content'] = $content; + $entity['attributes'] = $attributes; + + if ($multiple === TRUE) + $this->channels[$elementName][] = $entity; + else + $this->channels[$elementName] = $entity; + + return $this; + } + + /** + * Set multiple channel elements from an array. Array elements + * should be 'channelName' => 'channelContent' format. + * + * @access public + * @param array array of channels + * @return self + */ + public function setChannelElementsFromArray(array $elementArray) + { + foreach ($elementArray as $elementName => $content) { + $this->setChannelElement($elementName, $content); + } + + return $this; + } + + /** + * Get the appropriate MIME type string for the current feed. + * + * @access public + * @return string The MIME type string. + */ + public function getMIMEType() + { + switch ($this->version) { + case Feed::RSS2 : $mimeType = "application/rss+xml"; + break; + case Feed::RSS1 : $mimeType = "application/rdf+xml"; + break; + case Feed::ATOM : $mimeType = "application/atom+xml"; + break; + default : $mimeType = "text/xml"; + } + + return $mimeType; + } + + /** + * Print the actual RSS/ATOM file + * + * Sets a Content-Type header and echoes the contents of the feed. + * Should only be used in situations where direct output is desired; + * if you need to pass a string around, use generateFeed() instead. + * + * @access public + * @param bool FALSE if the specific feed media type should be sent. + * @return void + * @throws \InvalidArgumentException if the useGenericContentType parameter is not boolean. + */ + public function printFeed($useGenericContentType = false) + { + if (!is_bool($useGenericContentType)) + throw new \InvalidArgumentException('The useGenericContentType parameter must be boolean.'); + + $contentType = "text/xml"; + + if (!$useGenericContentType) { + $contentType = $this->getMIMEType(); + } + + // Generate the feed before setting the header, so Exceptions will be nicely visible. + $feed = $this->generateFeed(); + header("Content-Type: " . $contentType . "; charset=" . $this->encoding); + echo $feed; + } + + /** + * Generate the feed. + * + * @access public + * @return string The complete feed XML. + * @throws InvalidOperationException if the link element of the feed is not set. + */ + public function generateFeed() + { + if ($this->version != Feed::ATOM && !array_key_exists('link', $this->channels)) + throw new InvalidOperationException('RSS1 & RSS2 feeds need a link element. Call the setLink method before this method.'); + + return $this->makeHeader() + . $this->makeChannels() + . $this->makeItems() + . $this->makeFooter(); + } + + /** + * Create a new Item. + * + * @access public + * @return Item instance of Item class + */ + public function createNewItem() + { + $Item = new Item($this->version); + + return $Item; + } + + /** + * Add one or more tags to the list of CDATA encoded tags + * + * @access public + * @param array $tags An array of tag names that are merged into the list of tags which should be encoded as CDATA + * @return self + */ + public function addCDATAEncoding(array $tags) + { + $this->CDATAEncoding = array_merge($this->CDATAEncoding, $tags); + + return $this; + } + + /** + * Get list of CDATA encoded properties + * + * @access public + * @return array Return an array of CDATA properties that are to be encoded as CDATA + */ + public function getCDATAEncoding() + { + return $this->CDATAEncoding; + } + + /** + * Remove tags from the list of CDATA encoded tags + * + * @access public + * @param array $tags An array of tag names that should be removed. + * @return void + */ + public function removeCDATAEncoding(array $tags) + { + // Call array_values to re-index the array. + $this->CDATAEncoding = array_values(array_diff($this->CDATAEncoding, $tags)); + } + + /** + * Add a FeedItem to the main class + * + * @access public + * @param Item $feedItem instance of Item class + * @return self + * @throws \InvalidArgumentException if the given item version mismatches. + */ + public function addItem(Item $feedItem) + { + if ($feedItem->getVersion() != $this->version) + { + $msg = sprintf('Feed type mismatch: This instance can handle %s feeds only, but item for %s feeds given.', $this->version, $feedItem->getVersion()); + throw new \InvalidArgumentException($msg); + } + + $this->items[] = $feedItem; + + return $this; + } + + // Wrapper functions ------------------------------------------------------------------- + + /** + * Set the 'encoding' attribute in the XML prolog. + * + * @access public + * @param string $encoding value of 'encoding' attribute + * @return self + * @throws \InvalidArgumentException if the encoding is not a string, empty or NULL. + */ + public function setEncoding($encoding) + { + if (empty($encoding)) + throw new \InvalidArgumentException('The encoding may not be empty or NULL.'); + if (!is_string($encoding)) + throw new \InvalidArgumentException('The encoding must be a string.'); + + $this->encoding = $encoding; + + return $this; + } + + /** + * Set the 'title' channel element + * + * @access public + * @param string $title value of 'title' channel tag + * @return self + */ + public function setTitle($title) + { + return $this->setChannelElement('title', $title); + } + + /** + * Set the date when the feed was lastly updated. + * + * This adds the 'updated' element to the feed. The value of the date parameter + * can be either an instance of the DateTime class, an integer containing a UNIX + * timestamp or a string which is parseable by PHP's 'strtotime' function. + * + * Not supported in RSS1 feeds. + * + * @access public + * @param DateTime|int|string Date which should be used. + * @return self + * @throws \InvalidArgumentException if the given date is not an instance of DateTime, a UNIX timestamp or a date string. + * @throws InvalidOperationException if this method is called on an RSS1 feed. + */ + public function setDate($date) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('The publication date is not supported in RSS1 feeds.'); + + // The feeds have different date formats. + $format = $this->version == Feed::ATOM ? \DATE_ATOM : \DATE_RSS; + + if ($date instanceof DateTime) + $date = $date->format($format); + else if(is_numeric($date) && $date >= 0) + $date = date($format, $date); + else if (is_string($date)) + { + $timestamp = strtotime($date); + if ($timestamp === FALSE) + throw new \InvalidArgumentException('The given date was not parseable.'); + + $date = date($format, $timestamp); + } + else + throw new \InvalidArgumentException('The given date is not an instance of DateTime, a UNIX timestamp or a date string.'); + + if ($this->version == Feed::ATOM) + $this->setChannelElement('updated', $date); + else + $this->setChannelElement('lastBuildDate', $date); + + return $this; + } + + /** + * Set a phrase or sentence describing the feed. + * + * @access public + * @param string $description Description of the feed. + * @return self + */ + public function setDescription($description) + { + if ($this->version != Feed::ATOM) + $this->setChannelElement('description', $description); + else + $this->setChannelElement('subtitle', $description); + + return $this; + } + + /** + * Set the 'link' channel element + * + * @access public + * @param string $link value of 'link' channel tag + * @return self + */ + public function setLink($link) + { + if ($this->version == Feed::ATOM) + $this->setAtomLink($link); + else + $this->setChannelElement('link', $link); + + return $this; + } + + /** + * Set custom 'link' channel elements. + * + * In ATOM feeds, only one link with alternate relation and the same combination of + * type and hreflang values. + * + * @access public + * @param string $href URI of this link + * @param string $rel relation type of the resource + * @param string $type MIME type of the target resource + * @param string $hreflang language of the resource + * @param string $title human-readable information about the resource + * @param int $length length of the resource in bytes + * @link https://www.iana.org/assignments/link-relations/link-relations.xml + * @link https://tools.ietf.org/html/rfc4287#section-4.2.7 + * @return self + * @throws \InvalidArgumentException on multiple occasions. + * @throws InvalidOperationException if the same link with the same attributes was already added to the feed. + */ + public function setAtomLink($href, $rel = null, $type = null, $hreflang = null, $title = null, $length = null) + { + $data = array('href' => $href); + + if ($rel != null) { + if (!is_string($rel) || empty($rel)) + throw new \InvalidArgumentException('rel parameter must be a string and a valid relation identifier.'); + + $data['rel'] = $rel; + } + if ($type != null) { + // Regex used from RFC 4287, page 41 + if (!is_string($type) || preg_match('/.+\/.+/', $type) != 1) + throw new \InvalidArgumentException('type parameter must be a string and a MIME type.'); + + $data['type'] = $type; + } + if ($hreflang != null) { + // Regex used from RFC 4287, page 41 + if (!is_string($hreflang) || preg_match('/[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*/', $hreflang) != 1) + throw new \InvalidArgumentException('hreflang parameter must be a string and a valid language code.'); + + $data['hreflang'] = $hreflang; + } + if ($title != null) { + if (!is_string($title) || empty($title)) + throw new \InvalidArgumentException('title parameter must be a string and not empty.'); + + $data['title'] = $title; + } + if ($length != null) { + if (!is_int($length) || $length < 0) + throw new \InvalidArgumentException('length parameter must be a positive integer.'); + + $data['length'] = (string) $length; + } + + // ATOM spec. has some restrictions on atom:link usage + // See RFC 4287, page 12 (4.1.1) + if ($this->version == Feed::ATOM) { + foreach ($this->channels as $key => $value) { + if ($key != 'atom:link') + continue; + + // $value is an array , so check every element + foreach ($value as $linkItem) { + $attrib = $linkItem['attributes']; + // Only one link with relation alternate and same hreflang & type is allowed. + if (@$attrib['rel'] == 'alternate' && @$attrib['hreflang'] == $hreflang && @$attrib['type'] == $type) + throw new InvalidOperationException('The feed must not contain more than one link element with a' + . ' relation of "alternate" that has the same combination of type and hreflang attribute values.'); + } + } + } + + return $this->setChannelElement('atom:link', '', $data, true); + } + + /** + * Set an 'atom:link' channel element with relation=self attribute. + * Needs the full URL to this feed. + * + * @link http://www.rssboard.org/rss-profile#namespace-elements-atom-link + * @access public + * @param string $url URL to this feed + * @return self + */ + public function setSelfLink($url) + { + return $this->setAtomLink($url, 'self', $this->getMIMEType()); + } + + /** + * Set the 'image' channel element + * + * @access public + * @param string $url URL of the image + * @param string $title Title of the image. RSS only. + * @param string $link Link target URL of the image. RSS only. + * @return self + * @throws \InvalidArgumentException if the url is invalid. + * @throws \InvalidArgumentException if the title and link parameter are not a string or empty. + */ + public function setImage($url, $title = null, $link = null) + { + if (!is_string($url) || empty($url)) + throw new \InvalidArgumentException('url parameter must be a string and may not be empty or NULL.'); + + // RSS feeds have support for a title & link element. + if ($this->version != Feed::ATOM) + { + if (!is_string($title) || empty($title)) + throw new \InvalidArgumentException('title parameter must be a string and may not be empty or NULL.'); + if (!is_string($link) || empty($link)) + throw new \InvalidArgumentException('link parameter must be a string and may not be empty or NULL.'); + + $data = array('title'=>$title, 'link'=>$link, 'url'=>$url); + $name = 'image'; + } + else + { + $name = 'logo'; + $data = $url; + } + + // Special handling for RSS1 again (since RSS1 is a bit strange...) + if ($this->version == Feed::RSS1) + { + $this->data['Image'] = $data; + return $this->setChannelElement($name, '', array('rdf:resource' => $url), false); + } + else + return $this->setChannelElement($name, $data); + } + + /** + * Set the channel 'rdf:about' attribute, which is used in RSS1 feeds only. + * + * @access public + * @param string $url value of 'rdf:about' attribute of the channel element + * @return self + * @throws InvalidOperationException if this method is called and the feed is not of type RSS1. + * @throws \InvalidArgumentException if the given URL is invalid. + */ + public function setChannelAbout($url) + { + if ($this->version != Feed::RSS1) + throw new InvalidOperationException("This method is only supported in RSS1 feeds."); + if (empty($url)) + throw new \InvalidArgumentException('The about URL may not be empty or NULL.'); + if (!is_string($url)) + throw new \InvalidArgumentException('The about URL must be a string.'); + + $this->data['ChannelAbout'] = $url; + + return $this; + } + + /** + * Generate an UUID. + * + * The UUID is based on an MD5 hash. If no key is given, a unique ID as the input + * for the MD5 hash is generated. + * + * @author Anis uddin Ahmad + * @access public + * @param string $key optional key on which the UUID is generated + * @param string $prefix an optional prefix + * @return string the formatted UUID + */ + public static function uuid($key = null, $prefix = '') + { + $key = ($key == null) ? uniqid(rand()) : $key; + $chars = md5($key); + $uuid = substr($chars,0,8) . '-'; + $uuid .= substr($chars,8,4) . '-'; + $uuid .= substr($chars,12,4) . '-'; + $uuid .= substr($chars,16,4) . '-'; + $uuid .= substr($chars,20,12); + + return $prefix . $uuid; + } + + /** + * Replace invalid XML characters. + * + * @link http://www.phpwact.org/php/i18n/charsets#xml See utf8_for_xml() function + * @link http://www.w3.org/TR/REC-xml/#charsets + * @link https://github.com/mibe/FeedWriter/issues/30 + * + * @access public + * @param string $string string which should be filtered + * @param string $replacement replace invalid characters with this string + * @return string the filtered string + */ + public static function filterInvalidXMLChars($string, $replacement = '_') // default to '\x{FFFD}' ??? + { + $result = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u', $replacement, $string); + + // Did the PCRE replace failed because of bad UTF-8 data? + // If yes, try a non-multibyte regex and without the UTF-8 mode enabled. + if ($result == NULL && preg_last_error() == PREG_BAD_UTF8_ERROR) + $result = preg_replace('/[^\x09\x0a\x0d\x20-\xFF]+/', $replacement, $string); + + // In case the regex replacing failed completely, return the whole unfiltered string. + if ($result == NULL) + $result = $string; + + return $result; + } + // End # public functions ---------------------------------------------- + + // Start # private functions ---------------------------------------------- + + /** + * Returns all used XML namespace prefixes in this instance. + * This includes all channel elements and feed items. + * Unfortunately some namespace prefixes are not included, + * because they are hardcoded, e.g. rdf. + * + * @access private + * @return array Array with namespace prefix as value. + */ + private function getNamespacePrefixes() + { + $prefixes = array(); + + // Get all tag names from channel elements... + $tags = array_keys($this->channels); + + // ... and now all names from feed items + foreach ($this->items as $item) { + foreach (array_keys($item->getElements()) as $key) { + if (!in_array($key, $tags)) { + $tags[] = $key; + } + } + } + + // Look for prefixes in those tag names + foreach ($tags as $tag) { + $elements = explode(':', $tag); + + if (count($elements) != 2) + continue; + + $prefixes[] = $elements[0]; + } + + return array_unique($prefixes); + } + + /** + * Returns the XML header and root element, depending on the feed type. + * + * @access private + * @return string The XML header of the feed. + * @throws InvalidOperationException if an unknown XML namespace prefix is encountered. + */ + private function makeHeader() + { + $out = 'encoding.'" ?>' . PHP_EOL; + + $prefixes = $this->getNamespacePrefixes(); + $attributes = array(); + $tagName = ''; + $defaultNamespace = ''; + + if ($this->version == Feed::RSS2) { + $tagName = 'rss'; + $attributes['version'] = '2.0'; + } elseif ($this->version == Feed::RSS1) { + $tagName = 'rdf:RDF'; + $prefixes[] = 'rdf'; + $defaultNamespace = $this->namespaces['rss1']; + } elseif ($this->version == Feed::ATOM) { + $tagName = 'feed'; + $defaultNamespace = $this->namespaces['atom']; + + // Ugly hack to remove the 'atom' value from the prefixes array. + $prefixes = array_flip($prefixes); + unset($prefixes['atom']); + $prefixes = array_flip($prefixes); + } + + // Iterate through every namespace prefix and add it to the element attributes. + foreach ($prefixes as $prefix) { + if (!isset($this->namespaces[$prefix])) + throw new InvalidOperationException('Unknown XML namespace prefix: \'' . $prefix . '\'.' + . ' Use the addNamespace method to add support for this prefix.'); + else + $attributes['xmlns:' . $prefix] = $this->namespaces[$prefix]; + } + + // Include default namepsace, if required + if (!empty($defaultNamespace)) + $attributes['xmlns'] = $defaultNamespace; + + $out .= $this->makeNode($tagName, '', $attributes, true); + + return $out; + } + + /** + * Closes the open tags at the end of file + * + * @access private + * @return string The XML footer of the feed. + */ + private function makeFooter() + { + if ($this->version == Feed::RSS2) { + return '' . PHP_EOL . ''; + } elseif ($this->version == Feed::RSS1) { + return ''; + } elseif ($this->version == Feed::ATOM) { + return ''; + } + } + + /** + * Creates a single node in XML format + * + * @access private + * @param string $tagName name of the tag + * @param mixed $tagContent tag value as string or array of nested tags in 'tagName' => 'tagValue' format + * @param array $attributes Attributes (if any) in 'attrName' => 'attrValue' format + * @param bool $omitEndTag True if the end tag should be omitted. Defaults to false. + * @return string formatted xml tag + * @throws \InvalidArgumentException if the tagContent is not an array and not a string. + */ + private function makeNode($tagName, $tagContent, array $attributes = null, $omitEndTag = false) + { + $nodeText = ''; + $attrText = ''; + + if ($attributes != null) { + foreach ($attributes as $key => $value) { + $value = self::filterInvalidXMLChars($value); + $value = htmlspecialchars($value); + $attrText .= " $key=\"$value\""; + } + } + + $attrText .= (in_array($tagName, $this->CDATAEncoding) && $this->version == Feed::ATOM) ? ' type="html"' : ''; + $nodeText .= "<{$tagName}{$attrText}>"; + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? ' $value) { + if (is_array($value)) { + $nodeText .= PHP_EOL; + foreach ($value as $subValue) { + $nodeText .= $this->makeNode($key, $subValue); + } + } else if (is_string($value)) { + $nodeText .= $this->makeNode($key, $value); + } else { + throw new \InvalidArgumentException("Unknown node-value type for $key"); + } + } + } else { + $tagContent = self::filterInvalidXMLChars($tagContent); + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? $this->sanitizeCDATA($tagContent) : htmlspecialchars($tagContent); + } + + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? ']]>' : ''; + + if (!$omitEndTag) + $nodeText .= ""; + + $nodeText .= PHP_EOL; + + return $nodeText; + } + + /** + * Make the channels. + * + * @access private + * @return string The feed header as XML containing all the feed metadata. + */ + private function makeChannels() + { + $out = ''; + + //Start channel tag + switch ($this->version) { + case Feed::RSS2: + $out .= '' . PHP_EOL; + break; + case Feed::RSS1: + $out .= (isset($this->data['ChannelAbout']))? "data['ChannelAbout']}\">" : "channels['link']['content']}\">"; + break; + } + + //Print Items of channel + foreach ($this->channels as $key => $value) { + // In ATOM feeds, strip all ATOM namespace prefixes from the tag name. They are not needed here, + // because the ATOM namespace name is set as default namespace. + if ($this->version == Feed::ATOM && strncmp($key, 'atom', 4) == 0) { + $key = substr($key, 5); + } + + // The channel element can occur multiple times, when the key 'content' is not in the array. + if (!array_key_exists('content', $value)) { + // If this is the case, iterate through the array with the multiple elements. + foreach ($value as $singleElement) { + $out .= $this->makeNode($key, $singleElement['content'], $singleElement['attributes']); + } + } else { + $out .= $this->makeNode($key, $value['content'], $value['attributes']); + } + } + + if ($this->version == Feed::RSS1) { + //RSS 1.0 have special tag with channel + $out .= "" . PHP_EOL . "" . PHP_EOL; + foreach ($this->items as $item) { + $thisItems = $item->getElements(); + $out .= "" . PHP_EOL; + } + $out .= "" . PHP_EOL . "" . PHP_EOL . "" . PHP_EOL; + + // An image has its own element after the channel elements. + if (array_key_exists('image', $this->data)) + $out .= $this->makeNode('image', $this->data['Image'], array('rdf:about' => $this->data['Image']['url'])); + } else if ($this->version == Feed::ATOM) { + // ATOM feeds have a unique feed ID. Use the title channel element as key. + $out .= $this->makeNode('id', Feed::uuid($this->channels['title']['content'], 'urn:uuid:')); + } + + return $out; + } + + /** + * Prints formatted feed items + * + * @access private + * @return string The XML of every feed item. + */ + private function makeItems() + { + $out = ''; + + foreach ($this->items as $item) { + $thisItems = $item->getElements(); + + // The argument is printed as rdf:about attribute of item in RSS 1.0 + // We're using the link set in the item (which is mandatory) as the about attribute. + if ($this->version == Feed::RSS1) + $out .= $this->startItem($thisItems['link']['content']); + else + $out .= $this->startItem(); + + foreach ($thisItems as $feedItem) { + $name = $feedItem['name']; + + // Strip all ATOM namespace prefixes from tags when feed is an ATOM feed. + // Not needed here, because the ATOM namespace name is used as default namespace. + if ($this->version == Feed::ATOM && strncmp($name, 'atom', 4) == 0) + $name = substr($name, 5); + + $out .= $this->makeNode($name, $feedItem['content'], $feedItem['attributes']); + } + $out .= $this->endItem(); + } + + return $out; + } + + /** + * Make the starting tag of channels + * + * @access private + * @param string $about The value of about attribute which is used for RSS 1.0 only. + * @return string The starting XML tag of an feed item. + * @throws InvalidOperationException if this object misses the data for the about attribute. + */ + private function startItem($about = false) + { + $out = ''; + + if ($this->version == Feed::RSS2) { + $out .= '
    ' . PHP_EOL; + } elseif ($this->version == Feed::RSS1) { + if ($about) { + $out .= "" . PHP_EOL; + } else { + throw new InvalidOperationException("Missing data for about attribute. Call setChannelAbout method."); + } + } elseif ($this->version == Feed::ATOM) { + $out .= "" . PHP_EOL; + } + + return $out; + } + + /** + * Closes feed item tag + * + * @access private + * @return string The ending XML tag of an feed item. + */ + private function endItem() + { + if ($this->version == Feed::RSS2 || $this->version == Feed::RSS1) { + return '
    ' . PHP_EOL; + } elseif ($this->version == Feed::ATOM) { + return '' . PHP_EOL; + } + } + + /** + * Sanitizes data which will be later on returned as CDATA in the feed. + * + * A "]]>" respectively "", "]]>", $text); + $text = str_replace(" + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * The exception that is thrown when an invalid operation is performed on + * the object. + * + * @package UniversalFeedWriter + */ +class InvalidOperationException extends LogicException +{ +} diff --git a/module/download/vendor/FeedWriter/Item.php b/module/download/vendor/FeedWriter/Item.php new file mode 100644 index 00000000..12b7f9c0 --- /dev/null +++ b/module/download/vendor/FeedWriter/Item.php @@ -0,0 +1,413 @@ + + * Copyright (C) 2010-2013, 2015-2016 Michael Bemmerl + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Universal Feed Writer + * + * Item class - Used as feed element in Feed class + * + * @package UniversalFeedWriter + * @author Anis uddin Ahmad + * @link http://www.ajaxray.com/projects/rss + */ +class Item +{ + /** + * Collection of feed item elements + */ + private $elements = array(); + + /** + * Contains the format of this feed. + */ + private $version; + + /** + * Is used as a suffix when multiple elements have the same name. + **/ + private $_cpt = 0; + + /** + * Constructor + * + * @param string $version constant (RSS1/RSS2/ATOM) RSS2 is default. + */ + public function __construct($version = Feed::RSS2) + { + $this->version = $version; + } + + /** + * Return an unique number + * + * @access private + * @return int + **/ + private function cpt() + { + return $this->_cpt++; + } + + /** + * Add an element to elements array + * + * @access public + * @param string $elementName The tag name of an element + * @param string $content The content of tag + * @param array $attributes Attributes (if any) in 'attrName' => 'attrValue' format + * @param boolean $overwrite Specifies if an already existing element is overwritten. + * @param boolean $allowMultiple Specifies if multiple elements of the same name are allowed. + * @return self + * @throws \InvalidArgumentException if the element name is not a string, empty or NULL. + */ + public function addElement($elementName, $content, array $attributes = null, $overwrite = FALSE, $allowMultiple = FALSE) + { + if (empty($elementName)) + throw new \InvalidArgumentException('The element name may not be empty or NULL.'); + if (!is_string($elementName)) + throw new \InvalidArgumentException('The element name must be a string.'); + + $key = $elementName; + + // return if element already exists & if overwriting is disabled + // & if multiple elements are not allowed. + if (isset($this->elements[$elementName]) && !$overwrite) { + if (!$allowMultiple) + return $this; + + $key .= '-' . $this->cpt(); + } + + $this->elements[$key]['name'] = $elementName; + $this->elements[$key]['content'] = $content; + $this->elements[$key]['attributes'] = $attributes; + + return $this; + } + + /** + * Set multiple feed elements from an array. + * Elements which have attributes cannot be added by this method + * + * @access public + * @param array array of elements in 'tagName' => 'tagContent' format. + * @return self + */ + public function addElementArray(array $elementArray) + { + foreach ($elementArray as $elementName => $content) { + $this->addElement($elementName, $content); + } + + return $this; + } + + /** + * Return the collection of elements in this feed item + * + * @access public + * @return array All elements of this item. + * @throws InvalidOperationException on ATOM feeds if either a content or link element is missing. + * @throws InvalidOperationException on RSS1 feeds if a title or link element is missing. + */ + public function getElements() + { + // ATOM feeds have some specific requirements... + if ($this->version == Feed::ATOM) + { + // Add an 'id' element, if it was not added by calling the setLink method. + // Use the value of the title element as key, since no link element was specified. + if (!array_key_exists('id', $this->elements)) + $this->setId(Feed::uuid($this->elements['title']['content'], 'urn:uuid:')); + + // Either a 'link' or 'content' element is needed. + if (!array_key_exists('content', $this->elements) && !array_key_exists('link', $this->elements)) + throw new InvalidOperationException('ATOM feed entries need a link or a content element. Call the setLink or setContent method.'); + } + // ...same with RSS1 feeds. + else if ($this->version == Feed::RSS1) + { + if (!array_key_exists('title', $this->elements)) + throw new InvalidOperationException('RSS1 feed entries need a title element. Call the setTitle method.'); + if (!array_key_exists('link', $this->elements)) + throw new InvalidOperationException('RSS1 feed entries need a link element. Call the setLink method.'); + } + + return $this->elements; + } + + /** + * Return the type of this feed item + * + * @access public + * @return string The feed type, as defined in Feed.php + */ + public function getVersion() + { + return $this->version; + } + + // Wrapper functions ------------------------------------------------------ + + /** + * Set the 'description' element of feed item + * + * @access public + * @param string $description The content of the 'description' or 'summary' element + * @return self + */ + public function setDescription($description) + { + $tag = ($this->version == Feed::ATOM) ? 'summary' : 'description'; + + return $this->addElement($tag, $description); + } + + /** + * Set the 'content' element of the feed item + * For ATOM feeds only + * + * @access public + * @param string $content Content for the item (i.e., the body of a download post). + * @return self + * @throws InvalidOperationException if this method is called on non-ATOM feeds. + */ + public function setContent($content) + { + if ($this->version != Feed::ATOM) + throw new InvalidOperationException('The content element is supported in ATOM feeds only.'); + + return $this->addElement('content', $content, array('type' => 'html')); + } + + /** + * Set the 'title' element of feed item + * + * @access public + * @param string $title The content of 'title' element + * @return self + */ + public function setTitle($title) + { + return $this->addElement('title', $title); + } + + /** + * Set the 'date' element of the feed item. + * + * The value of the date parameter can be either an instance of the + * DateTime class, an integer containing a UNIX timestamp or a string + * which is parseable by PHP's 'strtotime' function. + * + * @access public + * @param DateTime|int|string $date Date which should be used. + * @return self + * @throws \InvalidArgumentException if the given date was not parseable. + */ + public function setDate($date) + { + if (!is_numeric($date)) { + if ($date instanceof DateTime) + $date = $date->getTimestamp(); + else { + $date = strtotime($date); + + if ($date === FALSE) + throw new \InvalidArgumentException('The given date string was not parseable.'); + } + } elseif ($date < 0) + throw new \InvalidArgumentException('The given date is not an UNIX timestamp.'); + + if ($this->version == Feed::ATOM) { + $tag = 'updated'; + $value = date(\DATE_ATOM, $date); + } elseif ($this->version == Feed::RSS2) { + $tag = 'pubDate'; + $value = date(\DATE_RSS, $date); + } else { + $tag = 'dc:date'; + $value = date("Y-m-d", $date); + } + + return $this->addElement($tag, $value); + } + + /** + * Set the 'link' element of feed item + * + * @access public + * @param string $link The content of 'link' element + * @return self + */ + public function setLink($link) + { + if ($this->version == Feed::RSS2 || $this->version == Feed::RSS1) { + $this->addElement('link', $link); + } else { + $this->addElement('link','',array('href'=>$link)); + $this->setId(Feed::uuid($link,'urn:uuid:')); + } + + return $this; + } + + /** + * Attach a external media to the feed item. + * Not supported in RSS 1.0 feeds. + * + * See RFC 4288 for syntactical correct MIME types. + * + * Note that you should avoid the use of more than one enclosure in one item, + * since some RSS aggregators don't support it. + * + * @access public + * @param string $url The URL of the media. + * @param integer $length The length of the media. + * @param string $type The MIME type attribute of the media. + * @param boolean $multiple Specifies if multiple enclosures are allowed + * @return self + * @link https://tools.ietf.org/html/rfc4288 + * @throws \InvalidArgumentException if the length or type parameter is invalid. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function addEnclosure($url, $length, $type, $multiple = TRUE) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('Media attachment is not supported in RSS1 feeds.'); + + // the length parameter should be set to 0 if it can't be determined + // see http://www.rssboard.org/rss-profile#element-channel-item-enclosure + if (!is_numeric($length) || $length < 0) + throw new \InvalidArgumentException('The length parameter must be an integer and greater or equals to zero.'); + + // Regex used from RFC 4287, page 41 + if (!is_string($type) || preg_match('/.+\/.+/', $type) != 1) + throw new \InvalidArgumentException('type parameter must be a string and a MIME type.'); + + $attributes = array('length' => $length, 'type' => $type); + + if ($this->version == Feed::RSS2) { + $attributes['url'] = $url; + $this->addElement('enclosure', '', $attributes, FALSE, $multiple); + } else { + $attributes['href'] = $url; + $attributes['rel'] = 'enclosure'; + $this->addElement('atom:link', '', $attributes, FALSE, $multiple); + } + + return $this; + } + + /** + * Set the 'author' element of feed item. + * Not supported in RSS 1.0 feeds. + * + * @access public + * @param string $author The author of this item + * @param string|null $email Optional email address of the author + * @param string|null $uri Optional URI related to the author + * @return self + * @throws \InvalidArgumentException if the provided email address is syntactically incorrect. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function setAuthor($author, $email = null, $uri = null) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('The author element is not supported in RSS1 feeds.'); + + // Regex from RFC 4287 page 41 + if ($email != null && preg_match('/.+@.+/', $email) != 1) + throw new \InvalidArgumentException('The email address is syntactically incorrect.'); + + if ($this->version == Feed::RSS2) + { + if ($email != null) + $author = $email . ' (' . $author . ')'; + + $this->addElement('author', $author); + } + else + { + $elements = array('name' => $author); + + if ($email != null) + $elements['email'] = $email; + + if ($uri != null) + $elements['uri'] = $uri; + + $this->addElement('author', $elements); + } + + return $this; + } + + /** + * Set the unique identifier of the feed item + * + * On ATOM feeds, the identifier must begin with an valid URI scheme. + * + * @access public + * @param string $id The unique identifier of this item + * @param boolean $permaLink The value of the 'isPermaLink' attribute in RSS 2 feeds. + * @return self + * @throws \InvalidArgumentException if the permaLink parameter is not boolean. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function setId($id, $permaLink = false) + { + if ($this->version == Feed::RSS2) { + if (!is_bool($permaLink)) + throw new \InvalidArgumentException('The permaLink parameter must be boolean.'); + + $permaLink = $permaLink ? 'true' : 'false'; + + $this->addElement('guid', $id, array('isPermaLink' => $permaLink)); + } elseif ($this->version == Feed::ATOM) { + // Check if the given ID is an valid URI scheme (see RFC 4287 4.2.6) + // The list of valid schemes was generated from http://www.iana.org/assignments/uri-schemes + // by using only permanent or historical schemes. + $validSchemes = array('aaa', 'aaas', 'about', 'acap', 'acct', 'cap', 'cid', 'coap', 'coaps', 'crid', 'data', 'dav', 'dict', 'dns', 'example', 'fax', 'file', 'filesystem', 'ftp', 'geo', 'go', 'gopher', 'h323', 'http', 'https', 'iax', 'icap', 'im', 'imap', 'info', 'ipp', 'ipps', 'iris', 'iris.beep', 'iris.lwz', 'iris.xpc', 'iris.xpcs', 'jabber', 'ldap', 'mailserver', 'mailto', 'mid', 'modem', 'msrp', 'msrps', 'mtqp', 'mupdate', 'news', 'nfs', 'ni', 'nih', 'nntp', 'opaquelocktoken', 'pack', 'pkcs11', 'pop', 'pres', 'prospero', 'reload', 'rtsp', 'rtsps', 'rtspu', 'service', 'session', 'shttp', 'sieve', 'sip', 'sips', 'sms', 'snews', 'snmp', 'soap.beep', 'soap.beeps', 'stun', 'stuns', 'tag', 'tel', 'telnet', 'tftp', 'thismessage', 'tip', 'tn3270', 'turn', 'turns', 'tv', 'urn', 'vemmi', 'videotex', 'vnc', 'wais', 'ws', 'wss', 'xcon', 'xcon-userid', 'xmlrpc.beep', 'xmlrpc.beeps', 'xmpp', 'z39.50', 'z39.50r', 'z39.50s'); + $found = FALSE; + $checkId = strtolower($id); + + foreach($validSchemes as $scheme) + if (strrpos($checkId, $scheme . ':', -strlen($checkId)) !== FALSE) + { + $found = TRUE; + break; + } + + if (!$found) + throw new \InvalidArgumentException("The ID must begin with an IANA-registered URI scheme."); + + $this->addElement('id', $id, NULL, TRUE); + } else + throw new InvalidOperationException('A unique ID is not supported in RSS1 feeds.'); + + return $this; + } + + } // end of class Item diff --git a/module/download/vendor/FeedWriter/README.md b/module/download/vendor/FeedWriter/README.md new file mode 100644 index 00000000..5d1d1fba --- /dev/null +++ b/module/download/vendor/FeedWriter/README.md @@ -0,0 +1,42 @@ +# Generate **RSS 1.0**, **RSS 2.0** or **ATOM** Formatted Feeds + +This package can be used to generate feeds in either **RSS 1.0**, **RSS 2.0** or **ATOM** format. + +Applications can create a feed object, several feed item objects, set several types of properties of either feed and feed items, and add items to the feed. + +Once a feed is fully composed with its items, the feed class can generate the necessary XML structure to describe the feed in **RSS** or **ATOM** format. This structure can be directly sent to the browser, or just returned as string. + +## Requirements + +- PHP 5.3 or higher + +If you don't have **PHP 5.3** available on your system there is a version supporting **PHP 5.0** and above. See the `legacy-php-5.0` branch. + +## Documentation + +The documentation can be found in the `gh-pages` branch, or on [GitHub Pages](https://mibe.github.io/FeedWriter/). + +See the `/examples` directory for usage examples. + +See the `CHANGELOG.md` file for changes between the different versions. + +## Authors + +In chronological order: + +- [Anis uddin Ahmad](https://github.com/ajaxray) +- [Michael Bemmerl](https://github.com/mibe) +- Phil Freo +- Paul Ferrett +- Brennen Bearnes +- Michael Robinson +- Baptiste Fontaine +- Kristián Valentín +- Brandtley McMinn +- Julian Bogdani +- Cedric Gampert +- Yamek +- Thielj +- Pavel Khakhlou +- Daniel +- Tino Goratsch diff --git a/module/download/vendor/FeedWriter/RSS1.php b/module/download/vendor/FeedWriter/RSS1.php new file mode 100644 index 00000000..69ac1874 --- /dev/null +++ b/module/download/vendor/FeedWriter/RSS1.php @@ -0,0 +1,37 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating RSS1 feeds + * + * @package UniversalFeedWriter + */ +class RSS1 extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::RSS1); + } +} diff --git a/module/download/vendor/FeedWriter/RSS2.php b/module/download/vendor/FeedWriter/RSS2.php new file mode 100644 index 00000000..3fa7db8d --- /dev/null +++ b/module/download/vendor/FeedWriter/RSS2.php @@ -0,0 +1,37 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating RSS2 feeds + * + * @package UniversalFeedWriter + */ +class RSS2 extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::RSS2); + } +} diff --git a/module/download/view/add/add.css b/module/download/view/add/add.css new file mode 100644 index 00000000..dc0024c0 --- /dev/null +++ b/module/download/view/add/add.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/module/download/view/add/add.js.php b/module/download/view/add/add.js.php new file mode 100644 index 00000000..06cb3b0b --- /dev/null +++ b/module/download/view/add/add.js.php @@ -0,0 +1,54 @@ +/** + * 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/ + */ + +/** + * Soumission du formulaire pour enregistrer en brouillon + */ +$("#downloadAddDraft").on("click", function() { + $("#downloadAddState").val(0); + $("#downloadAddForm").trigger("submit"); +}); + +/** + * Options de commentaires + */ +$("#downloadAddCommentClose").on("change", function() { + if ($(this).is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } +}); + +$("#downloadAddCommentNotification").on("change", function() { + if ($(this).is(':checked') ) { + $("#downloadAddCommentGroupNotification").slideDown(); + } else { + $("#downloadAddCommentGroupNotification").slideUp(); + } +}); + + +$( document).ready(function() { + + if ($("#downloadAddCloseComment").is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } + + if ($("#downloadAddCommentNotification").is(':checked') ) { + $("#downloadAddCommentGroupNotification").slideDown(); + } else { + $("#downloadAddCommentGroupNotification").slideUp(); + } +}); \ No newline at end of file diff --git a/module/download/view/add/add.php b/module/download/view/add/add.php new file mode 100644 index 00000000..0b3376e7 --- /dev/null +++ b/module/download/view/add/add.php @@ -0,0 +1,184 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'value' => template::ico('left') + ]); ?> +
    +
    + true, + 'value' => 'Brouillon' + ]); ?> + true + ]); ?> +
    +
    + 'Publier' + ]); ?> +
    +
    +
    +
    +
    +

    Informations sur la ressource

    +
    +
    + 'Titre' + ]); ?> +
    +
    + 'Version' + ]); ?> +
    +
    + 'Publiée le' + ]); ?> +
    +
    +
    +
    + 'Auteur' + ]); ?> +
    +
    + 'Licence' + ]); ?> +
    +
    + 'Catégorie' + ]); + } else { + echo template::select('downloadAddCategorie', [''=>''], [ + 'label' => 'Pas de catégorie', + 'disabled' => true + ]); + } + ?> +
    +
    + 'Capture d\'écran', + 'language' => $this->getData(['user', $this->getUser('id'), 'language']), + 'type' => 1 + ]); ?> +
    +
    +
    +
    + 'Type de ressource', + 'selected' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'ressourceType']) + ]); ?> +
    +
    +
    +
    + 'Fichier', + 'language' => $this->getData(['user', $this->getUser('id'), 'language']), + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'file']) + ]); ?> +
    +
    + 'URL', + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'url']), + 'placeholder' => 'https://' + ]); ?> +
    +
    +
    +
    +
    +
    +
    +
    + 'editorWysiwyg' + ]); ?> +
    +
    +
    +
    +
    +

    Options de publication

    +
    +
    + 'Auteur', + 'selected' => $this->getUser('id'), + 'disabled' => $this->getUser('group') !== self::GROUP_ADMIN ? true : false + ]); ?> +
    +
    + 'L\'item n\'est visible qu\'après la date de publication prévue.', + 'label' => 'Date de publication', + 'value' => time() + ]); ?> +
    +
    + 'Edition - Suppression', + 'selected' => is_numeric($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'editConsent'])) ? $module::EDIT_GROUP : $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'editConsent']), + 'help' => 'Les utilisateurs des groupes supérieurs accèdent à l\'item sans restriction' + ]); ?> +
    +
    +
    +
    +
    +
    +
    +
    +

    Commentaires

    +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentClose']) + ]); ?> +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentApproved']), + '' + ]); ?> +
    +
    + 'Choix du nombre maximum de caractères pour chaque commentaire de l\'item, mise en forme html comprise.', + 'label' => 'Caractères par commentaire', + 'selected' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentMaxlength']) + ]); ?> +
    + +
    +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentNotification']), + ]); ?> +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentGroupNotification']), + 'help' => 'Editeurs = éditeurs + administrateurs
    Membres = membres + éditeurs + administrateurs' + ]); ?> +
    +
    +
    +
    +
    + diff --git a/module/download/view/categories/categories.css b/module/download/view/categories/categories.css new file mode 100644 index 00000000..1e998767 --- /dev/null +++ b/module/download/view/categories/categories.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 +*/ diff --git a/module/download/view/categories/categories.js.php b/module/download/view/categories/categories.js.php new file mode 100644 index 00000000..1898d01e --- /dev/null +++ b/module/download/view/categories/categories.js.php @@ -0,0 +1,23 @@ + /** + * 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/ + */ + +/** + * Confirmation de suppression + */ + $(".categoriesDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer cette catégorie ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); diff --git a/module/download/view/categories/categories.php b/module/download/view/categories/categories.php new file mode 100644 index 00000000..a5f8010d --- /dev/null +++ b/module/download/view/categories/categories.php @@ -0,0 +1,40 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'value' => template::ico('left') + ]); ?> +
    +
    +
    +
    +
    +

    Nouvelle catégorie

    +
    +
    + 'Nom', + 'value' => $this->getData(['module', $this->getUrl(0), 'categories', $this->getUrl(2), 'title']) + ]); ?> +
    +
    + 'plus', + 'value' => '', + ]); ?> +
    +
    +
    +
    + + + + + + + +
    Version n° + +
    \ No newline at end of file diff --git a/module/download/view/categoryEdit/categoryEdit.css b/module/download/view/categoryEdit/categoryEdit.css new file mode 100644 index 00000000..dc0024c0 --- /dev/null +++ b/module/download/view/categoryEdit/categoryEdit.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/module/download/view/categoryEdit/categoryEdit.php b/module/download/view/categoryEdit/categoryEdit.php new file mode 100644 index 00000000..d4d0c654 --- /dev/null +++ b/module/download/view/categoryEdit/categoryEdit.php @@ -0,0 +1,30 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/categories', + 'value' => template::ico('left') + ]); ?> +
    +
    + 'Valider' + ]); ?> +
    +
    +
    +
    +

    Éditer la catégorie

    +
    +
    + 'Nom', + 'value' => $this->getData(['module', $this->getUrl(0), 'categories', $this->getUrl(2)]) + ]); ?> +
    +
    +
    +
    +
    + \ No newline at end of file diff --git a/module/download/view/comment/comment.css b/module/download/view/comment/comment.css new file mode 100644 index 00000000..dc0024c0 --- /dev/null +++ b/module/download/view/comment/comment.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/module/download/view/comment/comment.js.php b/module/download/view/comment/comment.js.php new file mode 100644 index 00000000..958317d7 --- /dev/null +++ b/module/download/view/comment/comment.js.php @@ -0,0 +1,62 @@ +/** + * 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 + */ +$(".downloadCommentDelete").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Supprimer le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation d'approbation + */ +$(".downloadCommentApproved").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Approuver le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation de rejet + */ +$(".downloadCommentRejected").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Rejeter le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation de suppression en masse + */ +$(".downloadCommentDeleteAll").on("click", function() { + var _this = $(this); + var nombre = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'comment' ])); ?>"; + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + if( nombre === "1"){ + var message = "Supprimer le commentaire de l'item " + nom + " ?"; + } else{ + var message = "Supprimer les " + nombre + " commentaires de l'item " + nom + " ?"; + } + return core.confirm(message, function() { + $(location).attr("href", _this.attr("href")); + }); +}); diff --git a/module/download/view/comment/comment.php b/module/download/view/comment/comment.php new file mode 100644 index 00000000..e42d3fd3 --- /dev/null +++ b/module/download/view/comment/comment.php @@ -0,0 +1,22 @@ +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
    + + +
    + +
    + +
    + + '; ?> + +
    + + diff --git a/module/download/view/config/config.css b/module/download/view/config/config.css new file mode 100644 index 00000000..1e998767 --- /dev/null +++ b/module/download/view/config/config.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 +*/ diff --git a/module/download/view/config/config.js.php b/module/download/view/config/config.js.php new file mode 100644 index 00000000..d96c2c34 --- /dev/null +++ b/module/download/view/config/config.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 + */ +$(".downloadConfigDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer cet item ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/module/download/view/config/config.php b/module/download/view/config/config.php new file mode 100644 index 00000000..2ae385e9 --- /dev/null +++ b/module/download/view/config/config.php @@ -0,0 +1,40 @@ +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0), + 'value' => template::ico('left') + ]); ?> +
    +
    + helper::baseUrl() . $this->getUrl(0) . '/setup', + 'value' => template::ico('sliders'), + 'help' => 'Options' + ]); ?> +
    +
    + helper::baseUrl() . $this->getUrl(0) . '/categories', + 'value' => template::ico('table'), + 'help' => 'Catégories' + ]); ?> +
    +
    + helper::baseUrl() . $this->getUrl(0) . '/add', + 'class' => 'buttonGreen', + 'value' => template::ico('plus'), + 'help' => 'Ajouter une ressource' + ]); ?> +
    +
    + + + + + + +
    Version n° + +
    \ No newline at end of file diff --git a/module/download/view/edit/edit.css b/module/download/view/edit/edit.css new file mode 100644 index 00000000..dc0024c0 --- /dev/null +++ b/module/download/view/edit/edit.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/module/download/view/edit/edit.js.php b/module/download/view/edit/edit.js.php new file mode 100644 index 00000000..46cd1d5d --- /dev/null +++ b/module/download/view/edit/edit.js.php @@ -0,0 +1,77 @@ +/** + * 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/ + */ + + +// Lien de connexion +$("#downloadEditMailNotification").on("change", function() { + if($(this).is(":checked")) { + $("#formConfigGroup").show(); + } + else { + $("#formConfigGroup").hide(); + } +}).trigger("change"); + + +/** + * Soumission du formulaire pour enregistrer en brouillon + */ +$("#downloadEditDraft").on("click", function() { + $("#downloadEditState").val(0); + $("#downloadEditForm").trigger("submit"); +}); + +/** + * Options de commentaires + */ +$("#downloadEditCommentClose").on("change", function() { + if ($(this).is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } +}); + +$("#downloadEditCommentNotification").on("change", function() { + if ($(this).is(':checked') ) { + $("#downloadEditCommentGroupNotification").slideDown(); + } else { + $("#downloadEditCommentGroupNotification").slideUp(); + } +}); + + +$( document).ready(function() { + + /** Gestion des commentaires */ + + if ($("#downloadEditCloseComment").is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } + + if ($("#downloadEditCommentNotification").is(':checked') ) { + $("#downloadEditCommentGroupNotification").slideDown(); + } else { + $("#downloadEditCommentGroupNotification").slideUp(); + } + + + /** + * Paramétrage du sélecteur de date + * Supprimer les heures + + const datepickr = flatpickr("#downloadEditversionDate", {}); + datepickr.set (enableTime, false); + */ +}); \ No newline at end of file diff --git a/module/download/view/edit/edit.php b/module/download/view/edit/edit.php new file mode 100644 index 00000000..f9a69523 --- /dev/null +++ b/module/download/view/edit/edit.php @@ -0,0 +1,195 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
    +
    + true, + 'value' => 'Enregistrer en brouillon' + ]); ?> + true + ]); ?> +
    +
    + 'Publier' + ]); ?> + +
    +
    +
    +
    +
    +

    Informations sur la ressource

    +
    +
    + 'Titre', + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'title']) + ]); ?> +
    +
    + 'Version', + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'version']) + ]); ?> +
    +
    + 'Publiée le', + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'versionDate']) + ]); ?> +
    +
    +
    +
    + 'Auteur', + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'author']) + ]); ?> +
    +
    + 'Licence', + 'selected' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'license']) + ]); ?> +
    +
    + 'Catégorie', + 'selected' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'category']) + ]); + } else { + echo template::select('downloadEditCategorie', [''=>''], [ + 'label' => 'Pas de catégorie', + 'disabled' => true + ]); + } + ?> +
    +
    + 'Capture d\'écran', + 'language' => $this->getData(['user', $this->getUser('id'), 'language']), + 'type' => 1, + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'thumb']) + ]); ?> +
    +
    +
    +
    + 'Type de ressource', + 'selected' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'ressourceType']) + ]); ?> +
    +
    +
    +
    + 'Fichier', + 'language' => $this->getData(['user', $this->getUser('id'), 'language']), + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'file']) + ]); ?> +
    +
    + 'URL', + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'url']), + 'placeholder' => 'https://' + ]); ?> +
    +
    +
    +
    +
    +
    +
    +
    +
    + 'editorWysiwyg', + 'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'content']) + ]); ?> +
    +
    +
    +
    +
    +

    Options de publication

    +
    +
    + 'Auteur', + 'selected' => $this->getUser('id'), + 'disabled' => $this->getUser('group') !== self::GROUP_ADMIN ? true : false + ]); ?> +
    +
    + 'L\'item n\'est visible qu\'après la date de publication prévue.', + 'label' => 'Date de publication', + 'value' => time() + ]); ?> +
    +
    + 'Edition - Suppression', + 'selected' => is_numeric($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'editConsent'])) ? $module::EDIT_GROUP : $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'editConsent']), + 'help' => 'Les utilisateurs des groupes supérieurs accèdent à l\'item sans restriction' + ]); ?> +
    +
    +
    +
    +
    +
    +
    +
    +

    Commentaires

    +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentClose']) + ]); ?> +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentApproved']), + '' + ]); ?> +
    +
    + 'Choix du nombre maximum de caractères pour chaque commentaire de l\'item, mise en forme html comprise.', + 'label' => 'Caractères par commentaire', + 'selected' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentMaxlength']) + ]); ?> +
    + +
    +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentNotification']), + ]); ?> +
    +
    + $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'commentGroupNotification']), + 'help' => 'Editeurs = éditeurs + administrateurs
    Membres = membres + éditeurs + administrateurs' + ]); ?> +
    +
    +
    +
    +
    + diff --git a/module/download/view/index/index.css b/module/download/view/index/index.css new file mode 100644 index 00000000..21e784f9 --- /dev/null +++ b/module/download/view/index/index.css @@ -0,0 +1,69 @@ +.rowitem { + margin-bottom: 10px !important; +} +.downloadPicture { + float: none; + border: 1px; +} +.downloadPicture img { + width: 100%; + height: auto; + /* + border:1px solid lightgray; + box-shadow: 1px 1px 5px darkgray; + */ +} + +.downloadPicture:hover { + opacity: .7; +} +.row:after { + content: " "; + display: table; + clear: both; +} +.downloadComment { + padding-right: 10px; + float: right; +} +h2{ + margin-bottom: 5px; + margin-top: 0px; + padding: 0px; + +} +.downloadContent { + float: left; + margin-top: 5px; +} +.downloadDate { + font-size:0.8em; + font-style: italic; + /* + color: grey; + */ +} +@media (max-width: 768px) { + .downloadContent { + display: none; + } + + .downloadPicture img { + width: 50% ; + display: block; + margin-left: auto; + margin-right: auto; + } +} + +/* +* Flux RSS +*/ +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} \ No newline at end of file diff --git a/module/download/view/index/index.php b/module/download/view/index/index.php new file mode 100644 index 00000000..24850fb2 --- /dev/null +++ b/module/download/view/index/index.php @@ -0,0 +1,65 @@ + +
    +
    + $item): ?> +
    +
    + makeThumb( self::FILE_DIR . 'source/' . $item['thumb'], + self::FILE_DIR . 'thumb/' . $thumb, + self::THUMBS_WIDTH); + } + + ?> + + <?php echo $item['thumb']; ?> + +
    +
    + +
    +
    + +
    +
    + + getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?> + + + + + \ No newline at end of file diff --git a/module/download/view/item/item.css b/module/download/view/item/item.css new file mode 100644 index 00000000..cad4142d --- /dev/null +++ b/module/download/view/item/item.css @@ -0,0 +1,67 @@ + +#sectionTitle { + margin-top: 0; + margin-bottom: 5px; +} +.downloadItemPicture { + width: 100%; + border:1px solid lightgray; + box-shadow: 1px 1px 5px; +} +.downloadItemPictureleft { + float: left; + margin: 15px 10px 5px 0 ; +} +.downloadItemPictureright { + float: right; + margin: 15px 0 5px 10px ; +} + + +.pict20{ + width: 20%; +} +.pict30{ + width: 30%; +} +.pict40{ + width: 40%; +} +.pict50{ + width: 50%; +} +.pict100{ + width: 100%; + margin: 15px 0 20px 0 ; +} + +#downloaditemCommentShow { + cursor: text; +} +#downloaditemOr { + padding: 10px; +} +.downloadDate { + font-size:0.8em; + font-style: italic; + color: grey; +} +@media (max-width: 767px) { + .downloaditemPicture { + height:auto; + max-width: 100%;} + } + + +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} + +.itemInfo, .itemContent { + min-height: 25em; +} \ No newline at end of file diff --git a/module/download/view/item/item.js.php b/module/download/view/item/item.js.php new file mode 100644 index 00000000..a6559e0a --- /dev/null +++ b/module/download/view/item/item.js.php @@ -0,0 +1,50 @@ +/** + * 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/ + */ + +/** + * Incrémente les stats + */ +$('#downloadItemFile').click(function() { + $('#downloadStats').html(function(i, val) { return val*1+1 }); +}); + +/** + * Affiche le bloc pour rédiger un commentaire + */ +var commentShowDOM = $("#downloadItemCommentShow"); +commentShowDOM.on("click focus", function() { + $("#downloadItemCommentShowWrapper").fadeOut(function() { + $("#downloadItemCommentWrapper").fadeIn(); + $("#downloadItemCommentContent").trigger("focus"); + }); +}); +if($("#downloadItemCommentWrapper").find("textarea.notice,input.notice").length) { + commentShowDOM.trigger("click"); +} + +/** + * Cache le bloc pour rédiger un commentaire + */ +$("#downloadItemCommentHide").on("click focus", function() { + $("#downloadItemCommentWrapper").fadeOut(function() { + $("#downloadItemCommentShowWrapper").fadeIn(); + $("#downloadItemCommentContent").val(""); + $("#downloadItemCommentAuthor").val(""); + }); +}); + +/** + * Force le scroll vers les commentaires en cas d'erreur + */ +$("#downloadItemCommentForm").on("submit", function() { + $(location).attr("href", "#comment"); +}); \ No newline at end of file diff --git a/module/download/view/item/item.php b/module/download/view/item/item.php new file mode 100644 index 00000000..e23d74e4 --- /dev/null +++ b/module/download/view/item/item.php @@ -0,0 +1,226 @@ +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'thumb'])): ?> +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']) === null ? '100' : $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']); + $parts = explode('/',$this->getData(['module', $this->getUrl(0), 'posts',$this->getUrl(1), 'thumb'])); + $thumb = str_replace ($parts[(count($parts)-1)],'mini_' . $parts[(count($parts)-1)], $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'thumb'])); + echo '' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'thumb']) . ''; + ?> +
    +
    + + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'ressourceType']) !== 'content'): ?> +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'ressourceType'])) { + case 'file': + $href = helper::baseUrl() . $this->getUrl(0) . '/downloadFile/' . $this->getUrl(1) . '/' . $_SESSION['csrf']; + $target = '_self'; + break; + case 'url' : + $href = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'url']); + $target = '_blank'; + break; + } + ?> + $href, + 'value' => 'Télécharger', + 'target'=> $target + ]); + ?> +
    +
    + + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'version']) ): ?> +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'version']); ?> +
    +
    + + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'date']) ): ?> +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'date'])); + ?> +
    +
    + +
    +
    + Auteur : + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'author']); ?> + +
    +
    +
    +
    + Licence : + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'license'])]; ?> + +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'file'])): ?> +
    +
    + Téléchargements : '?> +
    +
    + +
    +
    +
    +
    + getData(['module', $this->getUrl(0),'posts', $this->getUrl(1), 'content']); ?> +
    +
    +
    +
    + + + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])); + $heure = helper::dateUTF8('%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'] + ) + ) + ): ?> + + Éditer + + + + getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?> + + +
    +
    +
    +
    + +
    +
    + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentClose'])): ?> +

    Cet item 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')): ?> +
    +
    + $this->getData(['config','connect', 'captchaStrong']), + 'type' => $this->getData(['config','connect', 'captchaType']) + ]); ?> +
    +
    + +
    +
    + 'buttonGrey', + 'value' => 'Annuler' + ]); ?> +
    +
    + 'Envoyer', + 'ico' => '' + ]); ?> +
    +
    +
    + +
    +
    + $comment): ?> +
    +

    + le + +

    + +
    +
    +
    +
    + \ No newline at end of file diff --git a/module/download/view/list/list.php b/module/download/view/list/list.php new file mode 100644 index 00000000..4b8f6d3c --- /dev/null +++ b/module/download/view/list/list.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/module/download/view/rss/rss.php b/module/download/view/rss/rss.php new file mode 100644 index 00000000..4b8f6d3c --- /dev/null +++ b/module/download/view/rss/rss.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/module/download/view/setup/setup.css b/module/download/view/setup/setup.css new file mode 100644 index 00000000..1e998767 --- /dev/null +++ b/module/download/view/setup/setup.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 +*/ diff --git a/module/download/view/setup/setup.php b/module/download/view/setup/setup.php new file mode 100644 index 00000000..565948e1 --- /dev/null +++ b/module/download/view/setup/setup.php @@ -0,0 +1,47 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'value' => template::ico('left') + ]); ?> +
    +
    + +
    +
    +
    +
    +
    +

    Paramètres +

    +
    +
    +
    + $this->getData(['module', $this->getUrl(0), 'config', 'feeds']), + ]); ?> +
    +
    + 'Etiquette du flux', + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'feedsLabel']) + ]); ?> +
    +
    + 'Articles par page', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']) + ]); ?> +
    +
    +
    +
    +
    +
    + +
    Version n° + +
    + diff --git a/module/download/view/stats/stats.css b/module/download/view/stats/stats.css new file mode 100644 index 00000000..dc0024c0 --- /dev/null +++ b/module/download/view/stats/stats.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/module/download/view/stats/stats.js.php b/module/download/view/stats/stats.js.php new file mode 100644 index 00000000..efc51d58 --- /dev/null +++ b/module/download/view/stats/stats.js.php @@ -0,0 +1,22 @@ +/** + * 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 + */ +$(".statsDeleteAll").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir purger les statistiques ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/module/download/view/stats/stats.php b/module/download/view/stats/stats.php new file mode 100644 index 00000000..5cca452b --- /dev/null +++ b/module/download/view/stats/stats.php @@ -0,0 +1,36 @@ + +
    +
    + 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
    +
    + 'statsDeleteAll buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/statsDeleteAll' . '/' . $this->getUrl(2) . '/'. $_SESSION['csrf'] , + 'ico' => 'cancel', + 'value' => 'Purger' + ]); ?> +
    +
    + +
    +
    +

    Nombre de téléchargements : + +

    +
    +
    + + + + + + +
    Version n° + +
    \ No newline at end of file diff --git a/module/registration/changes.md b/module/registration/changes.md new file mode 100644 index 00000000..db45eeed --- /dev/null +++ b/module/registration/changes.md @@ -0,0 +1,2 @@ +# Version 1.2 +- Compatiblité PHP 8.2 \ No newline at end of file diff --git a/module/registration/registration.php b/module/registration/registration.php new file mode 100644 index 00000000..5161e8c5 --- /dev/null +++ b/module/registration/registration.php @@ -0,0 +1,388 @@ + + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.com/ + */ + +class registration extends common { + + const VERSION = '1.2'; + const REALNAME = 'Auto-Inscription'; + const DELETE = true; + const UPDATE = '0.0'; + const DATADIRECTORY = ''; // Contenu localisé inclus par défaut (page.json et module.json) + + const STATUS_AWAITING = NULL; // En attente de validation du mail + const STATUS_VALIDATED = -2; // Mail validé en attente d'un admin + + public static $actions = [ + 'index' => self::GROUP_VISITOR, + 'validate' => self::GROUP_VISITOR, + 'config' => self::GROUP_ADMIN, + 'user' => self::GROUP_ADMIN, + 'delete' => self::GROUP_ADMIN, + 'edit' => self::GROUP_ADMIN + ]; + + public static $statusGroups = [ + self::STATUS_AWAITING => 'En attente', + self::STATUS_VALIDATED => 'Email validé', + ]; + + public static $timeLimit = [ + 2 => '2 minutes', + 5 => '5 minutes', + 10 => '10 minutes' + ]; + + public static $users = []; + + + + /** + * Liste des utilisateurs en attente + */ + public function user() { + $userIdsFirstnames = helper::arraycollumn($this->getData(['user']), 'firstname'); + ksort($userIdsFirstnames); + foreach($userIdsFirstnames as $userId => $userFirstname) { + if ( $this->getData(['user',$userId,'group']) === self::STATUS_AWAITING || + $this->getData(['user',$userId,'group']) === self::STATUS_VALIDATED ) { + self::$users[] = [ + $userId, + $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']), + self::$statusGroups[$this->getData(['user', $userId, 'group'])] , + helper::dateUTF8(date('Y-m-d G:i'), $this->getData(['user', $userId, 'timer'])), + template::button('registrationUserEdit' . $userId, [ + 'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $userId . '/' . $_SESSION['csrf'], + 'value' => template::ico('pencil') + ]), + template::button('registrationUserDelete' . $userId, [ + 'class' => 'userDelete red', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/delete/' . $userId . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + ]; + } + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Demandes d\'inscription', + 'view' => 'user' + ]); + } + + + /** + * Édition + */ + public function edit() { + if ($this->getUrl(3) !== $_SESSION['csrf'] && + $this->getUrl(4) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . 'user', + 'notification' => 'Action non autorisée' + ]); + } + // Accès refusé + if( + // L'utilisateur n'existe pas + $this->getData(['user', $this->getUrl(2)]) === null + // Droit d'édition + AND ( + // Impossible de s'auto-éditer + ( + $this->getUser('id') === $this->getUrl(2) + AND $this->getUrl('group') <= self::GROUP_VISITOR + ) + // Impossible d'éditer un autre utilisateur + OR ($this->getUrl('group') < self::GROUP_MODERATOR) + ) + ) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Accès autorisé + else { + // Soumission du formulaire + if($this->isPost()) { + // Modification du groupe + $this->setData([ + 'user', + $this->getUrl(2), + [ + 'firstname' => $this->getData(['user',$this->getUrl(2),'firstname']), + 'forgot' => 0, + 'group' => $this->getInput('registrationUserEditGroup',helper::FILTER_INT), + 'lastname' => $this->getData(['user',$this->getUrl(2),'lastname']), + 'mail' => $this->getData(['user',$this->getUrl(2),'mail']), + 'password' => $this->getData(['user',$this->getUrl(2),'password']), + 'connectFail' => $this->getData(['user',$this->getUrl(2),'connectFail']), + 'connectTimeout' => $this->getData(['user',$this->getUrl(2),'connectTimeout']), + 'accessUrl' => $this->getData(['user',$this->getUrl(2),'accessUrl']), + 'accessTimer' => $this->getData(['user',$this->getUrl(2),'accessTimer']), + 'accessCsrf' => $this->getData(['user',$this->getUrl(2),'accessCsrf']) + ] + ]); + // Notifier le user uniquement si le groupe est membre au moins membre + if ($this->getInput('registrationUserEditGroup') >= 1 ) { + $this->sendMail( + $this->getData(['user',$this->getUrl(2),'mail']), + 'Approbation de l\'inscription', + '

    ' . $this->getdata(['module','registration',$this->getUrl(0),'config','mailValidateContent']) . '

    ' + + ); + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/user', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => $this->getData(['user', $this->getUrl(2), 'firstname']) . ' ' . $this->getData(['user', $this->getUrl(2), 'lastname']), + 'view' => 'edit' + ]); + } + } + + + /** + * Suppression + */ + public function delete() { + // Accès refusé + if( + // L'utilisateur n'existe pas + $this->getData(['user', $this->getUrl(2)]) === null + // Groupe insuffisant + AND ($this->getUrl('group') < self::GROUP_MODERATOR) + ) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/user', + 'notification' => 'Action interdite' + ]); + } + // Bloque la suppression de son propre compte + elseif($this->getUser('id') === $this->getUrl(2)) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/user', + 'notification' => 'Impossible de supprimer votre propre compte' + ]); + } + // Suppression + else { + $this->deleteData(['user', $this->getUrl(2)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/user', + 'notification' => 'Utilisateur supprimé', + 'state' => true + ]); + } + } + + + /** + * Ajout + */ + public function index() { + // Soumission du formulaire + if($this->isPost()) { + $check=true; + // L'identifiant d'utilisateur est indisponible + $userId = $this->getInput('registrationAddId', helper::FILTER_ID, true); + if($this->getData(['module','registration', $userId])) { + self::$inputNotices['registrationAddId'] = 'Identifiant déjà utilisé'; + $check=false; + } + // Double vérification pour le mot de passe + if($this->getInput('registrationAddPassword', helper::FILTER_STRING_SHORT, true) !== $this->getInput('registrationAddConfirmPassword', helper::FILTER_STRING_SHORT, true)) { + self::$inputNotices['registrationAddConfirmPassword'] = 'Incorrect'; + $check = false; + } + // Le mail existe déjà + foreach($this->getData(['user']) as $usersId => $user) { + if($user['mail'] === $this->getInput('registrationAddMail', helper::FILTER_MAIL, true) ) { + self::$inputNotices['registrationAddMail'] = 'Mail déjà utilisé'; + $check = false; + break; + } + } + // Données de l'utilisateur + $userFirstname = $this->getInput('registrationAddFirstname', helper::FILTER_STRING_SHORT, true); + $userLastname = $this->getInput('registrationAddLastname', helper::FILTER_STRING_SHORT, true); + $userMail = $this->getInput('registrationAddMail', helper::FILTER_MAIL, true); + $userTimer = $this->getInput('registrationAddTimer', helper::FILTER_INT, true); + // Pas de nom saisi + if (empty($userFirstname) || + empty($userLastname) || + empty($this->getInput('registrationAddPassword', helper::FILTER_STRING_SHORT, true)) || + empty($this->getInput('registrationAddConfirmPassword', helper::FILTER_STRING_SHORT, true))) { + $check=false; + } + // Si tout est ok + if ($check === true) { + // création effective temporaire + $this->setData([ + 'user', + $userId, + [ + 'firstname' => $userFirstname, + 'lastname' => $userLastname, + 'mail' => $userMail, + 'password' => $this->getInput('registrationAddPassword', helper::FILTER_PASSWORD, true), + // pas de groupe afin de le différencier dans la liste des users + 'group' => null, + 'forgot' => 0, + 'timer' => $userTimer, + 'auth' => $_SESSION['csrf'], + 'status' => self::STATUS_AWAITING + ] + ]); + // Mail d'avertissement aux administrateurs + // Utilisateurs dans le groupe admin + $to = []; + foreach($this->getData(['user']) as $userId => $user) { + if($user['group'] == self::GROUP_ADMIN) { + $to[] = $user['mail']; + } + } + // Envoi du mail + if($to) { + $messageAdmin = $this->getdata(['module','registration',$this->getUrl(0),'config','state']) ? 'Une demande d\'inscription attend l`approbation d\'un administrateur.' : 'Un nouveau membre s\'est inscrit.'; + // Envoi le mail + $this->sendMail( + $to, + 'Auto-inscription sur le site ' . $this->getData(['config', 'title']), + '

    ' . $messageAdmin . '

    ' . + '

    Identifiant du compte : ' . $userId .' (' . $userFirstname . ' ' . $userLastname . ')
    ' . + 'Email : ' . $userMail . '

    ' . + 'Validation de l\'inscription' + ); + } + + // Mail de confirmation à l'utilisateur + // forger le lien de vérification + $validateLink = helper::baseUrl(true) . $this->getUrl() . '/validate/' . $userId . '/' . $_SESSION['csrf']; + // Envoi + $sentMailtoUser = false; + if($check === true) { + $sentMailtoUser = $this->sendMail( + $userMail, + 'Confirmation de votre inscription', + '

    ' . $this->getdata(['module','registration',$this->getUrl(0),'config','mailRegisterContent']) . '

    ' . + 'Activer votre compte' + ); + } + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl(), + //'redirect' => $validateLink, + 'notification' => $sentMailtoUser ? "Consultez votre messagerie, un mail vous a été envoyé." : 'Quelque chose n\'a pas fonctionné !', + 'state' => $sentMailtoUser ? true : false + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Inscription', + 'view' => 'index', + 'showBarEditButton' => true, + 'showPageContent' => true + ]); + } + + /** + * Vérification de l'email + */ + public function validate() { + // Vérifie la session + l'id + le timer + $check = true; + $notification = 'Bienvenue sur le site' . $this->getData(['config', 'title']) ; + $csrf = $this->getUrl(3); + $userId = $this->getUrl(2); + // Validité + if ( time() - $this->getData(['user',$userId,'timer']) <= (60 * $this->getdata(['module','registration',$this->getUrl(0),'config','pageTimeOut'])) ) { + $check = false; + $notification = 'Le lien n\'est plus valide'; + } + if (( $csrf !== $this->getData(['user',$userId,'auth']) ) ) { + $check = false; + $notification = 'Identifiant ou mot de passe inconnu'; + } + if ($check) { + $this->setData([ + 'user', + $userId, + [ + 'firstname' => $this->getData(['user',$userId,'firstname']), + 'lastname' => $this->getData(['user',$userId,'lastname']), + 'mail' => $this->getData(['user',$userId,'mail']), + 'password' => $this->getData(['user',$userId,'password']), + 'group' => $this->getdata(['module','registration',$this->getUrl(0),'config','state']) === true ? self::STATUS_VALIDATED : self::GROUP_MEMBER, + 'forgot' => 0, + 'timer' => $this->getData(['user',$userId,'timer']) + ] + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => $check ? helper::baseUrl() . $this->getdata(['module','registration',$this->getUrl(0),'config','pageSuccess']) : helper::baseUrl() . $this->getdata(['module','registration',$this->getUrl(0),'config','pageError']) , + 'notificaton' => $notification, + 'state' => $check + ]); + } + + /** + * Module de configuration + */ + public function config() { + // Soumission du formulaire + if($this->isPost()) { + // Lire les options et les enregistrer + $this->setData(['module','registration',$this->getUrl(0),'config', [ + 'timeOut' => $this->getInput('registrationConfigTimeOut',helper::FILTER_INT), + 'pageSuccess' => $this->getInput('registrationConfigSuccess'), + 'pageError' => $this->getInput('registrationConfigError'), + 'state' => $this->getInput('registrationConfigState',helper::FILTER_BOOLEAN), + 'mailRegisterContent' => $this->getInput('registrationconfigMailRegisterContent', null, true), + 'mailValidateContent' => $this->getInput('registrationconfigMailValidateContent', null, true), + ]]); + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(), + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Configuration', + 'view' => 'config', + 'vendor' => ['tinymce'] + ]); + } +} + diff --git a/module/registration/view/config/config.css b/module/registration/view/config/config.css new file mode 100644 index 00000000..51bbb482 --- /dev/null +++ b/module/registration/view/config/config.css @@ -0,0 +1,15 @@ +/** + * 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 CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.com/ + */ + +@import url("core/layout/admin.css"); \ No newline at end of file diff --git a/module/registration/view/config/config.php b/module/registration/view/config/config.php new file mode 100644 index 00000000..b641928f --- /dev/null +++ b/module/registration/view/config/config.php @@ -0,0 +1,92 @@ + + +
    +
    + '', + 'href' => helper::baseUrl() .'page/edit/' . $this->getUrl(0) , + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
    +
    + helper::baseUrl() .$this->getUrl(0) . '/user' , + 'value' => 'Inscriptions' + ]); ?> +
    +
    + 'green' + ]); ?> +
    +
    +
    +
    +
    +

    Paramètres

    +
    +
    + 'Validité du lien', + 'selected' => $this->getData(['module','registration',$this->getUrl(0),'config','timeOut']) + ]); ?> +
    +
    +
    +
    + getData(['page']), 'title', 'SORT_ASC'), [ + 'label' => 'Redirection après confirmation', + 'selected' => $this->getData(['module','registration',$this->getUrl(0),'config','pageSuccess']) + ]); ?> +
    +
    + getData(['page']), 'title', 'SORT_ASC'), [ + 'label' => 'Redirection après erreur', + 'selected' => $this->getData(['module','registration',$this->getUrl(0),'config','pageError']) + ]); ?> +
    +
    +
    +
    + Confirmez votre inscription en cliquant sur ce lien dans les ... minutes.

    '; ?> + 'Corps du mail de confirmation', + 'value' => !empty($this->getData(['module','registration',$this->getUrl(0),'config','mailRegisterContent'])) ? $this->getData(['module','registration',$this->getUrl(0),'config','mailRegisterContent']) : $messageDefault, + 'class' => 'editorWysiwyg', + 'help' => 'Précisez la durée de validité. Le lien sera inséré après ces explications.' + ]); ?> +
    +
    +
    +
    +
    +
    +
    +
    +

    Approbation préalable

    +
    +
    + $this->getData(['module','registration',$this->getUrl(0),'config','state']), + 'help' => 'Les comptes sont inactifs tant que les inscriptions ne sont pas approuvées par un administrateur.', + 'check' => true + ]); ?> +
    +
    +
    +
    + Votre inscription a été approuvée par un administrateur.

    '; ?> + 'Corps du mail d\'approbation', + 'value' =>!empty($this->getData(['module','registration',$this->getUrl(0),'config','mailValidateContent'])) ? $this->getData(['module','registration',$this->getUrl(0),'config','mailValidateContent']) : $messageDefault, + 'class' => 'editorWysiwyg' + ]); ?> +
    +
    +
    +
    +
    + +
    Version n° +
    diff --git a/module/registration/view/edit/edit.css b/module/registration/view/edit/edit.css new file mode 100644 index 00000000..04e97f12 --- /dev/null +++ b/module/registration/view/edit/edit.css @@ -0,0 +1,16 @@ +/** + * 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 CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.com/ + */ + + +@import url("core/layout/admin.css"); \ No newline at end of file diff --git a/module/registration/view/edit/edit.js.php b/module/registration/view/edit/edit.js.php new file mode 100644 index 00000000..05b585ab --- /dev/null +++ b/module/registration/view/edit/edit.js.php @@ -0,0 +1,19 @@ +/** + * 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 Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.com/ + */ + +/** + * Droits des groupes + */ +$("#registrationUserEditGroup").on("change", function() { + $(".registrationUserEditGroupDescription").hide(); + $("#registrationUserEditGroupDescription" + $(this).val()).show(); +}).trigger("change"); diff --git a/module/registration/view/edit/edit.php b/module/registration/view/edit/edit.php new file mode 100644 index 00000000..d7d25448 --- /dev/null +++ b/module/registration/view/edit/edit.php @@ -0,0 +1,111 @@ + +
    +
    + getUrl(3)): ?> + '', + 'href' => helper::baseUrl() . $this->geturl(0) . '/user', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> + + '', + 'href' => helper::baseUrl(false), + 'ico' => 'home', + 'value' => 'Accueil' + ]); ?> + +
    +
    + 'green' + ]); ?> +
    +
    +
    +
    +
    +

    Confirmation de l'inscription

    +
    +
    +
    +
    + 'off', + 'label' => 'Prénom', + 'value' => $this->getData(['user', $this->getUrl(2), 'firstname']), + 'disabled'=> true + ]); ?> +
    +
    + 'off', + 'label' => 'Nom', + 'value' => $this->getData(['user', $this->getUrl(2), 'lastname']), + 'disabled'=> true + ]); ?> +
    +
    +
    +
    + 'off', + 'label' => 'Adresse mail', + 'value' => $this->getData(['user', $this->getUrl(2), 'mail']), + 'disabled'=> true + ]); ?> +
    +
    +
    +
    + getData(['user', $this->getUrl(2), 'group'])];?> + 'État de l\'inscription', + 'value' => $status, + 'disabled'=> true, + 'help' => 'En attente : le mail n\'a pas encore été validé
    Email validé : approbation nécessaire.' + ]); ?> +
    +
    + 'Date', + 'value' => helper::dateUTF8(date('Y-m-d G:i'), $this->getData(['user', $userId, 'timer'])), + 'disabled'=> true + ]); ?> +
    +
    +
    + +
    + getUser('group') === self::GROUP_ADMIN): ?> + ($this->getUrl(2) === $this->getUser('id')), + 'help' => ($this->getUrl(2) === $this->getUser('id') ? 'Impossible de modifier votre propre groupe.' : ''), + 'label' => 'Groupe (Banni : en attente d\'approbation)', + 'selected' => $this->getData(['user', $this->getUrl(2), 'group']) + ]); ?> + Autorisations : +
      +
    • Accès aux pages privées membres
    • +
    +
      +
    • Accès aux pages privées membres et éditeurs
    • +
    • Ajout - Édition - Suppression de pages
    • +
    • Ajout - Édition - Suppression de fichiers
    • +
    +
      +
    • Accès à toutes les pages privées
    • +
    • Ajout - Édition - Suppression de pages
    • +
    • Ajout - Édition - Suppression de fichiers
    • +
    • Ajout / Édition / Suppression d'utilisateurs
    • +
    • Configuration du site
    • +
    • Personnalisation du thème
    • +
    + +
    +
    +
    +
    +
    + \ No newline at end of file diff --git a/module/registration/view/index/index.js.php b/module/registration/view/index/index.js.php new file mode 100644 index 00000000..3baf44f0 --- /dev/null +++ b/module/registration/view/index/index.js.php @@ -0,0 +1,47 @@ +/** + * 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 Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.com/ + */ + + +/** + * Affichage de l'id en simulant FILTER_ID + */ +$("#registrationAddId").on("change keydown keyup", function(event) { + var userId = $(this).val(); + if( + event.keyCode !== 8 // BACKSPACE + && event.keyCode !== 37 // LEFT + && event.keyCode !== 39 // RIGHT + && event.keyCode !== 46 // DELETE + && window.getSelection().toString() !== userId // Texte sélectionné + ) { + var searchReplace = { + "á": "a", "à": "a", "â": "a", "ä": "a", "ã": "a", "å": "a", "ç": "c", "é": "e", "è": "e", "ê": "e", "ë": "e", "í": "i", "ì": "i", "î": "i", "ï": "i", "ñ": "n", "ó": "o", "ò": "o", "ô": "o", "ö": "o", "õ": "o", "ú": "u", "ù": "u", "û": "u", "ü": "u", "ý": "y", "ÿ": "y", + "Á": "A", "À": "A", "Â": "A", "Ä": "A", "Ã": "A", "Å": "A", "Ç": "C", "É": "E", "È": "E", "Ê": "E", "Ë": "E", "Í": "I", "Ì": "I", "Î": "I", "Ï": "I", "Ñ": "N", "Ó": "O", "Ò": "O", "Ô": "O", "Ö": "O", "Õ": "O", "Ú": "U", "Ù": "U", "Û": "U", "Ü": "U", "Ý": "Y", "Ÿ": "Y", + "'": "-", "\"": "-", " ": "-" + }; + userId = userId.replace(/[áàâäãåçéèêëíìîïñóòôöõúùûüýÿ'" ]/ig, function(match) { + return searchReplace[match]; + }); + userId = userId.replace(/[^a-z0-9-]/ig, ""); + $(this).val(userId); + } +}); + +/** + * Droits des groupes + */ +$("#registrationAddGroup").on("change", function() { + $(".registrationAddGroupDescription").hide(); + $("#registrationAddGroupDescription" + $(this).val()).show(); +}).trigger("change"); + + diff --git a/module/registration/view/index/index.php b/module/registration/view/index/index.php new file mode 100644 index 00000000..3de76b6b --- /dev/null +++ b/module/registration/view/index/index.php @@ -0,0 +1,82 @@ + +
    +
    +
    +

    Identité

    +
    +
    + 'off', + 'label' => 'Prénom' + ]); ?> +
    +
    + 'off', + 'label' => 'Nom' + ]); ?> +
    +
    +
    +
    + 'off', + 'label' => 'Adresse mail' + ]); ?> +
    +
    +
    +
    +
    + self::GROUP_MEMBER + ]); ?> +
    +
    + +
    +

    Données de connexion

    +
    +
    + 'off', + 'label' => 'Identifiant de connexion' + ]); ?> +
    +
    +
    +
    + 'off', + 'label' => 'Mot de passe' + ]); ?> +
    +
    +
    +
    + 'off', + 'label' => 'Confirmation du mot de passe' + ]); + ?> +
    +
    +
    +
    +
    + time() + ]); + ?> +
    +
    +
    +
    +
    + 'Envoyer', + 'class' => 'green' + ]); ?> +
    +
    + diff --git a/module/registration/view/user/user.css b/module/registration/view/user/user.css new file mode 100644 index 00000000..04e97f12 --- /dev/null +++ b/module/registration/view/user/user.css @@ -0,0 +1,16 @@ +/** + * 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 CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.com/ + */ + + +@import url("core/layout/admin.css"); \ No newline at end of file diff --git a/module/registration/view/user/user.js.php b/module/registration/view/user/user.js.php new file mode 100644 index 00000000..1ed4c166 --- /dev/null +++ b/module/registration/view/user/user.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 Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.com/ + */ + +/** + * Confirmation de suppression + */ +$(".registrationUserDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer cet utilisateur ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/module/registration/view/user/user.php b/module/registration/view/user/user.php new file mode 100644 index 00000000..34650e34 --- /dev/null +++ b/module/registration/view/user/user.php @@ -0,0 +1,15 @@ +
    +
    + '', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'value' => 'Retour' + ]); ?> +
    +
    + + + + + + \ No newline at end of file diff --git a/module/registration/view/validate/validate.php b/module/registration/view/validate/validate.php new file mode 100644 index 00000000..923a0a1e --- /dev/null +++ b/module/registration/view/validate/validate.php @@ -0,0 +1,2 @@ + + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.com/ + * + */ + +class slider extends common +{ + + public static $actions = [ + 'config' => self::GROUP_MODERATOR, + 'update' => self::GROUP_MODERATOR, + 'theme' => self::GROUP_MODERATOR, + 'delete' => self::GROUP_MODERATOR, + 'dirs' => self::GROUP_MODERATOR, + 'index' => self::GROUP_VISITOR + ]; + + const VERSION = '5.0'; + const REALNAME = 'Slider'; + const DELETE = true; + const UPDATE = '0.0'; + const DATADIRECTORY = ''; // Contenu localisé inclus par défaut (page.json et module.json) + + public static $directories = []; + + public static $firstPictures = []; + + public static $galleries = []; + + public static $pictures = []; + + public static $pageList = []; + + //Visibilité des boutons de navigation + public static $namespace = [ + 'white-btns' => 'Blancs', + 'centered-btns' => 'Noirs', + 'transparent-btns' => 'Bandes invisibles', + 'large-btns' => 'Bandes grises', + ]; + + // Pager + public static $pager = [ + true => 'Puces visibles', + false => 'Puces invisibles' + ]; + + public static $auto = [ + true => 'Active', + false => 'Inactive' + ]; + + // Largeur + public static $screenWidth = [ + 640 => '640 pixels', + 720 => '720 pixels', + 768 => '768 pixels', + 800 => '800 pixels', + 854 => '854 pixels', + 1024 => '1024 pixels', + 1280 => '1280 pixels', + 1400 => '1400 pixels', + 1600 => '1600 pixels', + 1920 => '1920 pixels', + 0 => 'Largeur de l\'écran' + ]; + public static $selectedMaxwidth = 0; + + // Transition + public static $speed = [ + '500' => '500 ms', + '1000' => '1 s', + '1500' => '1.5 s', + '2000' => '2 s', + '2500' => '2.5 s', + '3000' => '3 s', + '3500' => '3.5 s' + ]; + + // Imeout + public static $timeout = [ + '500' => '500 ms', + '1000' => '1 s', + '1500' => '1.5 s', + '2000' => '2 s', + '3000' => '3 s', + '5000' => '5 s', + '7000' => '7 s', + '10000' => '10 s' + ]; + + //Visibilité de la légende + public static $visibilite_legende = [ + 'survol' => 'Au survol', + 'toujours' => 'Toujours visible', + 'jamais' => 'Jamais visible' + ]; + + //Position de la légende + public static $position_legende = [ + 'haut' => 'En haut', + 'bas' => 'En bas' + ]; + + //Temps d'apparition légende et boutons + public static $apparition = [ + 'opacity 0.2s ease-in' => '0.2s', + 'opacity 0.5s ease-in' => '0.5s', + 'opacity 1s ease-in' => '1s', + 'opacity 2s ease-in' => '2s' + ]; + + + //Choix du tri + public static $sort = [ + 'asc' => 'Alphabétique naturel', + 'dsc' => 'Alphabétique naturel inverse', + 'rand' => 'Aléatoire', + 'none' => 'Par défaut, sans tri', + ]; + + /** + * Mise à jour du dossier + */ + public function update() + { + // Soumission du formulaire + if ($this->isPost()) { + $this->setData([ + 'module', + $this->getUrl(0), + 'directory', + $this->getInput('galleryUpdateDirectory', helper::FILTER_STRING_SHORT, true) + ]); + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Configuration de la galerie', + 'view' => 'update' + ]); + } + + /** + * Configuration + */ + public function config() + { + // Initialise le module + $this->init(); + + // Liste des pages active à l'exclusion des barres latérales + $pagesId = $this->getHierarchy(null, false, null); + $excludeBar = $this->getHierarchy(null, false, true); + $pagesId = array_diff_key($pagesId, $excludeBar); + + // Construit le tableau pour le select du formulaire + foreach ($pagesId as $parentKey => $parentValue) { + self::$pageList[$parentKey] = $this->getData(['page', $parentKey, 'title']); + foreach ($parentValue as $childKey) { + self::$pageList[$childKey] = $this->getData(['page', $childKey, 'title']); + } + } + // Aucun choix + self::$pageList = array_merge([0 => ''], self::$pageList); + + // Soumission du formulaire + if ($this->isPost()) { + + $inputs['legends'] = $this->getInput('legends', null); + $inputs['uri'] = $this->getInput('sliderHref', null); + + // Supprime les points devant les extensions des clés à cause du système de BDD + foreach ($inputs as $keyinputs => $valuesinputs) { + foreach ($valuesinputs as $keyinput => $valueinput) { + $datas[$keyinputs][str_replace('.', '', $keyinput)] = $valueinput; + } + } + + $this->setData([ + 'module', + $this->getUrl(0), + [ + 'directory' => $this->getData(['module', $this->getUrl(0), 'directory']), + 'theme' => $this->getData(['module', $this->getUrl(0), 'theme']), + 'legends' => $datas['legends'], + 'uri' => $datas['uri'] + ] + ]); + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + + } + + // Met en forme le tableau + $directory = $this->getData(['module', $this->getUrl(0), 'directory']); + if ($directory && is_dir($directory)) { + $iterator = new DirectoryIterator($directory); + foreach ($iterator as $fileInfos) { + if ($fileInfos->isDot() === false and $fileInfos->isFile() and @getimagesize($fileInfos->getPathname())) { + self::$pictures[$fileInfos->getFilename()] = [ + $fileInfos->getFilename(), + template::text('legends[' . $fileInfos->getFilename() . ']', [ + 'value' => empty($this->getData(['module', $this->getUrl(0), 'legends', str_replace('.', '', $fileInfos->getFilename())])) + ? '' + : $this->getData(['module', $this->getUrl(0), 'legends', str_replace('.', '', $fileInfos->getFilename())]) + ]), + template::select('sliderHref[' . $fileInfos->getFilename() . ']', self::$pageList, [ + 'selected' => empty($this->getData(['module', $this->getUrl(0), 'uri', str_replace('.', '', $fileInfos->getFilename())])) + ? '' + : $this->getData(['module', $this->getUrl(0), 'uri', str_replace('.', '', $fileInfos->getFilename())]) + ]), + '
    ' + ]; + } + } + // Tri des images pour affichage de la liste dans la page d'édition + switch ($this->getData(['module', $this->getUrl(0), 'theme', 'tri'])) { + case 'dsc': + krsort(self::$pictures, SORT_NATURAL | SORT_FLAG_CASE); + break; + case 'asc': + ksort(self::$pictures, SORT_NATURAL | SORT_FLAG_CASE); + break; + case 'rand': + case 'none': + default: + break; + } + } + + + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Configuration du module', + 'view' => 'config' + ]); + } + + /** + * Suppression + */ + public function delete() + { + // $url prend l'adresse sans le token + // La galerie n'existe pas + if ($this->getData(['module', $this->getUrl(0), $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Suppression non autorisée' + ]); + } + // Suppression + else { + $this->deleteData(['module', $this->getUrl(0), $this->getUrl(2)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Galerie supprimée', + 'state' => true + ]); + } + } + + /** + * Liste des dossiers + */ + public function dirs() + { + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_JSON, + 'content' => $this->scanSubDir(self::FILE_DIR . 'source') + ]); + } + + + /** + * Édition + */ + public function theme() + { + // Soumission du formulaire + if ($this->isPost()) { + + // Adapte la largeur à celle de l'écran : + $maxWidth = $this->getInput('sliderThememaxWidth', helper::FILTER_INT) === 0 + ? intval(trim($this->getData(['theme', 'site', 'width']), 'px')) - 40 + : $this->getInput('sliderThememaxWidth', helper::FILTER_INT); + + // Equilibrer les durées + $speed = $this->getInput('sliderThemespeed', helper::FILTER_INT); + $timeout = $this->getInput('sliderThemeDiapoTime', helper::FILTER_INT); + if ($speed >= $timeout) { + // Valeurs en sortie + $notification = 'La durée de transition doit inférieure à la durée de l`\'image fixe'; + $state= false; + } else { + + $this->setData([ + 'module', + $this->getUrl(0), + [ + 'theme' => [ + 'pager' => $this->getInput('sliderThemePager', helper::FILTER_BOOLEAN), + 'auto' => $this->getInput('sliderThemeAuto', helper::FILTER_BOOLEAN), + 'maxWidth' => $maxWidth, + 'speed' => $speed, + 'timeout' => $timeout, + 'namespace' => $this->getInput('sliderThemeNameSpace', helper::FILTER_STRING_SHORT), + 'sort' => $this->getInput('sliderThemeTri', helper::FILTER_STRING_SHORT), + ], + 'directory' => $this->getData(['module', $this->getUrl(0), 'directory']), + 'legends' => $this->getData(['module', $this->getUrl(0), 'legends']), + 'uri' => $this->getData(['module', $this->getUrl(0), 'uri']), + ] + ]); + $notification = 'Modifications enregistrées'; + $state = true; + } + + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/theme', + 'notification' => $notification, + 'state' => $state + ]); + } + + // Sélection largeur de l'écran + self::$selectedMaxwidth = array_key_exists($this->getData(['module', $this->getUrl(0), 'theme', 'maxWidth']), self::$screenWidth) + ? $this->getData(['module', $this->getUrl(0), 'theme', 'maxWidth']) + : 0; + + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Thème', + 'view' => 'theme' + ]); + } + + /** + * Fonction index() modifiée par rapport au module Gallery + */ + public function index() + { + + $galleryId = $this->getUrl(0); + $directory = $this->getData(['module', $galleryId, 'directory']); + + // Images de la galerie + if (is_dir($directory)) { + $iterator = new DirectoryIterator($directory); + foreach ($iterator as $fileInfos) { + if ($fileInfos->isDot() === false and $fileInfos->isFile() and @getimagesize($fileInfos->getPathname())) { + self::$pictures[$directory . '/' . $fileInfos->getFilename()] = [ + 'legend' => $this->getData(['module', $galleryId, 'legends', str_replace('.', '', $fileInfos->getFilename())]), + 'uri' => $this->getData(['module', $galleryId, 'uri', str_replace('.', '', $fileInfos->getFilename())]), + ]; + //self::$pictures['uri'][$directory . '/' . $fileInfos->getFilename()] = ; + } + } + + // Tri des images par ordre alphabétique, alphabétique inverse, aléatoire ou pas + switch ($this->getData(['module', $galleryId, 'config', 'tri'])) { + case 'SORT_DSC': + krsort(self::$pictures, SORT_NATURAL | SORT_FLAG_CASE); + break; + case 'SORT_ASC': + ksort(self::$pictures, SORT_NATURAL | SORT_FLAG_CASE); + break; + case 'RAND': + break; + case 'NONE': + break; + default: + break; + } + } + + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'showPageContent' => true, + 'vendor' => [ + 'slider' + ], + 'view' => 'index' + ]); + } + + /** + * Scan le contenu d'un dossier et de ses sous-dossiers + * @param string $dir Dossier à scanner + * @return array + */ + private 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, $this->scanSubDir($dir . '/' . $fileInfos->getBasename())); + } + } + return $dirContent; + } + + private function init() + { + if (is_null($this->getData(['module', $this->getUrl(0), 'theme']))) { + + $this->setData([ + 'module', + $this->getUrl(0), + [ + 'theme' => [ + 'pager' => true, + 'auto' => true, + 'maxWidth' => '1280', + 'speed' => 1000, + 'timeout' => 3000, + 'namespace' => 'centered-btns', + 'tri' => 'RAND', + ], + 'directory' => null, + 'legends' => [], + 'uri' => [], + ] + ]); + } + } + +} \ No newline at end of file diff --git a/module/slider/vendor/slider/inc.json b/module/slider/vendor/slider/inc.json new file mode 100644 index 00000000..772fb24c --- /dev/null +++ b/module/slider/vendor/slider/inc.json @@ -0,0 +1,3 @@ +[ + "slider.js" +] \ No newline at end of file diff --git a/module/slider/vendor/slider/slider.js b/module/slider/vendor/slider/slider.js new file mode 100644 index 00000000..32ff39f2 --- /dev/null +++ b/module/slider/vendor/slider/slider.js @@ -0,0 +1,10 @@ +/*! http://responsiveslides.com v1.55 by @arielsalminen */ +(function(c,K,C){c.fn.responsiveSlides=function(m){var a=c.extend({auto:!0,speed:500,timeout:4E3,pager:!1,nav:!1,random:!1,pause:!1,pauseControls:!0,prevText:"Previous",nextText:"Next",maxwidth:"",navContainer:"",manualControls:"",namespace:"rslides",before:c.noop,after:c.noop},m);return this.each(function(){C++;var f=c(this),u,t,v,n,q,r,p=0,e=f.children(),D=e.length,h=parseFloat(a.speed),E=parseFloat(a.timeout),w=parseFloat(a.maxwidth),g=a.namespace,d=g+C,F=g+"_nav "+d+"_nav",x=g+"_here",k=d+"_on", +y=d+"_s",l=c("
      "),z={"float":"left",position:"relative",opacity:1,zIndex:2},A={"float":"none",position:"absolute",opacity:0,zIndex:1},G=function(){var b=(document.body||document.documentElement).style,a="transition";if("string"===typeof b[a])return!0;u=["Moz","Webkit","Khtml","O","ms"];var a=a.charAt(0).toUpperCase()+a.substr(1),c;for(c=0;c"+a+""});l.append(H);m.navContainer?c(a.navContainer).append(l):f.after(l)}a.manualControls&&(l=c(a.manualControls),l.addClass(g+"_tabs "+d+"_tabs"));(a.pager||a.manualControls)&&l.find("li").each(function(a){c(this).addClass(y+(a+1))});if(a.pager||a.manualControls)r= +l.find("a"),t=function(a){r.closest("li").removeClass(x).eq(a).addClass(x)};a.auto&&(v=function(){q=setInterval(function(){e.stop(!0,!0);var b=p+1"+a.prevText+"";m.navContainer?c(a.navContainer).append(g):f.after(g);var d=c("."+d+"_nav"),I=d.filter(".prev");d.bind("click",function(b){b.preventDefault();b=c("."+k);if(!b.queue("fx").length){var d=e.index(b);b=d-1;d=d+1w&&f.css("width",w)};J();c(K).bind("resize",function(){J()})}})}})(jQuery,this,0); + + diff --git a/module/slider/view/config/config.css b/module/slider/view/config/config.css new file mode 100644 index 00000000..ba8ba808 --- /dev/null +++ b/module/slider/view/config/config.css @@ -0,0 +1,22 @@ +/** + * 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-2023, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.fr/ + */ + +/** NE PAS EFFACER +* admin.css +*/ + +.galleryConfigError { + color: #F3674A; + font-weight: bold; +} diff --git a/module/slider/view/config/config.php b/module/slider/view/config/config.php new file mode 100644 index 00000000..def93168 --- /dev/null +++ b/module/slider/view/config/config.php @@ -0,0 +1,54 @@ + +
      +
      + 'buttonGrey', + 'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0), + 'value' => template::ico('left') + ]); ?> +
      +
      + helper::baseUrl() . $this->getUrl(0) . '/theme', + 'value' => template::ico('brush') + ]); ?> +
      +
      + helper::baseUrl() . $this->getUrl(0) . '/update', + 'value' => template::ico('folder') + ]); ?> +
      +
      + +
      +
      +
      +
      +
      +

      Galerie + getData(['module', $this->getUrl(0), 'directory']); + ?> +

      +
      +
      + +
      +
      +
      +
      + + + + + +
      +
      +
      +
      +
      + +
      Module Slider version n° + +
      \ No newline at end of file diff --git a/module/slider/view/index/black.gif b/module/slider/view/index/black.gif new file mode 100644 index 0000000000000000000000000000000000000000..2be4c3ee29305839d98bbe98888d3aa1b2a43624 GIT binary patch literal 359 zcmZ?wbhEHb^kJ}NIKsdnARu61VDSF^`}60|@87?_zP^6_`t<<;0SXEV2?+`F=g)U= zaJYZ}enCM&e}Dh~|Nj|C1d2adz&dn5B*;z%)+Y)oeJPpqGFGk2dA+Yd=X^=-{fc$( zYu^7qu%N(0N2>qClA@D2R`V~cDDhewwf;tw!h_pNj4j8L4{+OaG$4q>gB O6B`yfYbr7@SOWl~ZGf5p literal 0 HcmV?d00001 diff --git a/module/slider/view/index/index.css b/module/slider/view/index/index.css new file mode 100644 index 00000000..47748f28 --- /dev/null +++ b/module/slider/view/index/index.css @@ -0,0 +1,236 @@ + /** + * 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-2023, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.fr/ + */ + + /*! http://responsiveslides.com v1.55 by @arielsalminen */ + + .rslides { + position: relative; + list-style: none; + overflow: hidden; + width: 100%; + padding: 0; + margin: 0 auto; +} + +.rslides li { + -webkit-backface-visibility: hidden; + position: absolute; + display: none; + width: 100%; + left: 0; + top: 0; +} + +.rslides li:first-child { + position: relative; + display: block; + float: left; +} + +.rslides img { + display: block; + height: auto; + float: left; + width: 100%; + border: 0; +} + + #wrapper { + margin: 0 auto; + width: 100%; + margin-bottom: 50px; + } + + h1 { + font: 600 28px/36px sans-serif; + margin: 50px 0; + } + + h3 { + font: 600 18px/24px sans-serif; + color: #999; + margin: 0 0 20px; + } + + a { + color: #222; + } + + .rslides { + margin: 0 auto; + } + + .rslides_container { + margin-bottom: 50px; + position: relative; + float: left; + width: 100%; + } + + .centered-btns_nav { + z-index: 3; + position: absolute; + -webkit-tap-highlight-color: rgba(0,0,0,0); + top: 50%; + left: 0; + opacity: 0.7; + text-indent: -9999px; + overflow: hidden; + text-decoration: none; + height: 61px; + width: 38px; + background: transparent url("module/slider/view/index/black.gif") no-repeat left top; + margin-top: -45px; + } + + .centered-btns_nav:active { + opacity: 1.0; + } + + .centered-btns_nav.next { + left: auto; + background-position: right top; + right: 0; + } + + .transparent-btns_nav { + z-index: 3; + position: absolute; + -webkit-tap-highlight-color: rgba(0,0,0,0); + top: 0; + left: 0; + display: block; + background: #fff; /* Fix for IE6-9 */ + opacity: 0; + filter: alpha(opacity=1); + width: 48%; + text-indent: -9999px; + overflow: hidden; + height: 91%; + } + + .transparent-btns_nav.next { + left: auto; + right: 0; + } + + .large-btns_nav { + z-index: 3; + position: absolute; + -webkit-tap-highlight-color: rgba(0,0,0,0); + opacity: 0.6; + text-indent: -9999px; + overflow: hidden; + top: 0; + bottom: 0; + left: 0; + background: #000 url("module/slider/view/index/black.gif") no-repeat left 50%; + width: 38px; + } + + .large-btns_nav:active { + opacity: 1.0; + } + + .large-btns_nav.next { + left: auto; + background-position: right 50%; + right: 0; + } + + /** + Boutons blancs + */ + .white-btns_nav { + z-index: 3; + position: absolute; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + opacity: 0.6; + text-indent: -9999px; + overflow: hidden; + top: 0; + bottom: 0; + left: 0; + background: transparent url("module/slider/view/index/white.gif") no-repeat left 50%; + width: 38px; +} + +.white-btns_nav:active { + opacity: 1.0; +} + +.white-btns_nav.next { + left: auto; + background-position: right 50%; + right: 0; +} + + /** + Boutons blancs + */ + .centered-btns_nav:focus, + .transparent-btns_nav:focus, + .large-btns_nav:focus, + .white-btns_nav:focus { + outline: none; + } + + .centered-btns_tabs, + .transparent-btns_tabs, + .large-btns_tabs, + .white-btns_tabs { + margin-top: 10px; + text-align: center; + } + + .centered-btns_tabs li, + .transparent-btns_tabs li, + .large-btns_tabs li, + .white-btns_tabs li { + display: inline; + float: none; + _float: left; + *float: left; + margin-right: 5px; + } + + .centered-btns_tabs a, + .transparent-btns_tabs a, + .large-btns_tabs a, + .white-btns_tabs a { + text-indent: -9999px; + overflow: hidden; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + background: #ccc; + background: rgba(0, 0, 0, .2); + display: inline-block; + _display: block; + *display: block; + -webkit-box-shadow: inset 0 0 2px 0 rgba(0, 0, 0, .3); + -moz-box-shadow: inset 0 0 2px 0 rgba(0, 0, 0, .3); + box-shadow: inset 0 0 2px 0 rgba(0, 0, 0, .3); + width: 9px; + height: 9px; + } + + .centered-btns_here a, + .transparent-btns_here a, + .large-btns_here a, + .white-btns_here a { + background: #222; + background: rgba(0,0,0, .8); + } + \ No newline at end of file diff --git a/module/slider/view/index/index.js.php b/module/slider/view/index/index.js.php new file mode 100644 index 00000000..b255edfc --- /dev/null +++ b/module/slider/view/index/index.js.php @@ -0,0 +1,61 @@ +/** + * 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-2023, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.fr/ + */ + +/** + * + auto: true, // Boolean: Animate automatically, true or false + speed: 500, // Integer: Speed of the transition, in milliseconds + timeout: 4000, // Integer: Time between slide transitions, in milliseconds + pager: false, // Boolean: Show pager, true or false + nav: false, // Boolean: Show navigation, true or false + random: false, // Boolean: Randomize the order of the slides, true or false + pause: false, // Boolean: Pause on hover, true or false + pauseControls: true, // Boolean: Pause when hovering controls, true or false + prevText: "Previous", // String: Text for the "previous" button + nextText: "Next", // String: Text for the "next" button + maxwidth: "", // Integer: Max-width of the slideshow, in pixels + navContainer: "", // Selector: Where controls should be appended to, default is after the 'ul' + manualControls: "", // Selector: Declare custom pager navigation + namespace: "rslides", // String: Change the default namespace used + before: function(){}, // Function: Before callback + after: function(){} // Function: After callback + */ + + +$(document).ready(function() { + + var maxWidth = "getData(['module', $this->getUrl(0),'theme', 'maxWidth']); ?>"; + var sort = "getData(['module', $this->getUrl(0),'theme', 'sort']); ?>"; + // Réduction de la taille maximale selon la largeur de la section + var screenSize = $("section").width() - 40; + maxWidth = maxWidth < screenSize ? maxWidth : screenSize; + $("#wrapper").css('width', maxWidth); + $(function() { + $("#sliders").responsiveSlides({ + pager: "getData(['module', $this->getUrl(0), 'theme', 'pager']); ?>", + auto: "getData(['module', $this->getUrl(0), 'theme', 'auto']); ?>", + maxwidth: maxWidth, + speed: "getData(['module', $this->getUrl(0), 'theme', 'speed']); ?>", + timeout: "getData(['module', $this->getUrl(0), 'theme', 'timeout']); ?>", + namespace: "getData(['module', $this->getUrl(0), 'theme', 'namespace']); ?>", + nav: true, + random: sort == "random" ? true : false, + }); + }); + + + + + +}); \ No newline at end of file diff --git a/module/slider/view/index/index.php b/module/slider/view/index/index.php new file mode 100644 index 00000000..82eb530f --- /dev/null +++ b/module/slider/view/index/index.php @@ -0,0 +1,26 @@ + +
      +
      + +
      +
      +
    + + + +
    +
    + \ No newline at end of file diff --git a/module/slider/view/index/white.gif b/module/slider/view/index/white.gif new file mode 100644 index 0000000000000000000000000000000000000000..716e22a560031527b48f467bb0cdab02ac95559f GIT binary patch literal 1219 zcmZ?wbh9u|^kJ}NC}&{MVE_UUyB$a~GBPqTF)=eUv#_wRva+(Vv9YtWb8v8QadB~T zbMx@<@bdEV@$vEV^9u+F2nq@c2?>dah=_@aiHnO%N=iyeNl8mf%gV~i$;rvf%PT4> zDk&+csHmu_s;aB2Yieq0X=&-`=;-O`>Feto8X6iK8=IJzn3|fJnVFfJn_E~|SX*1$ z*x1tIXOE!ySux4czAevdU|lml?Af#D&6_uW z{`>_C7A#!2aM7Ygix)3mx^(G^6)RS)TD5xh>Wv#WZr!?d=gytGcJ11|d-t9_d-m?# zyKmpV{rmSHIB?+5p+kocA3k>M*zx1XPo6w^>eQ(-XU?2Gd-nYK^A|5(ymaZ(<;$0^ zT)A@f>eXx4u3f)={l<+OH*em&b?esc+qduDy?gK8z5Dm?KX~xq;lqcI9zA;e`0>-H zPoF=3{^G@pmoHzwdiCn{>(_7Iym|Zf?fdudKYaM`@#Du&pFVy5{Q1k5FJHfY{r2tK z_wV0-{P^+n=g(iie*OOa`_G?0fB*jd_wV2T|Npr;zA!KfGH`rg=lB4O|L*M{7#SFq zQ_lh!3`|U*w86kA`SFc6{ z;s7^a^3#l-YIUef7+Qb|z}`^-dXwWngFUB=$A$$5n>mEFVoq#Wc(`3a*=vr+#zjZF zC5*G~oY=Vdc)x;kmyGA8B_}6q1h0xYxoPR?=?2NC=6G&ic6PRfw$`M>&o3SGo*?3A zwNk^USJdUnk0TtKXZvKMswO>2Ryo$pZhA;(uLXxECyQ#&2g#K$PI9quXtC^E95`_r zFT(*lNs*!nqN_RNj$GIk=*P>#@a5d!6))a3@6cw;ml0XU(r`d~4bRhxlRmwN8N4)} zRXpdsbHMbB&$ScnC!VwWFDcuj!p@n%kaaU_&y}aI9}8t~D{I+u%#2AO$}K)b(c7QGHg7`d9 zX@<4~T!|US0|S333OF~5o!r>muBxDz + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2023, Frédéric Tempez + * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International + * @link http://zwiicms.fr/ + */ + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/slider/view/theme/theme.js.php b/module/slider/view/theme/theme.js.php new file mode 100644 index 00000000..f72a4534 --- /dev/null +++ b/module/slider/view/theme/theme.js.php @@ -0,0 +1,51 @@ +/** + * 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.com/ + */ + +/** + * Liste des dossiers + */ +var oldResult = []; +var directoryDOM = $("#galleryEditDirectory"); +var directoryOldDOM = $("#galleryEditDirectoryOld"); +function dirs() { + $.ajax({ + type: "POST", + url: "getUrl(0); ?>/dirs", + success: function(result) { + if($(result).not(oldResult).length !== 0 || $(oldResult).not(result).length !== 0) { + directoryDOM.empty(); + for(var i = 0; i < result.length; i++) { + directoryDOM.append(function(i) { + var option = $("
    - - - -
    -
    - \ No newline at end of file diff --git a/module/slider/view/index/white.gif b/module/slider/view/index/white.gif deleted file mode 100644 index 716e22a560031527b48f467bb0cdab02ac95559f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1219 zcmZ?wbh9u|^kJ}NC}&{MVE_UUyB$a~GBPqTF)=eUv#_wRva+(Vv9YtWb8v8QadB~T zbMx@<@bdEV@$vEV^9u+F2nq@c2?>dah=_@aiHnO%N=iyeNl8mf%gV~i$;rvf%PT4> zDk&+csHmu_s;aB2Yieq0X=&-`=;-O`>Feto8X6iK8=IJzn3|fJnVFfJn_E~|SX*1$ z*x1tIXOE!ySux4czAevdU|lml?Af#D&6_uW z{`>_C7A#!2aM7Ygix)3mx^(G^6)RS)TD5xh>Wv#WZr!?d=gytGcJ11|d-t9_d-m?# zyKmpV{rmSHIB?+5p+kocA3k>M*zx1XPo6w^>eQ(-XU?2Gd-nYK^A|5(ymaZ(<;$0^ zT)A@f>eXx4u3f)={l<+OH*em&b?esc+qduDy?gK8z5Dm?KX~xq;lqcI9zA;e`0>-H zPoF=3{^G@pmoHzwdiCn{>(_7Iym|Zf?fdudKYaM`@#Du&pFVy5{Q1k5FJHfY{r2tK z_wV0-{P^+n=g(iie*OOa`_G?0fB*jd_wV2T|Npr;zA!KfGH`rg=lB4O|L*M{7#SFq zQ_lh!3`|U*w86kA`SFc6{ z;s7^a^3#l-YIUef7+Qb|z}`^-dXwWngFUB=$A$$5n>mEFVoq#Wc(`3a*=vr+#zjZF zC5*G~oY=Vdc)x;kmyGA8B_}6q1h0xYxoPR?=?2NC=6G&ic6PRfw$`M>&o3SGo*?3A zwNk^USJdUnk0TtKXZvKMswO>2Ryo$pZhA;(uLXxECyQ#&2g#K$PI9quXtC^E95`_r zFT(*lNs*!nqN_RNj$GIk=*P>#@a5d!6))a3@6cw;ml0XU(r`d~4bRhxlRmwN8N4)} zRXpdsbHMbB&$ScnC!VwWFDcuj!p@n%kaaU_&y}aI9}8t~D{I+u%#2AO$}K)b(c7QGHg7`d9 zX@<4~T!|US0|S333OF~5o!r>muBxDz - * @copyright Copyright (C) 2008-2018, Rémi Jean - * @author Frédéric Tempez - * @copyright Copyright (C) 2018-2023, Frédéric Tempez - * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International - * @link http://zwiicms.fr/ - */ - -/** NE PAS EFFACER -* admin.css -*/ \ No newline at end of file diff --git a/module/slider/view/theme/theme.js.php b/module/slider/view/theme/theme.js.php deleted file mode 100644 index f72a4534..00000000 --- a/module/slider/view/theme/theme.js.php +++ /dev/null @@ -1,51 +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.com/ - */ - -/** - * Liste des dossiers - */ -var oldResult = []; -var directoryDOM = $("#galleryEditDirectory"); -var directoryOldDOM = $("#galleryEditDirectoryOld"); -function dirs() { - $.ajax({ - type: "POST", - url: "getUrl(0); ?>/dirs", - success: function(result) { - if($(result).not(oldResult).length !== 0 || $(oldResult).not(result).length !== 0) { - directoryDOM.empty(); - for(var i = 0; i < result.length; i++) { - directoryDOM.append(function(i) { - var option = $("