Changes In Branch dev Excluding Merge-Ins
This is equivalent to a diff from 2899c91022 to 8817cad74d
2023-09-27
| ||
15:22 | Fix typo : parent -> parente Leaf check-in: 8817cad74d user: bohwaz tags: dev | |
14:52 | Fix breadcrumbs when selecting a parent page check-in: 1cf59f1e3c user: bohwaz tags: dev, 1.3.0-rc14 | |
2023-09-13
| ||
15:03 | Merge with trunk check-in: 03930d1c1f user: bohwaz tags: dev | |
2023-09-10
| ||
16:54 | Use Date object for dates without timestamp Leaf check-in: 2899c91022 user: bohwaz tags: trunk, stable | |
2023-09-04
| ||
23:27 | Rebuild users indexes after the collation has change in version 1.2.10 check-in: ab68937246 user: bohwaz tags: trunk, stable, 1.2.11 | |
Modified .fossil-settings/ignore-glob from [97a282b8eb] to [962019af50].
1 2 3 4 5 6 | src/data/* src/*.tar.gz src/*.asc src/*.log src/include/lib/KD2 src/debug_sql.sqlite | > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | src/data/* src/*.tar.gz src/*.asc src/*.log src/include/lib/KD2 src/debug_sql.sqlite src/modules/* src/config.local.php build/windows/*.exe build/windows/php.zip build/windows/install_dir build/*.tar.gz* build/debian/*.deb src/psalm.phar |
Modified build/debian/config.debian.php from [88a7161654] to [f3119a8708].
1 2 | <?php | | > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Paheko; const SQLITE_JOURNAL_MODE = 'WAL'; const ENABLE_UPGRADES = false; if (shell_exec('which pdftotext')) { define('Paheko\PDFTOTEXT_COMMAND', 'pdftotext'); } if (shell_exec('which ssconvert')) { define('Paheko\CALC_CONVERT_COMMAND', 'ssconvert'); } elseif (shell_exec('which unoconv')) { define('Paheko\CALC_CONVERT_COMMAND', 'unoconv'); } if (!empty($_ENV['PAHEKO_STANDALONE'])) { $home = $_ENV['HOME']; // Config directory if (empty($_ENV['XDG_CONFIG_HOME'])) |
︙ | ︙ | |||
38 39 40 41 42 43 44 | rename($_ENV['XDG_DATA_HOME'] . '/garradin', $_ENV['XDG_DATA_HOME'] . '/paheko'); } if (!file_exists($_ENV['XDG_DATA_HOME'] . '/paheko')) { mkdir($_ENV['XDG_DATA_HOME'] . '/paheko', 0700, true); } | | | | | | > | | | | | | | | > > > > > > > | | | > > > > > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | rename($_ENV['XDG_DATA_HOME'] . '/garradin', $_ENV['XDG_DATA_HOME'] . '/paheko'); } if (!file_exists($_ENV['XDG_DATA_HOME'] . '/paheko')) { mkdir($_ENV['XDG_DATA_HOME'] . '/paheko', 0700, true); } if (!defined('Paheko\DATA_ROOT')) { define('Paheko\DATA_ROOT', $_ENV['XDG_DATA_HOME'] . '/paheko'); } // Cache directory: temporary stuff if (empty($_ENV['XDG_CACHE_HOME'])) { $_ENV['XDG_CACHE_HOME'] = $home . '/.cache'; } if (file_exists($_ENV['XDG_CACHE_HOME'] . '/garradin')) { rename($_ENV['XDG_CACHE_HOME'] . '/garradin', $_ENV['XDG_CACHE_HOME'] . '/paheko'); } if (!file_exists($_ENV['XDG_CACHE_HOME'] . '/paheko')) { mkdir($_ENV['XDG_CACHE_HOME'] . '/paheko', 0700, true); } if (!defined('Paheko\CACHE_ROOT')) { define('Paheko\CACHE_ROOT', $_ENV['XDG_CACHE_HOME'] . '/paheko'); } if (!defined('Paheko\DB_FILE')) { $last_file = $_ENV['XDG_CONFIG_HOME'] . '/paheko/last'; if ($_ENV['PAHEKO_STANDALONE'] != 1) { $last_sqlite = trim($_ENV['PAHEKO_STANDALONE']); } else if (file_exists($last_file)) { $last_sqlite = trim(file_get_contents($last_file)); $last_sqlite = str_replace('.local/share/garradin', '.local/share/paheko', $last_sqlite); } else { $last_sqlite = $_ENV['XDG_DATA_HOME'] . '/paheko/association.sqlite'; } file_put_contents($last_file, $last_sqlite); define('Paheko\DB_FILE', $last_sqlite); } if (!defined('Paheko\LOCAL_LOGIN')) { define('Paheko\LOCAL_LOGIN', -1); } } else { if (file_exists('/etc/paheko/config.php')) { require_once '/etc/paheko/config.php'; } if (!defined('Paheko\DATA_ROOT')) { define('Paheko\DATA_ROOT', '/var/lib/paheko'); } if (!defined('Paheko\CACHE_ROOT')) { define('Paheko\CACHE_ROOT', '/var/cache/paheko'); } } if (file_exists(DATA_ROOT . '/plugins')) { define('Paheko\PLUGINS_ROOT', DATA_ROOT . '/plugins'); } else { define('Paheko\PLUGINS_ROOT', __DIR__ . '/plugins'); } if (!defined('Paheko\SECRET_KEY')) { if (file_exists(CACHE_ROOT . '/key')) { define('Paheko\SECRET_KEY', trim(file_get_contents(CACHE_ROOT . '/key'))); } else { define('Paheko\SECRET_KEY', base64_encode(random_bytes(64))); file_put_contents(CACHE_ROOT . '/key', SECRET_KEY); } } // Disable PDF for CLI server if (PHP_SAPI == 'cli-server' && !defined('Paheko\PDF_COMMAND') && !file_exists(PLUGINS_ROOT . '/dompdf')) { define('Paheko\PDF_COMMAND', null); } |
Modified build/debian/makedeb.sh from [ed98f1ed48] to [dd8d4f904f].
1 2 3 4 5 6 7 8 9 10 11 | #!/bin/bash # Ripped from fossil makdedeb.sh DEB_REV=${1-1} # .deb package build/revision number. PACKAGE_DEBNAME=paheko THISDIR=${PWD} DEB_ARCH_NAME=all PACKAGE_VERSION=`cat ../../src/VERSION` | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/bin/bash # Ripped from fossil makdedeb.sh DEB_REV=${1-1} # .deb package build/revision number. PACKAGE_DEBNAME=paheko THISDIR=${PWD} DEB_ARCH_NAME=all PACKAGE_VERSION=`cat ../../src/VERSION` [ ! -f ../paheko-${PACKAGE_VERSION}.tar.gz ] && (cd ../../src; make release) tar xzvf ../paheko-${PACKAGE_VERSION}.tar.gz -C /tmp SRCDIR="/tmp/paheko-${PACKAGE_VERSION}" test -e ${SRCDIR} || { echo "This script must be run from a BUILT copy of the source tree." exit 1 } |
︙ | ︙ | |||
34 35 36 37 38 39 40 | mkdir -p "${DEBLOCALPREFIX}/share/applications" cp ${THISDIR}/paheko.desktop "${DEBLOCALPREFIX}/share/applications/" CODEDIR=${DEBLOCALPREFIX}/share/${PACKAGE_DEBNAME} mkdir -p ${CODEDIR} cp -r ${SRCDIR}/* ${CODEDIR} cp ${THISDIR}/config.debian.php ${CODEDIR}/config.local.php | > | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | mkdir -p "${DEBLOCALPREFIX}/share/applications" cp ${THISDIR}/paheko.desktop "${DEBLOCALPREFIX}/share/applications/" CODEDIR=${DEBLOCALPREFIX}/share/${PACKAGE_DEBNAME} mkdir -p ${CODEDIR} cp -r ${SRCDIR}/* ${CODEDIR} cp ${THISDIR}/config.debian.php ${CODEDIR}/config.local.php mv ${CODEDIR}/data/plugins ${CODEDIR}/plugins rm -rf ${CODEDIR}/*.sqlite ${CODEDIR}/data cp ${THISDIR}/paheko.png "${CODEDIR}" mkdir -p "${DEBROOT}/var/lib/${PACKAGE_DEBNAME}" mkdir -p "${DEBROOT}/var/cache/${PACKAGE_DEBNAME}" mkdir -p "${DEBROOT}/etc/${PACKAGE_DEBNAME}" # Cleaning files that will be copied to /usr/share/doc |
︙ | ︙ | |||
123 124 125 126 127 128 129 | echo "Generating ${CONTROL}..." cat <<EOF > ${CONTROL} Package: ${PACKAGE_DEBNAME} Section: web Priority: optional Maintainer: Paheko <paheko@paheko.eu> Architecture: ${DEB_ARCH_NAME} | | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | echo "Generating ${CONTROL}..." cat <<EOF > ${CONTROL} Package: ${PACKAGE_DEBNAME} Section: web Priority: optional Maintainer: Paheko <paheko@paheko.eu> Architecture: ${DEB_ARCH_NAME} Depends: dash | bash, php-cli (>=7.4), php-sqlite3, php-intl, php-mbstring, sensible-utils Version: ${PACKAGE_DEB_VERSION} Suggests: php-imagick Replaces: garradin (<< 1.2.3~) Breaks: garradin (<< 1.2.3~) Homepage: https://fossil.kd2.org/paheko/ Description: Paheko is a tool to manage non-profit organizations. It's only available in french. Description-fr: Gestionnaire d'association en interface web ou CLI. Paheko est un gestionnaire d'association à but non lucratif. |
︙ | ︙ |
Modified build/debian/paheko from [e989bd5817] to [a6de924cf5].
︙ | ︙ | |||
41 42 43 44 45 46 47 | -h|--help) cat <<EOF Usage : $0 [COMMANDE] [PROJET] Où COMMANDE peut être : server [-p|--port PORT] [-b|--bind IP] | | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | -h|--help) cat <<EOF Usage : $0 [COMMANDE] [PROJET] Où COMMANDE peut être : server [-p|--port PORT] [-b|--bind IP] Démarre un serveur web Paheko sur le port spécifié (8081 par défaut) et l'IP spécifiée (127.0.0.1 par défaut) ui [-p|--port PORT] [-b|--bind IP] Idem que 'server' mais démarre ensuite le navigateur web par défaut et connecte automatiquement avec le premier administrateur de l'association. |
︙ | ︙ | |||
92 93 94 95 96 97 98 99 100 101 102 103 104 105 | PROJECT="$2" [ "$PROJECT" = "" ] && PROJECT="1" export PAHEKO_STANDALONE="$PROJECT" [ -f $PID_FILE ] && kill `cat $PID_FILE` > /dev/null 2>&1 && rm -f $PID_FILE [ $VERBOSE = 1 ] && { php -S ${ADDRESS}:${PORT} -t ${ROOT} -d variables_order=EGPCS ${ROUTER} & } || { php -S ${ADDRESS}:${PORT} -t ${ROOT} -d variables_order=EGPCS ${ROUTER} > /dev/null 2>&1 & } | > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | PROJECT="$2" [ "$PROJECT" = "" ] && PROJECT="1" export PAHEKO_STANDALONE="$PROJECT" [ -f $PID_FILE ] && kill `cat $PID_FILE` > /dev/null 2>&1 && rm -f $PID_FILE PHP_CLI_SERVER_WORKER=2 [ $VERBOSE = 1 ] && { php -S ${ADDRESS}:${PORT} -t ${ROOT} -d variables_order=EGPCS ${ROUTER} & } || { php -S ${ADDRESS}:${PORT} -t ${ROOT} -d variables_order=EGPCS ${ROUTER} > /dev/null 2>&1 & } |
︙ | ︙ |
Modified build/windows/Makefile from [151de88204] to [7b464ebe75].
1 | .PHONY := php installer clean publish | | > > | 1 2 3 4 5 6 7 8 9 10 11 | .PHONY := php installer clean publish PHP_ARCHIVE := https://windows.php.net/downloads/releases/php-8.2.10-nts-Win32-vs16-x64.zip all: installer php.zip: wget ${PHP_ARCHIVE} -O php.zip php: php.zip mkdir -p install_dir/php unzip -o php.zip -d install_dir/php > /dev/null |
︙ | ︙ | |||
53 54 55 56 57 58 59 60 | php_xsl.dll \ php_zend_test.dll du -hs install_dir/php installer: clean php $(eval VERSION=$(shell cat ../../src/VERSION)) mkdir -p install_dir | > > | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | php_xsl.dll \ php_zend_test.dll du -hs install_dir/php installer: clean php $(eval VERSION=$(shell cat ../../src/VERSION)) # NSIS only accepts numbers as version $(eval NSIS_VERSION=$(shell sed -E 's/-(alpha|beta|rc)[0-9]+//' ../../src/VERSION)) mkdir -p install_dir cp ../paheko-${VERSION}.tar.gz install_dir/ cd install_dir && tar xzf paheko-${VERSION}.tar.gz && mv paheko-${VERSION} paheko cp config.local.php install_dir/paheko/ cp php.ini install_dir/php cp launch.bat install_dir cp paheko.ico install_dir rm -f install_dir/paheko-${VERSION}.tar.gz makensis -V3 -DNVERSION=${NSIS_VERSION} -DVERSION=${VERSION} paheko.nsis clean: rm -rf install_dir publish: $(eval VERSION=$(shell cat ../../src/VERSION)) fossil uv ls | grep '^paheko-.*\.exe' | xargs fossil uv rm fossil uv add paheko-${VERSION}.exe fossil uv sync |
Modified build/windows/config.local.php from [4f250a82d1] to [bce1077cb9].
1 2 | <?php | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php namespace Paheko; if (!empty(getenv('LOCALAPPDATA'))) { // Store data in user AppData directory define('Paheko\DATA_ROOT', trim(getenv('LOCALAPPDATA'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'Paheko'); } // Store secret key in user directory if (!defined('Paheko\SECRET_KEY')) { if (file_exists(DATA_ROOT . '/key')) { define('Paheko\SECRET_KEY', trim(file_get_contents(DATA_ROOT . '/key'))); } else { define('Paheko\SECRET_KEY', base64_encode(random_bytes(16))); file_put_contents(DATA_ROOT . '/key', SECRET_KEY); } } // Always log in as admin user const LOCAL_LOGIN = -1; // Disable PDF export const PDF_COMMAND = null; // Disable e-mails as Windows is not able to send e-mails const DISABLE_EMAIL = true; |
Modified build/windows/paheko.nsis from [8c0f2b68e1] to [8f73d399b0].
︙ | ︙ | |||
18 19 20 21 22 23 24 | !define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" !define REG_START_MENU "Start Menu Folder" var SM_Folder ###################################################################### | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | !define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" !define REG_START_MENU "Start Menu Folder" var SM_Folder ###################################################################### VIProductVersion "${NVERSION}.0" VIAddVersionKey "ProductName" "${APP_NAME}" VIAddVersionKey "CompanyName" "${COMP_NAME}" VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" VIAddVersionKey "FileDescription" "${DESCRIPTION}" VIAddVersionKey "FileVersion" "${VERSION}" ###################################################################### |
︙ | ︙ |
Modified build/windows/php.ini from [799dda8484] to [43ac89d677].
︙ | ︙ | |||
23 24 25 26 27 28 29 | ignore_repeated_errors = Off ignore_repeated_source = Off report_memleaks = On variables_order = "GPCS" request_order = "GP" register_argc_argv = Off auto_globals_jit = On | | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | ignore_repeated_errors = Off ignore_repeated_source = Off report_memleaks = On variables_order = "GPCS" request_order = "GP" register_argc_argv = Off auto_globals_jit = On post_max_size = 256M auto_prepend_file = auto_append_file = default_mimetype = "text/html" default_charset = "UTF-8" doc_root = user_dir = extension_dir = "ext" enable_dl = Off file_uploads = On upload_max_filesize = 256M max_file_uploads = 20 allow_url_fopen = On allow_url_include = Off default_socket_timeout = 60 extension=fileinfo extension=gd |
︙ | ︙ |
Modified doc/admin/brindille.md from [c51352c8ee] to [a8ac5faee9].
1 2 3 4 5 6 7 8 9 10 11 | Title: Documentation du langage Brindille dans Paheko {{{.nav * **[Documentation Brindille](brindille.html)** * [Fonctions](brindille_functions.html) * [Sections](brindille_sections.html) * [Filtres](brindille_modifiers.html) }}} <<toc aside>> | > > > > > | > > > > > > > > > | > | | < | > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | Title: Documentation du langage Brindille dans Paheko {{{.nav * [Modules](modules.html) * **[Documentation Brindille](brindille.html)** * [Fonctions](brindille_functions.html) * [Sections](brindille_sections.html) * [Filtres](brindille_modifiers.html) }}} <<toc aside>> # Introduction La syntaxe utilisée dans les squelettes du site web et des modules s'appelle **Brindille**. Si vous avez déjà fait de la programmation, elle ressemble à un mélange de Mustache, Smarty, Twig et PHP. Son but est de permettre une grande flexibilité, sans avoir à utiliser un "vrai" langage de programmation, mais en s'en rapprochant suffisamment quand même. ## Fichiers Un fichier texte contenant du code Brindille est appelé un **squelette**. Seuls les fichiers ayant une des extensions `.tpl`, `.html`, `.htm`, `.skel` ou `.xml` seront traités par Brindille. De même, les fichiers qui n'ont pas d'extension seront également traités par Brindille. Les autres types de fichiers seront renvoyés sans traitement, comme des fichiers "bruts". En d'autres termes, il n'est pas possible de mettre du code *Brindille* dans des fichiers qui ne sont pas des fichiers textes. # Syntaxe de base ## Affichage de variable Une variable est affichée à l'aide de la syntaxe : `{{$date}}` affichera la valeur brute de la date par exemple : `2020-01-31 16:32:00`. La variable peut être modifiée à l'aide de filtres de modification, qui sont ajoutés avec le symbole de la barre verticale (pipe `|`) : `{{$date|date_long}}` affichera une date au format long : `jeudi 7 mars 2021`. Ces filtres peuvent accepter des paramètres, séparés par deux points `:`. Exemple : `{{$date|date:"%d/%m/%Y"}}` affichera `31/01/2020`. Par défaut la variable sera recherchée dans le contexte actuel de la section, si elle n'est pas trouvée elle sera recherchée dans le contexte parent (section parente), etc. jusqu'à trouver la variable. Il est possible de faire référence à une variable d'un contexte particulier avec la notation à points : `{{$article.date}}`. La même syntaxe est utilisée pour accéder aux membres d'un tableau : `{{$labels.new_page}}`. Il existe deux variables de contexte spécifiques : `$_POST` et `$_GET` qui permettent d'accéder aux données envoyées dans un formulaire et dans les paramètres de la page. Par défaut le filtre `escape` est appliqué à toutes les variables pour protéger les variables contre les injections de code HTML. Ce filtre est appliqué en dernier, après les autres filtres. Il est possible de contourner cet automatisme en rajoutant le filtre `escape` ou `raw` explicitement. `raw` désactive tout échappement, alors que `escape` est utilisé pour changer l'ordre d'échappement. Exemple : ``` {{:assign text = "Coucou\nça va ?" }} {{$text|escape|nl2br}} ``` Donnera bien `Coucou<br />ça va ?`. Si on n'avait pas indiqué le filtre `escape` le résultat serait `Coucou<br />ça va ?`. ### Échappement des caractères spéciaux dans les chaînes de caractère Pour inclure un caractère spécial (retour de ligne, guillemets ou apostrophe) dans une chaîne de caractère il suffit d'utiliser un antislash : ``` {{:assign text="Retour \n à la ligne"}} {{:assign text="Utiliser des \"apostrophes\"}} ``` ## Ordre de recherche des variables Par défaut les variables sont recherchées dans l'ordre inverse, c'est à dire que sont d'abord recherchées les variables avec le nom demandé dans la section courante. Si la variable n'existe pas dans la section courante, alors elle est recherchée dans la section parente, et ainsi de suite jusqu'à ce que la variable soit trouvée, où qu'il n'y ait plus de section parente. Prenons cet exemple : ``` {{#articles uri="Actualite"}} <h1>{{$title}}</h1> {{#images parent=$path limit=1}} <img src="{{$thumb_url}}" alt="{{$title}}" /> {{/images}} {{/articles}} ``` Dans la section `articles`, `$title` est une variable de l'article, donc la variable est celle de l'article. Dans la section `images`, les images n'ayant pas de titre, la variable sera celle de l'article de la section parente, alors que `$thumb_url` sera lié à l'image. ## Conflit de noms de variables Imaginons que nous voulions mettre un lien vers l'article sur l'image de l'exemple précédent : ``` {{#articles uri="Actualite"}} <h1>{{$title}}</h1> {{#images parent=$path limit=1}} {{/images}} {{/articles}} ``` Problème, ici `$url` fera référence à l'URL de l'image elle-même, et non pas l'URL de l'article. La solution est d'ajouter un point au début du nom de variable : `{{$.url}}`. Un point au début d'un nom de variable signifie que la variable est recherchée à partir de la section précédente. Il est possible d'utiliser plusieurs points, chaque point correspond à un niveau à remonter. Ainsi `$.url` cherchera la variable dans la section parente (et ses sections parentes si elle n'existe pas, etc.). De même, `$..url` cherchera dans la section parente de la section parente. ## Création manuelle de variable ### Variable simple La création d'une variable se fait via l'appel de la fonction `{{:assign}}`. Exemple : ``` {{:assign source='wiki'}} {{* est identique à : *}} {{:assign var='source' value='wiki'}} ``` Un deuxième appel à `{{:assign}}` avec le même nom de variable écrase la valeur précédente ``` {{:assign var='source' value='wiki'}} {{:assign var='source' value='documentation'}} {{$source}} {{* => Affiche documentation *}} ``` ### Nom de variable dynamique Il est possible de créer une variable dont une partie du nom est dynamique. ``` {{:assign type='user'}} {{:assign var='allowed_%s'|args:$type value='jeanne'}} {{:assign type='side'}} {{:assign var='allowed_%s'|args:$type value='admin'}} {{$allowed_user}} => jeanne {{$allowed_side}} => admin ``` [Documentation complète de la fonction {{:assign}}](brindille_functions.html#assign). ### Tableaux *(array)* Pour créer des tableaux, il suffit d'utiliser des points `.` dans le nom de la variable (ex : `colors.yellow`). Il n'y a pas besoin d'initialiser le tableau avant de le remplir. ``` {{:assign var='colors.admin' value='blue'}} {{:assign var='colors.website' value='grey'}} {{:assign var='colors.debug' value='yellow'}} ``` On accède ensuite à la valeur d'un élément du tableau avec la même syntaxe : `{{$colors.website}}` Méthode rapide de création du même tableau : ``` {{:assign var='colors' admin='blue' website='grey' debug='yellow'}} ``` Pour ajouter un élément à la suite du tableau sans spécifier de clef *(push)*, il suffit de terminer le nom de la variable par un point `.` sans suffixe. Exemple : ``` {{* Ajouter les valeurs 17, 43 et 214 dans $processed_ids *}} {{:assign var='processed_ids.' value=17}} {{:assign var='processed_ids.' value=43}} {{:assign var='processed_ids.' value=214}} ``` #### Clef dynamique de tableau Il est possible d'accéder dynamiquement à un des éléments d'un tableau de la manière suivante : ``` {{:assign location='admin'}} {{:assign var='location_color' from='colors.%s'|args:$location}} {{$location_color}} => blue ``` Exemple plus complexe : ``` {{:assign var='type_whitelist.text' value=1}} {{:assign var='type_whitelist.html' value=1}} {{#foreach from=$documents item='document'}} {{:assign var='allowed' value='type_whitelist.%s'|args:$document->type}} {{if $allowed !== null}} {{:include file='document/'|cat:$type:'.tpl' keep='document'}} {{/if}} {{/foreach}} ``` Il est également possible de créer un membre dynamique d'un tableau en conjuguant les syntaxes précédentes. Exemple : ``` {{:assign var='type_whitelist.%s'|args:$type value=1}} ``` ## Conditions Il est possible d'utiliser des conditions de type **"si"** (`if`), **"sinon si"** (`elseif`) et **"sinon"** (`else`). Celles-ci sont terminées par un block **"fin si"** (`/if`). ``` {{if $date|date:"%Y" > 2020}} La date est en 2020 {{elseif $article.status == 'draft'}} La page est un brouillon {{else}} |
︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 | | `||` | Vrai si une des conditions à gauche ou à droite est vraie | Exemples : * `false && true` : sera évalué comme faux * `false || true` : sera évalué comme vrai ## Fonctions | > > > > > > > > > > > > > > > > | > > | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | | `||` | Vrai si une des conditions à gauche ou à droite est vraie | Exemples : * `false && true` : sera évalué comme faux * `false || true` : sera évalué comme vrai ### Tester si une variable existe Brindille ne fait pas de différences entre une variable qui n'existe pas, et une variable définie à `null`. On peut donc tester l'existence d'une variable en la comparant à `null` comme ceci : ``` {{if $session !== null}} Session en cours pour l'utilisateur/trice {{$session.user.name}}. {{else}} Session inexistante. {{/if}} ``` ## Fonctions ### Fonctions natives Une fonction va répondre à certains paramètres et renvoyer un résultat ou réaliser une action. **Un bloc de fonction commence par le signe deux points `:`.** ``` {{:http code=404}} ``` Contrairement aux autres types de blocs, et comme pour les variables, il n'y a pas de bloc fermant (avec un slash `/`). |
︙ | ︙ | |||
161 162 163 164 165 166 167 | Un exemple de sous-section ``` {{#categories uri=$_GET.uri}} <h1>{{$title}}</h1> {{#articles parent=$path order="published DESC" limit="10"}} | | | > | > | | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | Un exemple de sous-section ``` {{#categories uri=$_GET.uri}} <h1>{{$title}}</h1> {{#articles parent=$path order="published DESC" limit="10"}} <h2></h2> <p>{{$content|truncate:600:"..."}}</p> {{else}} <p>Aucun article trouvé.</p> {{/articles}} {{/categories}} ``` Voir la référence des sections pour voir quelles sont les sections possibles et quel est leur comportement. ## Bloc litéral Pour qu'une partie du code ne soit pas interprété, pour éviter les conflits avec certaines syntaxes, il est possible d'utiliser un bloc `literal` : ``` {{literal}} <script> // Ceci ne sera pas interprété function test (a) {{ }} </script> {{/literal}} ``` ## Commentaires Les commentaires sont figurés dans des blocs qui commencent et se terminent par une étoile (`*`) : ``` {{* Ceci est un commentaire Il sera supprimé du résultat final Il peut contenir du code qui ne sera pas interprété : {{if $test}} OK {{/if}} *}} ``` # Liste des variables définies par défaut Ces variables sont définies tout le temps : | Nom de la variable | Valeur | | :- | :- | | `$_GET` | Alias de la super-globale _GET de PHP. | | `$_POST` | Alias de la super-globale _POST de PHP. | | `$root_url` | Adresse racine du site web Paheko. | | `$request_url` | Adresse de la page courante. | | `$admin_url` | Adresse de la racine de l'administration Paheko. | | `$visitor_lang` | Langue préférée du visiteur, sur 2 lettres (exemple : `fr`, `en`, etc.). | | `$logged_user` | Informations sur le membre actuellement connecté dans l'administration (vide si non connecté). | | `$dialog` | Vaut `TRUE` si la page est dans un dialogue (iframe sous forme de pop-in dans l'administration). | | `$now` | Contient la date et heure courante. | | `$legal_line` | Contient la ligne de bas de page des mentions légales (sous forme de code HTML) qui doit être présente en bas des pages publiques. | | `$config.org_name` | Nom de l'association | | `$config.org_email` | Adresse e-mail de l'association | | `$config.org_phone` | Numéro de téléphone de l'association | | `$config.org_address` | Adresse postale de l'association | | `$config.org_web` | Adresse du site web de l'association | | `$config.files.logo` | Adresse du logo de l'association, si définit dans la personnalisation | | `$config.files.favicon` | Adresse de l'icône de favoris de l'association, si défini dans la personnalisation | | `$config.files.signature` | Adresse de l'image de signature, si défini dans la personnalisation | À celles-ci s'ajoutent [les variables spéciales des modules](modules.html#variables_speciales) lorsque le script est chargé dans un module. # Erreurs Si une erreur survient dans un squelette, que ça soit au niveau d'une erreur de syntaxe, ou une erreur dans une fonction, filtre ou section, alors elle sera affichée selon les règles suivantes : * si le membre connecté est administrateur, une erreur est affichée avec le code du squelette ; * sinon l'erreur est affichée sans le code. # Avertissement sur la sécurité des requêtes SQL Attention, en utilisant la section `{{#select ...}}`, ou une des sections SQL (voir plus bas), avec des paramètres qui ne seraient pas protégés, il est possible qu'une personne mal intentionnée ait accès à des parties de la base de données à laquelle vous ne désirez pas donner accès. Pour protéger contre cela il est essentiel d'utiliser les paramètres nommés. Exemple de requête dangereuse : ``` {{#sql select="*" tables="users" where="id = %s"|args:$_GET.id}} ... {{/sql}} ``` On se dit que la requête finale sera donc : `SELECT * FROM users WHERE id = 42;` si le numéro 42 est passé dans le paramètre `id` de la page. Imaginons qu'une personne mal-intentionnée indique dans le paramètre `id` de la page la chaîne de caractère suivante : `0 OR 1`. Dans ce cas la requête exécutée sera `SELECT * FROM users WHERE id = 0 OR 1;`. Cela aura pour effet de lister tous les membres, au lieu d'un seul. Pour protéger contre cela il convient d'utiliser un paramètre nommé : ``` {{#sql select="*" tables="users" where="id = :id" :id=$_GET.id}} ``` Dans ce cas la requête malveillante générée sera `SELECT * FROM users WHERE id = '0 OR 1';`. Ce qui aura pour effet de ne lister aucun membre. ## Mesures prises pour la sécurité des données Dans Brindille, il n'est pas possible de modifier ou supprimer des éléments dans la base de données avec les requêtes SQL directement. Seules les requêtes SQL en lecture (`SELECT`) sont permises. Cependant certaines fonctions permettent de modifier ou créer des éléments précis (écritures par exemple), ce qui peut avoir un effet de remplir ou modifier des données par une personne mal-intentionnée, donc attention à leur utilisation. Les autres mesures prises sont : * impossibilité d'accéder à certaines données sensibles (mot de passe, logs de connexion, etc.) * incitation forte à utiliser les paramètres nommés dans la documentation * protection automatique des variables dans la section `{{#select}}` * fourniture de fonctions pour protéger les chaînes de caractères contre l'injection SQL |
Modified doc/admin/brindille_functions.md from [5a9c2c0ee5] to [4ffcccd4be].
1 2 3 4 5 6 7 8 9 10 11 | Title: Référence des fonctions Brindille {{{.nav * [Documentation Brindille](brindille.html) * **[Fonctions](brindille_functions.html)** * [Sections](brindille_sections.html) * [Filtres](brindille_modifiers.html) }}} <<toc aside>> | > > > | | > > > > > > > > > > > < < | > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > | | | | | | | > | > | | > > | | | | > > > < | > | > > > > > > | > > > > | > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > | < < | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | Title: Référence des fonctions Brindille {{{.nav * [Modules](modules.html) * [Documentation Brindille](brindille.html) * **[Fonctions](brindille_functions.html)** * [Sections](brindille_sections.html) * [Filtres](brindille_modifiers.html) }}} <<toc aside>> # Fonctions généralistes ## assign Permet d'assigner une valeur dans une variable. | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `.` | optionnel | Assigner toutes les variables du contexte (section) actuel | | `var` | optionnel | Nom de la variable à créer ou modifier | | `value` | optionnel | Valeur de la variable | | `from` | optionnel | Recopier la valeur depuis la variable ayant le nom fourni dans ce paramètre. | Tous les autres paramètres sont considérés comme des variables à assigner. Exemple : ``` {{:assign blabla="Coucou"}} {{$blabla}} ``` Il est possible d'assigner toutes les variables d'une section dans une variable en utilisant le paramètre point `.` (`.="nom_de_variable"`). Cela permet de capturer le contenu d'une section pour le réutiliser à un autre endroit. ``` {{#pages uri="Informations" limit=1}} {{:assign .="infos"}} {{/pages}} {{$infos.title}} ``` Il est aussi possible de remonter dans les sections parentes en utilisant plusieurs points. Ainsi deux points remonteront à la section parente, trois points à la section parente de la section parente, etc. ``` {{#foreach from=$infos item="info"}} {{#foreach from=$info item="sous_info"}} {{if $sous_info.titre == 'Coucou'}} {{:assign ..="info_importante"}} {{/if}} {{/foreach}} {{/foreach}} {{$info_importante.titre}} ``` En utilisant le paramètre spécial `var`, tous les autres paramètres passés sont ajoutés à la variable donnée en valeur : ``` {{:assign var="tableau" label="Coucou" name="Pif le chien"}} {{$tableau.label}} {{$tableau.name}} ``` De la même manière on peut écraser une variable avec le paramètre spécial `value`: ``` {{:assign var="tableau" value=$infos}} ``` Il est également possible de créer des tableaux avec la syntaxe `.` dans le nom de la variable : ``` {{:assign var="liste.comptes.530" label="Caisse"}} {{:assign var="liste.comptes.512" label="Banque"}} {{#foreach from=$liste.comptes}} {{$key}} = {{$value.label}} {{/foreach}} ``` Il est possible de rajouter des éléments à un tableau simplement en utilisant un point seul : ``` {{:assign var="liste.comptes." label="530 - Caisse"}} {{:assign var="liste.comptes." label="512 - Banque"}} ``` Enfin, il est possible de faire référence à une variable de manière dynamique en utilisant le paramètre spécial `from` : ``` {{:assign var="tableau" a="Coucou" b="Test !"}} {{:assign var="titre" from="tableau.%s"|args:"b"}} {{$titre}} -> Affichera "Test !", soit la valeur de {{$tableau.b}} ``` ## break Interrompt une section. ## continue Passe à l'itération suivante d'une section. Le code situé entre cette instruction et la fin de la section ne sera pas exécuté. ``` {{#foreach from=$list item="event"}} {{if $event.date == '2023-01-01'}} {{:continue}} {{/if}} {{$event.title}} {{/foreach}} ``` Il est possible de passer à l'itération suivante d'une section parente en utilisant un chiffre en paramètre : ``` {{#foreach from=$list item="event"}} {{$event.title}} {{#foreach from=$event.people item="person"}} {{if $person.name == 'bohwaz'}} {{:continue 2}} {{/if}} - {{$person.name}} {{/foreach}} {{/foreach}} ``` ## debug Cette fonction permet d'afficher le contenu d'une ou plusieurs variables : ``` {{:debug test=$title}} ``` Affichera : ``` array(1) { ["test"] => string(6) "coucou" } ``` Si aucun paramètre n'est spécifié, alors toutes les variables définies sont renvoyées. Utile pour découvrir quelles sont les variables accessibles dans une section par exemple. ## error Affiche un message d'erreur et arrête le traitement à cet endroit. | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `message` | **obligatoire** | Message d'erreur à afficher | Exemple : ``` {{if $_POST.nombre != 42}} {{:error message="Le nombre indiqué n'est pas 42"}} {{/if}} ``` ## form_errors Affiche les erreurs du formulaire courant (au format HTML). ## http Permet de modifier les entêtes HTTP renvoyés par la page. Cette fonction doit être appelée au tout début du squelette, avant tout autre code ou ligne vide. | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `code` | *optionnel* | Modifie le code HTTP renvoyé. [Liste des codes HTTP](https://fr.wikipedia.org/wiki/Liste_des_codes_HTTP) | | `redirect` | *optionnel* | Rediriger vers l'adresse URL indiquée en valeur. | | `type` | *optionnel* | Modifie le type MIME renvoyé | | `download` | *optionnel* | Force la page à être téléchargée sous le nom indiqué. | | `inline` | *optionnel* | Force la page à être affichée, et peut ensuite être téléchargée sous le nom indiqué (utile pour la généraion de PDF : permet d'afficher le PDF dans le navigateur avant de le télécharger). | Note : si le type `application/pdf` est indiqué (ou juste `pdf`), la page sera convertie en PDF à la volée. Il est possible de forcer le téléchargement du fichier en utilisant le paramètre `download`. Exemples : ``` {{:http code=404}} {{:http redirect="/Nos-Activites/"}} {{:http redirect="https://mon-site-web.tld/"}} {{:http type="application/svg+xml"}} {{:http type="pdf" download="liste_membres_ca.pdf"}} ``` ## include Permet d'inclure un autre squelette. Paramètres : | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `file` | **obligatoire** | Nom du squelette à inclure | | `keep` | *optionnel* | Liste de noms de variables à conserver | | `capture` | *optionnel* | Si renseigné, au lieu d'afficher le squelette, son contenu sera enregistré dans la variable de ce nom. | | … | *optionnel* | Tout autre paramètre sera utilisé comme variable qui n'existea qu'à l'intérieur du squelette inclus. | ``` {{* Affiche le contenu du squelette "navigation.html" dans le même répertoire que le squelette d'origine *}} {{:include file="./navigation.html"}} ``` Par défaut, les variables du squelette parent sont transmis au squelette inclus, mais les variables définies dans le squelette inclus ne sont pas transmises au squelette parent. Exemple : ``` {{* Squelette page.html *}} {{:assign title="Super titre !"}} {{:include file="./_head.html"}} {{$nav}} ``` ``` {{* Squelette _head.html *}} <h1>{{$title}}</h1> {{:assign nav="Accueil > %s"|args:$title}} ``` Dans ce cas, la dernière ligne du premier squelette (`{{$nav}}`) n'affichera rien, car la variable définie dans le second squelette n'en sortira pas. Pour indiquer qu'une variable doit être transmise au squelette parent, il faut utiliser le paramètre `keep`: ``` {{:include file="./_head.html" keep="nav"}} ``` On peut spécifier plusieurs noms de variables, séparés par des virgules, et utiliser la notation à points : ``` {{:include file="./_head.html" keep="nav,article.title,name"}} {{$nav}} {{$article.title}} {{$name}} ``` On peut aussi capturer le résultat d'un squelette dans une variable : ``` {{:include file="./_test.html" capture="test"}} {{:assign var="test" value=$test|replace:'TITRE':'Ceci est un titre'}} {{$test}} ``` Il est possible d'assigner de nouvelles variables au contexte du include en les déclarant comme paramètres tout comme on le ferait avec `{{:assign}}` : ``` {{:include file="./_head.html" title='%s documentation'|args:$doc.label visitor=$user}} ``` ## captcha Permet de générer une question qui doit être répondue correctement par l'utilisateur pour valider une action. Utile pour empêcher les robots spammeurs d'effectuer une action. L'utilisation simplifiée utilise un de ces deux paramètres : | Paramètre | Fonction | | :- | :- | | `html` | Si `true`, crée un élément de formulaire HTML et le texte demandant à l'utilisateur de répondre à la question | | `verify` | Si `true`, vérifie que l'utilisateur a correctement répondu à la question | L'utilisation avancée utilise d'abord ces deux paramètres : | Paramètre | Fonction | | :- | :- | | `assign_hash` | Nom de la variable où assigner le hash (à mettre dans un `<input type="hidden" />`) | | `assign_number` | Nom de la variable où assigner le nombre de la question (à afficher à l'utilisateur) | Puis on vérifie : | Paramètre | Fonction | | :- | :- | | `verify_hash` | Valeur qui servira comme hash de vérification (valeur du `<input type="hidden" />`) | | `verify_number` | Valeur qui représente la réponse de l'utilisateur | | `assign_error` | Si spécifié, le message d'erreur sera placé dans cette variable, sinon il sera affiché directement. | Exemple : ``` {{if $_POST.send}} {{:captcha verify_hash=$_POST.h verify_number=$_POST.n assign_error="error"}} {{if $error}} <p class="alert">Mauvaise réponse</p> {{else}} ... {{/if}} {{/if}} <form method="post" action=""> {{:captcha assign_hash="hash" assign_number="number"}} <p>Merci de recopier le nombre suivant en chiffres : <tt>{{$number}}</tt></p> <p> <input type="text" name="n" placeholder="1234" /> <input type="hidden" name="h" value="{{$hash}}" /> <input type="submit" name="send" /> </p> </form> ``` ## mail Permet d'envoyer un e-mail à une ou des adresses indiquées (sous forme de tableau). Restrictions : * le message est toujours envoyé en format texte ; * l'expéditeur est toujours l'adresse de l'association ; * l'envoi est limité à une seule adresse e-mail externe (adresse qui n'est pas celle d'un membre) dans une page ; * l'envoi est limité à maximum 10 adresses e-mails internes (adresses de membres) dans une page ; * un message envoyé à une adresse e-mail externe ne peut pas contenir une adresse web (`https://...`) autre que celle de l'association. Note : il est également conseillé d'utiliser la fonction `captcha` pour empêcher l'envoi de spam. | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `to` | **obligatoire** | Adresse email destinataire (seule l'adresse e-mail elle-même est acceptée, pas de nom) | | `subject` | **obligatoire** | Sujet du message | | `body` | **obligatoire** | Corps du message | | `block_urls` | *optionnel* | (`true` ou `false`) Permet de bloquer l'envoi si le message contient une adresse `https://…` | | `attach_file` | *optionnel* | Chemin vers un ou plusieurs documents à joindre au message (situé dans les documents) | | `attach_from` | *optionnel* | Chemin vers un ou plusieurs squelettes à joindre au message (par exemple pour joindre un document généré) | Pour le destinataire, il est possible de spécifier un tableau : ``` {{:assign var="recipients[]" value="membre1@framasoft.net"}} {{:assign var="recipients[]" value="membre2@chatons.org"}} {{:mail to=$recipients subject="Coucou" body="Contenu du message\nNouvelle ligne"}} ``` Exemple de formulaire de contact : ``` {{if !$_POST.email|check_email}} <p class="alert">L'adresse e-mail indiquée est invalide.</p> {{elseif $_POST.message|trim == ''}} <p class="alert">Le message est vide</p> {{elseif $_POST.send}} {{:captcha verify=true}} {{:mail to=$config.org_email subject="Formulaire de contact" body="%s a écrit :\n\n%s"|args:$_POST.email:$_POST.message block_urls=true}} <p class="ok">Votre message nous a bien été transmis !</p> {{/if}} <form method="post" action=""> <dl> <dt><label>Votre e-mail : <input type="email" required name="email" /></label></dt> <dt><label>Votre message : <textarea required name="message" cols="50" rows="5"></textarea></label></dt> <dt>{{:captcha html=true}}</dt> </dl> <p><input type="submit" name="send" value="Envoyer !" /></p> </form> ``` ## redirect Redirige vers une nouvelle page. Avec le paramètre `force`, si la page actuelle est ouverte dans une fenêtre modale (grâce à la cible `_dialog`), alors la fenêtre modale est fermée, et la redirection se passe dans la page parente. Avec le paramètre `to`, si la page actuelle est ouverte dans une fenêtre modal (grâce à la cible `_dialog`), alors la fenêtre modale est fermée, et la page parente est rechargée. Si la page n'est pas ouvertre dans dans une fenêtre modale, la redirection est effectuée. Seules les adresses internes sont acceptées, il n'est pas possible de rediriger vers une adresse extérieure. | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `force` | optionnel | Adresse de redirection forcée | | `to` | optionnel | Adresse de redirection si pas dans une fenêtre modale | Si `to=null` est utilisé, alors la fenêtre modale sera fermée. Ou, si la page n'est pas dans une fenêtre modale, la page courante sera rechargée. # Fonctions relatives aux Modules ## save Enregistre des données, sous la forme d'un document, dans la base de données, pour le module courant. Note : un appel à cette fonction depuis le code du site web provoquera une erreur, elle ne peut être appelée que depuis un module. | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `key` | optionnel | Clé unique du document | | `id` | optionnel | Numéro unique du document | | `validate_schema` | optionnel | Fichier de schéma JSON à utiliser pour valider les données avant enregistrement | | `validate_only` | optionnel | Liste des paramètres à valider (par exemple pour ne faire qu'une mise à jour partielle), séparés par des virgules. | | `assign_new_id` | optionnel | Si renseigné, le nouveau numéro unique du document sera indiqué dans cette variable. | | … | optionnel | Autres paramètres : traités comme des valeurs à enregistrer dans le document | Si ni `key` ni `id` ne sont indiqués, un nouveau document sera créé avec un nouveau numéro (ID) unique. Si le document indiqué existe déjà, il sera mis à jour. Les valeurs nulles (`NULL`) seront effacées. ``` {{:save key="facture_43" nom="Atelier mobile" montant=250}} ``` Enregistrera dans la base de données le document suivant sous la clé `facture_43` : ``` {"nom": "Atelier mobile", "montant": 250} ``` Exemple de mise à jour : ``` {{:save key="facture_43" montant=300}} ``` Exemple de récupération du nouvel ID : ``` {{:save titre="Coucou !" assign_new_id="id"}} Le document n°{{$id}} a bien été enregistré. ``` ### Validation avec un schéma JSON ``` {{:save titre="Coucou" texte="Très long" validate_schema="./document.schema.json"}} ``` Pour ne valider qu'une partie du schéma, par exemple si on veut faire une mise à jour du document : ``` {{:save key="test" titre="Coucou" validate_schema="./document.schema.json" validate_only="titre"}} ``` ## delete Supprime un document lié au module courant. Note : un appel à cette fonction depuis le code du site web provoquera une erreur, elle ne peut être appelée que depuis un module. | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `key` | optionnel | Clé unique du document | | `id` | optionnel | Numéro unique du document | Il est possible de spécifier d'autres paramètres, ou une clause `where` et des paramètres dont le nom commence par deux points. * Supprimer le document avec la clé `facture_43` : `{{:delete key="facture_43"}}` * Supprimer le document avec la clé `ABCD` et dont la propriété `type` du document correspond à la valeur `facture` : `{{:delete key="ABCD" type="facture"}}` * Supprimer tous les documents : `{{:delete}}` * Supprimer tous les documents ayant le type `facture` : `{{:delete type="facture"}}` * Supprimer tous les documents de type `devis` ayant une date dans le passé : `{{:delete :type="devis" where="$$.type = :type AND $$.date < datetime()"}}` ## admin_header Affiche l'entête de l'administration de l'association. | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `title` | *optionnel* | Titre de la page | | `layout` | *optionnel* | Aspect de la page. Peut être `public` pour une page publique simple (sans le menu), ou `raw` pour une page vierge (sans aucun menu ni autre élément). Défaut : vide (affichage du menu) | | `current` | *optionnel* | Indique quel élément dans le menu de gauche doit être marqué comme sélectionné | | `custom_css` | *optionnel* | Fichier CSS supplémentaire à appeler dans le `<head>` | ``` {{:admin_header title="Gestion des dons" current="acc"}} ``` Liste des choix possibles pour `current` : * `home` : menu Accueil * `users` : menu Membres * `users/new` : sous-menu "Ajouter" de Membres * `users/services` : sous-menu "Activités et cotisations" de Membres * `users/mailing` : sous-menu "Message collectif" de Membres * `acc` : menu Comptabilité * `acc/new` : sous-menu "Saisie" de Comptabilité * `acc/accounts` : sous-menu "Comptes" * `acc/simple` : sous-menu "Suivi des écritures" * `acc/years` : sous-menu "Exercices et rapports" * `docs` : menu Documents * `web` : menu Site web * `config` : menu Configuration * `me` : menu "Mes infos personnelles" * `me/services` : sous-menu "Mes activités et cotisations" Exemple d'utilisation de `custom_css` depuis un module : ``` {{:admin_header title="Mon module" custom_css="./style.css"}} ``` ## admin_footer Affiche le pied de page de l'administration de l'association. ``` {{:admin_footer}} ``` ## delete_form Affiche un formulaire demandant la confirmation de suppression d'un élément. | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `legend` | **obligatoire** | Libellé de l'élément `<legend>` du formulaire | | `warning` | **obligatoire** | Libellé de la question de suppression (en gros en rouge) | | `alert` | *optionnel* | Message d'alerte supplémentaire (bloc jaune) | | `info` | *optionnel* | Informations liées à la suppression (expliquant ce qui va être impacté par la suppression) | | `confirm` | *optionnel* | Libellé de la case à cocher pour la suppression, si ce paramètre est absent ou `NULL`, la case à cocher ne sera pas affichée. | Le formulaire envoie un `POST` avec le bouton ayant le nom `delete`. Si le paramètre `confirm` est renseigné, alors la case à cochée aura le nom `confirm_delete`. Exemple : ``` {{#load id=$_GET.id assign="invoice"}} {{else}} {{:error message="Facture introuvable"}} {{/load}} {{#form on="delete"}} {{if !$_POST.confirm_delete}} {{:error message="Merci de cocher la case"}} {{/if}} {{:delete id=$invoice.id}} {{/form}} {{:form_errors}} {{:delete_form legend="Suppression d'une facture" warning="Supprimer la facture n°%d ?"|args:$invoice.id info="Le devis lié sera également supprimé" alert="La facture sera définitivement perdue !" confirm="Cocher cette case pour confirmer la suppression de la facture" }} ``` ## input Crée un champ de formulaire HTML. Cette fonction est une extension à la balise `<input>` en HTML, mais permet plus de choses. | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `name` | **obligatoire** | Nom du champ | | `type` | **obligatoire** | Type de champ | | `required` | *optionnel* | Mettre à `true` si le champ est obligatoire | | `label` | *optionnel* | Libellé du champ | | `help` | *optionnel* | Texte d'aide, affiché sous le champ | | `default` | *optionnel* | Valeur du champ par défaut, si le formulaire n'a pas été envoyé, et que la valeur dans `source` est vide | | `source` | *optionnel* | Source de pré-remplissage du champ. Si le nom du champ est `montant`, alors la valeur de `[source].montant` sera affichée si présente. | Si `label` ou `help` sont spécifiés, le champ sera intégré à une balise HTML `<dd>`, et le libellé sera intégré à une balise `<dt>`. Dans ce cas il faut donc que le champ soit dans une liste `<dl>`. Si ces deux paramètres ne sont pas spécifiés, le champ sera le seul tag HTML. ``` <dl> {{:input name="amount" type="money" label="Montant" required=true}} </dl> ``` Note : le champ aura comme `id` la valeur `f_[name]`. Ainsi un champ avec `amount` comme `name` aura `id="f_amount"`. ### Valeur du champ La valeur du champ est remplie avec : * la valeur dans `$_POST` qui correspond au `name` ; * sinon la valeur dans `source` (tableau) avec le même nom (exemple : `$source[name]`) ; * sinon la valeur de `default` est utilisée. Note : le paramètre `value` n'est pas supporté sauf pour checkbox et radio. ### Types de champs supportés * les types classiques de `input` en HTML : text, search, email, url, file, date, checkbox, radio, password, etc. * Note : pour checkbox et radio, il faut utiliser le paramètre `value` en plus pour spécifier la valeur. * `textarea` * `money` créera un champ qui attend une valeur de monnaie au format décimal * `datetime` créera un champ date et un champ texte pour entrer l'heure au format `HH:MM` * `radio-btn` créera un champ de type radio mais sous la forme d'un gros bouton * `select` crée un sélecteur de type `<select>`. Dans ce cas il convient d'indiquer un tableau associatif dans le paramètre `options`. * `select_groups` crée un sélecteur de type `<select>`, mais avec des `<optgroup>`. Dans ce cas il convient d'indiquer un tableau associatif à deux niveaux dans le paramètre `options`. * `list` crée un champ permettant de sélectionner un ou des éléments (selon si le paramètre `multiple` est `true` ou `false`) dans un formulaire externe. Le paramètre `can_delete` indique si l'utilisateur peut supprimer l'élément déjà sélectionné (si `multiple=false`). La sélection se fait à partir d'un formulaire dont l'URL doit être spécifiée dans le paramètre `target`. Les formulaires actuellement supportés sont : * `!acc/charts/accounts/selector.php?targets=X` pour sélectionner un compte du plan comptable, où X est une liste de types de comptes qu'il faut permettre de choisir (séparés par des `:`) * `!users/selector.php` pour sélectionner un membre ## button Affiche un bouton, similaire à `<button>` en HTML, mais permet d'ajouter une icône par exemple. ``` {{:button type="submit" name="save" label="Créer ce membre" shape="plus" class="main"}} ``` | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `type` | optionnel | Type du bouton | | `name` | optionnel | Nom du bouton | | `label` | optionnel | Label du bouton | | `shape` | optionnel | Affiche une icône en préfixe du label | | `class` | optionnel | Classe CSS | | `title` | optionnel | Attribut HTML `title` | | `disabled` | optionnel | Désactive le bouton si `true` | ## link Affiche un lien. ``` {{:link href="!users/new.php" label="Créer un nouveau membre"}} ``` | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `href` | **obligatoire** | Adresse du lien | | `label` | **obligatoire** | Libellé du lien | | `target` | *optionnel* | Cible du lien, utiliser `_dialog` pour que le lien s'ouvre dans une fenêtre modale. | Préfixer l'adresse par "!" donnera une URL absolue en préfixant l'adresse par l'URL de l'administration. Sans "!", l'adresse générée sera relative au contexte d'appel (module/plugin ou squelette site web). ## linkbutton Affiche un lien sous forme de faux bouton, avec une icône si le paramètre `shape` est spécifié. ``` {{:linkbutton href="!users/new.php" label="Créer un nouveau membre" shape="plus"}} ``` | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `href` | **obligatoire* | Adresse du lien | | `label` | **obligatoire** | Libellé du bouton | | `target` | *optionnel* | Cible de l'ouverture du lien | | `shape` | *optionnel* | Affiche une icône en préfixe du label | Si on utilise `target="_dialog"` alors le lien s'ouvrira dans une fenêtre modale (iframe) par dessus la page actuelle. Si on utilise `target="_blank"` alors le lien s'ouvrira dans un nouvel onglet. ## icon Affiche une icône. ``` {{:icon shape="print"}} ``` | Paramètre | Obligatoire ou optionnel ? | Fonction | | :- | :- | :- | | `shape` | **obligatoire** | Forme de l'icône. | # Formes d'icônes disponibles  |
Modified doc/admin/brindille_modifiers.md from [dc87155bc4] to [6c3b819d22].
1 2 3 4 5 6 7 8 9 10 11 12 13 | Title: Référence des filtres Brindille {{{.nav * [Documentation Brindille](brindille.html) * [Fonctions](brindille_functions.html) * [Sections](brindille_sections.html) * **[Filtres](brindille_modifiers.html)** }}} <<toc aside>> # Filtres PHP | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > | > | > | > | > > > > > > | > | > | | > | | | > | < > > | | > | | | < > > > > | > | > > > > > | > | > > > > | > > | > > > | | > | > > > > > | > > > > | > > | > > > > | > | > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | Title: Référence des filtres Brindille {{{.nav * [Modules](modules.html) * [Documentation Brindille](brindille.html) * [Fonctions](brindille_functions.html) * [Sections](brindille_sections.html) * **[Filtres](brindille_modifiers.html)** }}} <<toc aside>> # Filtres PHP Ces filtres viennent directement de PHP et utilisent donc les mêmes paramètres. Voir la [documentation PHP](https://www.php.net/manual/fr/function.htmlspecialchars.php) pour plus de détails. | Nom | Description | | :- | :- | | `htmlentities` | Convertit tous les caractères éligibles en entités HTML | | `htmlspecialchars` | Convertit les caractères spéciaux en entités HTML | | `trim` | Supprime les espaces et lignes vides au début et à la fin d'un texte | | `ltrim` | Supprime les espaces et lignes vides au début d'un texte | [Documentation](https://www.php.net/ltrim) | | `rtrim` | Supprime les espaces et lignes vides à la fin d'un texte | [Documentation](https://www.php.net/rtrim) | | `md5` | Génère un hash MD5 d'un texte | | `sha1` | Génère un hash SHA1 d'un texte | | `strlen` | Nombre de caractères dans une chaîne de texte | | `strpos` | Position d'un élément dans une chaîne de texte | | `strrpos` | Position d'un dernier élément dans une chaîne de texte | | `strip_tags` | Supprime les tags HTML | | `nl2br` | Remplace les retours à la ligne par des tags HTML `<br/>` | | `wordwrap` | Ajoute des retours à la ligne tous les 75 caractères | | `substr` | Découpe une chaîne de caractère | | `abs` | Renvoie la valeur absolue d'un nombre (exemple : -42 sera transformé en 42) | | `intval` | Transforme une valeur en entier (integer) | | `boolval` | Transforme une valeur en booléen (true ou false) | | `floatval` | Transforme une valeur en nombre flottant (à virgule) | | `strval` | Transforme une valeur en chaîne de texte | | `arrayval` | Transforme une valeur en tableau | | `json_decode` | Transforme une chaîne JSON en tableau | | `json_encode` | Transforme une valeur en chaîne JSON | # Filtres utiles pour les e-mails ## check_email Permet de vérifier la validité d'une adresse email. Cette fonction vérifie la syntaxe de l'adresse mais aussi que le nom de domaine indiqué possède bien un enregistrement de type MX. Renvoie `true` si l'adresse est valide. ``` {{if !$_POST.email|check_email}} <p class="alert">L'adresse e-mail indiquée est invalide.</p> {{/if}} ``` ## protect_contact Crée un lien protégé pour une adresse email, pour éviter que l'adresse ne soit recueillie par les robots spammeurs (empêche également le copier-coller et le lien ne fonctionnera pas avec javascript désactivé). # Filtres de tableaux ## has Renvoie vrai si le tableau contient l'élément passé en paramètre. ``` {{:assign var="table" a="bleu" b="orange"}} {{if $table|has:"bleu"}} Oui, il y a du bleu {{/if}} ``` ## in Renvoie vrai si l'élément fait partie du tableau passé en paramètre. C'est exactement la même chose que `has`, mais exprimé à l'envers. ``` {{:assign var="table" a="bleu" b="orange"}} {{if "bleu"|in:$table}} Oui, il y a du bleu {{/if}} ``` ## keys Renvoie les clés du tableau, sous forme de tableau. ``` {{:assign var="table" a="bleu" b="orange"}} {{:assign var="cles" value=$table|keys}} {{$cles|implode:","}} ``` Donnera : ``` a,b ``` ## values Renvoie les valeurs du tableau, sous forme de tableau. Cela revient en fait à supprimer les clés associatives. ``` {{:assign var="table" a="bleu" b="orange"}} {{#foreach from=$table key="cle" item="valeur"}} {{$cle}} = {{$valeur}} {{/foreach}} -- {{:assign var="valeurs" value=$table|values}} {{#foreach from=$valeurs key="cle" item="valeur"}} {{$cle}} = {{$valeur}} {{/foreach}} ``` Donnera : ``` a = bleu b = orange -- 0 = bleu 1 = orange ``` ## count Compte le nombre d'entrées dans un tableau. ``` {{$products|count}} = 5 ``` ## explode Sépare une chaîne de texte en tableau à partir d'une chaîne de séparation. ``` {{:assign var="table" value="a,b,c"|explode:","}} - {{$table.0}} - {{$table.1}} - {{$table.2}} ``` Affichera : ``` - a - b - c ``` ## implode Réunit un tableau sous forme de chaîne de texte en utilisant éventuellement une chaîne de liaison entre chaque élément du tableau. ``` {{:assign var="table" a="bleu" b="orange"}} {{$table|implode}} {{$table|implode:" - "}} ``` Affichera : ``` bleuorange bleu - orange ``` ## map Applique un filtre sur chaque élément du tableau. Le premier paramètre doit être le nom du filtre. Les autres paramètres seront passés au filtre. ``` {{:assign var="table" a="01" b="02"}} {{:assign var="table" value=$table|map:intval}} - {{$table.a}} - {{$table.b}} ``` Affichera : ``` - 1 - 2 ``` ## ksort, sort Trie un tableau par ordre alpha-numérique, sans tenir compte des majuscules/minuscules. `ksort` trie le tableau en utilisant les clés, et `sort` trie le tableau en utilisant les valeurs. ``` {{:assign var="table" b="3" a="2" c="1"}} {{$table|sort|implode:","}} {{$table|ksort|implode:","}} ``` Affichera : ``` 1,2,3 2,3,1 ``` # Filtres de texte ## args Remplace des arguments dans le texte selon le schéma utilisé par [sprintf](https://www.php.net/sprintf). ``` {{"Il y a %d résultats dans la recherche sur le terme '%s'."|args:$results_count:$query}} = Il y a 5 résultat dans la recherche sur le terme 'test'. ``` ## cat Concaténer un texte avec un autre. ``` {{"Tangerine"|cat:" Dream"}} = Tangerine Dream ``` ## count_words Compte le nombre de mots dans un texte. ## escape Échappe le contenu pour un usage dans un document HTML. Ce filtre est appliqué par défaut à tout ce qui est affiché (variables, etc.) sauf à utiliser le filtre `raw` (voir plus bas). ## excerpt Produit un extrait d'un texte. Supprime les tags HTML, tronque au nombre de caractères indiqué en second argument (si rien n'est indiqué, alors 600 est utilisé), et englobe dans un paragraphe `<p>...</p>`. Équivalent de : ``` <p>{{$html|strip_tags|truncate:600|nl2br}}</p> ``` ## extract_leading_number Extrait le numéro au début d'une chaîne de texte. Exemple : ``` {{:assign title="02. Cours sur la physique nucléaire"}} {{$title|extract_leading_number}} ``` Affichera : ``` 02 ``` ## markdown Transforme un texte en HTML en utilisant la syntaxe Markdown. Il est conseillé de rajouter le filtre `|raw` pour ne pas échapper le HTML produit, si on veut afficher le texte formatté dans une page HTML. ``` {{$texte|markdown|raw}} ``` ## raw Passer ce filtre désactive la protection automatique contre le HTML (échappement) dans le texte. À utiliser en connaissance de cause avec les contenus qui contiennent du HTML et sont déjà filtrés ! ``` {{"<b>Test"}} = <b>Test {{"<b>Test"|raw}} = <b>Test ``` ## replace Remplace des parties du texte par une autre partie. ``` {{"Tata yoyo"|replace:"yoyo":"yaya"}} = Tata yaya ``` ## regexp_replace Remplace des valeurs en utilisant une expression rationnelles (regexp) ([documentation PHP](https://www.php.net/manual/fr/regexp.introduction.php)). ``` {{"Tartagueule"|regexp_replace:"/ta/i":"tou"}} = tourtougueule ``` ## remove_leading_number Supprime le numéro au début d'un titre. Cela permet de définir un ordre spécifique aux pages et catégories dans les listes. ``` {{"03. Beau titre"|remove_leading_number}} Beau titre ``` ## truncate Tronque un texte à une longueur définie. | Argument | Fonction | Valeur par défaut (si omis) | | :- | :- | :- | | 1 | longueur en nombre de caractères | 80 | | 2 | texte à placer à la fin (si tronqué) | … | | 3 | coupure stricte, si `true` alors un mot pourra être coupé en deux, si `false` le texte sera coupé au dernier mot complet | `false` | ``` {{:assign texte="Ceci n'est pas un texte."}} {{$texte|truncate:19:"(...)":true}} {{$texte|truncate:19:"":false}} ``` Affichera : ``` Ceci n'est pas un (...) Ceci n'est pas un t ``` ## typo Formatte un texte selon les règles typographiques françaises : ajoute des espaces insécables devant ou derrière les ponctuations françaises (`« » ? ! :`). ## urlencode Encode une chaîne de texte pour utilisation dans une adresse URL (alias de `rawurlencode` en PHP). ## xml_escape Échappe le contenu pour un usage dans un document XML. ## Autres filtres de texte Les filtres suivants modifient la casse (majuscule/minuscules) d'un texte et ne fonctionneront correctement que si l'extension `mbstring` est installée sur le serveur. Sinon les lettres accentuées ne seront pas modifiées. Note : il est donc préférable d'utiliser la propriété CSS [`text-transform`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-transform) pour modifier la casse si l'usage n'est que pour l'affichage, et non pas pour enregistrer les données. * `tolower` : transforme un texte en minuscules * `toupper` : transforme un texte en majuscules * `ucfirst` : met la première lettre du texte en majuscule * `ucwords` : met la première lettre de chaque mot en majuscule * `lcfirst` : met la première lettre du texte en minuscule # Filtres sur les sommes en devises ## money Formatte une valeur de monnaie pour l'affichage. Une valeur de monnaie doit **toujours** inclure les cents (exprimée sous forme d'entier). Ainsi `15,02` doit être exprimée sous la forme `1502`. Paramètres optionnels : 1. `true` (défaut) pour ne rien afficher si la valeur est zéro, ou `false` pour afficher `0,00` 2. `true` pour afficher le signe `+` si le nombre est positif (`-` est toujours affiché si le nombre est négatif) ``` {{* 12 345,67 = 1234567 *}} {{:assign amount=1234567}} {{$amount|money}} 12 345,67 ``` ## money_currency Comme `money` (même paramètres), formatte une valeur de monnaie (entier) pour affichage, mais en ajoutant la devise. ``` {{:assign amount=1502}} {{$amount|money_currency}} 15,02 € ``` ## money_html Idem que `money`, mais pour l'affichage en HTML : ``` {{* 12 345,67 = 1234567 *}} {{:assign amount=1234567}} {{$amount|money_html}} <span class="money">12 345,67</span> ``` ## money_currency_html Idem que `money_currency`, mais pour l'affichage en HTML : ``` {{:assign amount=1502}} {{$amount|money_currency_html}} <span class="money">15,02 €</span> ``` ## money_raw Formatte une valeur de monnaie (entier) de manière brute : les milliers n'auront pas de séparateur. ``` {{:assign amount=1234567}} {{$amount|money_raw}} 12345,67 ``` ## money_int Transforme un nombre à partir d'une chaîne de caractère (par exemple `12345,67`) en entier (`1234567`) pour stocker une valeur de monnaie. ``` {{:assign montant=$_POST.montant|trim|money_int}} ``` # Filtres SQL ## quote_sql Protège une chaîne contre les attaques SQL, pour l'utilisation dans une condition. **Note : il est FORTEMENT déconseillé d'intégrer directement des sources extérieures dans les requêtes SQL, il est préférable d'utiliser les paramètres dans la boucle `sql` et ses dérivées, comme ceci : `{{#sql select="id, nom" tables="users" where="lettre_infos = :lettre" :lettre=$_GET.lettre}}`.** Exemple : ``` {{:assign nom=$_GET.nom|quote_sql}} {{#sql select="id, nom" tables="users" where="nom = %s"|args:$nom}} ``` ## quote_sql_identifier La même chose que `quote_sql`, mais pour les identifiants (par exemple nom de table ou de colonne). Exemple : ``` {{:assign colonne=$_GET.colonne|quote_sql_identifier}} {{#sql select="id, %s"|args:$colonne tables="users"}} ``` Il est possible d'utiliser un préfixe en argument, utile par exemple quand on a plusieurs tables avec le même nom de colonne : ``` {{:assign colonne=$_GET.colonne|quote_sql_identifier:"u1"}} {{#sql select="u1.id, %s"|args:$colonne tables="users AS u1 INNER JOIN users AS u2 ON u2.id_parent = u1.id"}} ``` ## sql_where Permet de créer une partie d'une clause SQL `WHERE` complexe. Le premier paramètre est le nom de la colonne (sans préfixe). Paramètres : 1. Comparateur : `=, !=, IN, NOT IN, >, >=, <, <=` 2. Valeur à comparer (peut être un tableau) Exemple pour afficher la liste des membres des catégories n°1 et n°2: ``` {{:assign var="list." value=1}} {{:assign var="list." value=2}} {{#sql select="nom" tables="users" where="id_category"|sql_where:'IN':$id_list}} {{$nom}} {{/sql}} ``` Le requête SQL générée sera alors `SELECT nom FROM users WHERE id_category IN (1, 2)`. # Filtres de date ## date Formatte une date selon le format spécifié en premier paramètre. Le format est identique au [format utilisé par PHP](https://www.php.net/manual/fr/datetime.format.php). Si aucun format n'est indiqué, le défaut sera `d/m/Y à H:i`. (en français) ## strftime Formatte une date selon un format spécifié en premier paramètre. Le format à utiliser est identique [au format utilisé par la fonction strftime de PHP](https://www.php.net/strftime). Un format doit obligatoirement être spécifié. En passant un code de langue en second paramètre, cette langue sera utilisée. Sont supportés le français (`fr`) et l'anglais (`en`). Le défaut est le français si aucune valeur n'est passée en second paramètre . ## relative_date Renvoie une date relative à la date du jour : `aujourd'hui`, `hier`, `demain`, ou sinon `mardi 2 janvier` (si la date est de l'année en cours) ou `2 janvier 2021` (si la date est d'une autre année). En spécifiant `true` en premier paramètre, l'heure sera ajoutée au format `14h34`. ## date_short Formatte une date au format court : `d/m/Y`. En spécifiant `true` en premier paramètre l'heure sera ajoutée : `à H\hi`. ## date_long Formatte une date au format long : `lundi 2 janvier 2021`. En spécifiant `true` en premier paramètre l'heure sera ajoutée : `à 20h42`. ## date_hour Formatte une date en renvoyant l'heure uniquement : `20h00`. En passant `true` en premier paramètre, les minutes seront omises si elles sont égales à zéro : `20h`. ## atom_date Formatte une date au format ATOM : `Y-m-d\TH:i:sP` ## parse_date Vérifie le format d'une chaîne de texte représentant la date et la transforme en chaîne de date standardisée au format `AAAA-MM-JJ`. Les formats acceptés sont : * `AAAA-MM-JJ` * `JJ/MM/AAAA` * `JJ/MM/AA` ## parse_datetime Vérifie le format d'une chaîne de texte représentant la date et l'heure et la transforme en chaîne de date et heure standardisée au format `AAAA-MM-JJ HH:mm`. Les formats acceptés sont : * `AAAA-MM-JJ HH:mm:ss` * `AAAA-MM-JJ HH:mm` * `JJ/MM/AAAA HH:mm` ## parse_time Vérifie le format d'une chaîne de texte représentant l'heure et la transforme en chaîne de date standardisée au format `HH:MM`. Les formats acceptés sont : * `HH:MM` * `H:M` * `H:MM` * `HH:M` Le séparateur peut être `:` ou `h`. # Filtres de condition Ces filtres sont à utiliser dans les conditions ## match Renvoie `true` si le texte indiqué en premier paramètre est trouvé dans la variable. Ce filtre est insensible à la casse. ``` {{if $page.path|match:"/aide"}}Bienvenue dans l'aide !{{/if}} ``` ## regexp_match Renvoie `true` si l'expression régulière indiquée en premier paramètre est trouvée dans la variable. Exemple pour voir si le texte contient les mots "Bonjour" ou "Au revoir" (insensible à la casse) : ``` {{if $texte|regexp_match:"/Bonjour|Au revoir/i"}} Trouvé ! {{else}} Rien trouvé :-( {{/if}} ``` # Autres filtres ## math Réalise un calcul mathématique. Cette fonction accepte : * les nombres: `42`, `13,37`, `14.05` * les signes : `+ - / *` pour additionner, diminuer, diviser ou multiplier |
︙ | ︙ | |||
130 131 132 133 134 135 136 | {{"1+%d"|math:$age}} = 43 {{:assign prix=39.99 tva=19.1}} {{"round(%f*%f, 2)"|math:$prix:$tva}} = 47.63 ``` | < < | < > < < > > < | < < < > > < | < < | < < | < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < > < | < < < < < < < < | < < < < < < < < | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 | {{"1+%d"|math:$age}} = 43 {{:assign prix=39.99 tva=19.1}} {{"round(%f*%f, 2)"|math:$prix:$tva}} = 47.63 ``` ## or Si la variable passée est évalue comme `false` (c'est à dire que sa valeur est un texte vide, ou un nombre qui vaut zéro, ou la valeur `false`), alors le premier paramètre sera utilisé. ``` {{:assign texte=""}} {{$texte|or:"Le texte est vide"}} ``` Il est possible de chaîner les appels à `or` : ``` {{:assign texte1="" texte2="0"}} {{$texte1|or:$texte2|or:"Aucun texte"}} ``` ## size_in_bytes Renvoie une taille en octets, Ko, Mo, ou Go à partir d'une taille en octets. ``` {{100|size_in_bytes}} = 100 o {{1500|size_in_bytes}} = 1,50 Ko {{1048576|size_in_bytes}} = 1 Mo ``` ## spell_out_number Épelle un nombre en toutes lettres. Le premier paramètre peut être utilisé pour spécifier le code de la langue à utiliser (par défaut c'est le français, donc le code `fr`). ``` {{42|spell_out_number}} ``` Donnera : ``` quarante deux ``` ## uuid Renvoie un identifiant unique au format UUIDv4. |
Modified doc/admin/brindille_sections.md from [3025661395] to [7106a855ae].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Title: Référence des sections Brindille {{{.nav * [Documentation Brindille](brindille.html) * [Fonctions](brindille_functions.html) * **[Sections](brindille_sections.html)** * [Filtres](brindille_modifiers.html) }}} <<toc aside level=2>> # Sections généralistes ## foreach | > | > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | > | > > > > > > | > | > > > | > > | > > > > > > > > > > > > > > > > | > > > > | > > > | < | > > > > > > > > | > > > > | > | > | > > > > | > > > > > | > > > > > > | | > > > | > | > | > > > > > | > | | < > > > > | > | > > > > > | > | > | < > | | > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | Title: Référence des sections Brindille {{{.nav * [Modules](modules.html) * [Documentation Brindille](brindille.html) * [Fonctions](brindille_functions.html) * **[Sections](brindille_sections.html)** * [Filtres](brindille_modifiers.html) }}} <<toc aside level=2>> # Sections généralistes ## foreach Permet d'itérer sur un tableau par exemple. Ainsi chaque élément du tableau exécutera une fois le contenu de la section. | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `from` | **obligatoire** | Variable sur laquelle effectuer l'itération | | `key` | **optionnel** | Nom de la variable à utiliser pour la clé de l'élément | | `value` | **optionnel** | Nom de la variable à utiliser pour la valeur de l'élément | Considérons ce tableau : ``` {{:assign var="tableau" a="bleu" b="orange"}} ``` On peut alors itérer pour récupérer les clés (`a` et `b` ainsi que les valeurs `bleu` et `orange`) : ``` {{#foreach from=$tableau key="key" item="value"}} {{$key}} = {{$value}} {{/foreach}} ``` Cela affichera : ``` a = bleu b = orange ``` Si on a un tableau à plusieurs niveaux, les éléments du tableau sont automatiquement transformés en variable : ``` {{:assign var="tableau.a" couleur="bleu"}} {{:assign var="tableau.b" couleur="orange"}} ``` ``` {{#foreach from=$variable}} {{$couleur}} {{/foreach}} ``` Affichera : ``` bleu orange ``` ### Itérer sans tableau Il est aussi possible de faire `X` itérations, arbitrairement, sans avoir de tableau en entrée, en utilisant le paramètre `count`. C'est l'équivalent des boucles `for` dans les autres langages de programmation. Exemple : ``` {{#foreach count=3 key="i"}} - {{$i}} {{/foreach}} ``` Affichera : ``` - 0 - 1 - 2 ``` ## restrict Permet de limiter (restreindre) une partie de la page aux membres qui sont connectés et/ou qui ont certains droits. Deux paramètres optionnels peuvent être utilisés ensemble (il n'est pas possible d'utiliser seulement un des deux) : | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `level` | *optionnel* | Niveau d'accès : `read`, `write`, `admin` | | `section` | *optionnel* | Section où le niveau d'accès doit s'appliquer : `users`, `accounting`, `web`, `documents`, `config` | | `block` | *optionnel* | Si ce paramètre est présent et vaut `true`, alors l'accès sera interdit si les conditions d'accès demandées ne sont pas remplies : une page d'erreur sera renvoyée. | Exemple pour voir si un membre est connecté : ``` {{#restrict}} Un membre est connecté, mais on ne sait pas avec quels droits. {{else}} Aucun membre n'est connecté. {{/restrict}} ``` Exemple pour voir si un membre qui peut administrer les membres est connecté : ``` {{#restrict section="users" level="admin"}} Un membre est connecté, et il a le droit d'administrer les membres. {{else}} Aucun membre n'est connecté, ou un membre est connecté mais n'est pas administrateur des membres. {{/restrict}} ``` Pour bloquer l'accès aux membres non connectés, ou qui n'ont pas accès en écriture à la comptabilité. ``` {{#restrict block=true section="accounting" level="write"}} {{/restrict}} ``` Le mieux est de mettre ce code au début d'un squelette. # Requêtes SQL ## select Exécute une requête SQL `SELECT` et effectue une itération pour chaque résultat de la requête. Pour une utilisation plus simplifiée des requêtes, voir aussi la section [sql](#sql). Attention : la syntaxe de cette section est différente des autres sections Brindille. En effet après le début (`{{#select`) doit suivre la suite de la requête, et non pas les paramètres : ``` Liste des membres inscrits à la lettre d'informations : {{#select nom, prenom FROM users WHERE lettre_infos = 1;}} - {{prenom}} {{$nom}}<br /> {{else}} Aucun membre n'est inscrit à la lettre d'information. {{/select}} ``` Des paramètres nommés de SQL peuvent être présentés après le point-virgule marquant la fin de la requête SQL : ``` {{:assign prenom="Karim"}} {{#select * FROM users WHERE prenom = :prenom; :prenom=$prenom}} ... {{/select}} ``` Notez les deux points avant le nom du paramètre. Ces paramètres sont protégés contre les injections SQL (généralement appelés paramètres nommés). Pour intégrer des paramètres qui ne sont pas protégés (**attention !**), il faut utiliser le point d'exclamation : ``` {{:assign var="categories." value=1}} {{:assign var="categories." value=2}} {{#select * FROM users WHERE !categories; !categories='id_category'|sql_where:'IN':$categories}} ``` Cela créera la requête suivante : `SELECT * FROM users WHERE id_category IN (1, 2);` Il est aussi possible d'intégrer directement des variables dans la requête, en utilisant la syntaxe `{$variable|filtre:argument1:argument2}`, comme une variable classique donc, mais au lieu d'utiliser des doubles accolades, on utilise ici des accolades simples. Ces variables seront automatiquement protégées contre les injections SQL. ``` {{:assign prenom="Camille"}} {{#select * FROM users WHERE initiale_prenom = {$prenom|substr:0:1};}} ``` Cependant, pour plus de lisibilité il est conseillé d'utiliser la syntaxe des paramètres nommés SQL (voir ci-dessus). Il est aussi possible d'insérer directement du code SQL (attention aux problèmes de sécurité dans ce cas !), pour cela il faut rajouter un point d'exclamation après l'accolade ouvrante : ``` {{:assign var="prenoms." value="Karim"}} {{:assign var="prenoms." value="Camille"}} {{#select * FROM users WHERE {!"prenom"|sql_where:"IN":$prenoms};}} ... {{/select}} ``` Il est aussi possible d'utiliser les paramètres suivants : | Paramètre | Fonction | | :- | :- | | `debug` | Si ce paramètre existe, la requête SQL exécutée sera affichée avant le début de la boucle. | | `explain` | Si ce paramètre existe, l'explication de la requête SQL exécutée sera affichée avant le début de la boucle. | | `assign` | Si renseigné, une variable de ce nom sera créée, et le contenu de la ligne y sera assigné. | Exemple avec `debug` : ``` {{:assign prenom="Karim"}} {{#select * FROM users WHERE prenom = :prenom; :prenom=$prenom debug=true}} ... {{/select}} ``` Affichera juste au dessus du résultat la requête exécutée : ``` SELECT * FROM users WHERE nom = 'Karim' ``` ### Paramètre assign Exemple avec `assign` : ``` {{#select * FROM users WHERE prenom = 'Camille' LIMIT 1; assign="membre"}}{{/select}} {{$membre.nom}} ``` Il est possible d'utiliser un point final pour que toutes les lignes soient mises dans un tableau : ``` {{#select * FROM users WHERE prenom = 'Camille' LIMIT 10; assign="membres."}}{{/select}} {{#foreach from=$membres}} Nom : {{$nom}}<br /> Adresse : {{$adresse}} {{/foreach}} ``` ## sql Effectue une requête SQL de type `SELECT` dans la base de données, mais de manière simplifiée par rapport à `select`. ``` {{#sql select="*, julianday(date) AS day" tables="membres" where="id_categorie = :id_categorie" :id_categorie=$_GET.id_categorie order="numero DESC" begin=":page*100" limit=100 :page=$_GET.page}} … {{/sql}} ``` | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `tables` | **obligatoire** | Liste des tables à utiliser dans la requête (séparées par des virgules). | | `select` | *optionnel* | Liste des colonnes à sélectionner, si non spécifié, toutes les colonnes (`*`) seront sélectionnées | ### Sections qui héritent de `sql` Certaines sections (voir plus bas) héritent de `sql` et rajoutent des fonctionnalités. Dans toutes ces sections, il est possible d'utiliser les paramètres suivants : | Paramètre | Fonction | | :- | :- | | `where` | Condition de sélection des résultats | | `begin` | Début des résultats, si vide une valeur de `0` sera utilisée. | | `limit` | Limitation des résultats. Si vide, une valeur de `1000` sera utilisée. | | `group` | Contenu de la clause `GROUP BY` | | `having` | Contenu de la clause `HAVING` | | `order` | Ordre de tri des résultats. Si vide le tri sera fait par ordre d'ajout dans la base de données. | | `assign` | Si renseigné, une variable de ce nom sera créée, et le contenu de la ligne du résultat y sera assigné. | | `debug` | Si ce paramètre existe, la requête SQL exécutée sera affichée avant le début de la boucle. | | `explain` | Si ce paramètre existe, l'explication de la requête SQL exécutée sera affichée avant le début de la boucle. | Il est également possible de passer des arguments dans les paramètres à l'aides des arguments nommés qui commencent par deux points `:` : ``` {{#articles where="title = :montitre" :montitre="Actualité"}} ``` # Membres ## users Liste les membres. Paramètres possibles : | `id` | optionnel | Identifiant unique du membre, ou tableau contenant une liste d'identifiants. | | `search_name` | optionnel | Ne lister que les membres dont le nom correspond au texte passé en paramètre. | | `id_parent` | optionnel | Ne lister que les membres rattachés à l'identifiant unique du membre responsable indiqué. | Chaque itération renverra la fiche du membre, ainsi que ces variables : | `$id` | Identifiant unique du membre | | `$_name` | Nom du membre, tel que défini dans la configuration | | `$_login` | Identifiant de connexion du membre, tel que défini dans la configuration | | `$_number` | Numéro du membre, tel que défini dans la configuration | ## subscriptions Liste les inscriptions à une ou des activités. Paramètres possibles : | Paramètre | | Fonction | | :- | :- | :- | | `user` | optionnel | Identifiant unique du membre | | `active` | optionnel | Si `TRUE`, seules les inscriptions à jour sont listées | | `id_service` | optionnel | Ne renvoie que les inscriptions à l'activité correspondant à cet ID. | # Comptabilité ## accounts Liste les comptes d'un plan comptable. | Paramètre | Fonction | | :- | :- | | `codes` (optionel) | Ne renvoyer que les comptes ayant ces codes (séparer par des virgules). | | `id` (optionel) | Ne renvoyer que le compte ayant cet ID. | ## balances Renvoie la balance des comptes. | Paramètre | Fonction | | :- | :- | | `codes` (optionel) | Ne renvoyer que les balances des comptes ayant ces codes (séparer par des virgules). | | `year` (optionel) | Ne renvoyer que les balances des comptes utilisés sur l'année (indiquer ici un ID de year). | ## transactions Renvoie des écritures. | Paramètre | | Fonction | | :- | :- | :- | | `id` | optionnel | Indiquer un ID d'écriture pour récupérer ses informations. | | `user` | optionnel | Indiquer ici un ID utilisateur pour lister les écritures liées à un membre. | ## years Liste les exercices comptables | Paramètre | Fonction | | :- | :- | | `closed` (optionel) | Mettre `closed=true` pour ne lister que les exercices clôturés, ou `closed=false` pour ne lister que les exercices ouverts. | # Pour le site web ## breadcrumbs Permet de récupérer la liste des pages parentes d'une page afin de constituer un [fil d'ariane](https://fr.wikipedia.org/wiki/Fil_d'Ariane_(ergonomie)) permettant de remonter dans l'arborescence du site Un seul paramètre est possible : | Paramètre | Fonction | | :- | :- | | `uri` (obligatoire) | Adresse unique de la page parente | | ou `id_page` (obligatoire) | Numéro unique (ID) de la page parente | Chaque itération renverra trois variables : | Variable | Contenu | | :- | :- | | `$id` | Numéro unique (ID) de la page ou catégorie | | `$title` | Titre de la page ou catégorie | | `$uri` | Nom unique de la page ou catégorie | | `$url` | Adresse HTTP de la page ou catégorie | ### Exemple ``` <ul> {{#breadcrumbs id_page=$page.id}} <li>{{$title}}</li> {{/breadcrumbs}} </ul> ``` ## pages, articles, categories <sup>(sql)</sup> Note : ces sections héritent de `sql` (voir plus haut). * `pages` renvoie une liste de pages, qu'elles soient des articles ou des catégories * `categories` ne renvoie que des catégories * `articles` ne renvoie que des articles À part cela ces trois types de section se comportent de manière identique. | Paramètre | Fonction | | :- | :- | | `search` | Renseigner ce paramètre avec un terme à rechercher dans le texte ou le titre. Dans ce cas par défaut le tri des résultats se fait sur la pertinence, sauf si le paramètre `order` est spécifié. | | `future` | Renseigner ce paramètre à `false` pour que les articles dont la date est dans le futur n'apparaissent pas, `true` pour ne renvoyer QUE les articles dans le futur, et `null` (ou ne pas utiliser ce paramètre) pour que tous les articles, passés et futur, apparaissent. | | `uri` | Adresse unique de la page/catégorie à retourner. | | `id_parent` | Numéro unique (ID) de la catégorie parente. Utiliser `null` pour n'afficher que les articles ou catégories de la racine du site. | | `parent` | Adresse unique (URI) de la catégorie parente. Exemple pour renvoyer la liste des articles de la sous-catégorie "Événements" de la catégorie "Notre atelier" : `evenements`. Utiliser `null` pour n'afficher que les articles ou catégories de la racine du site. Ajouter un point d'exclamation au début de la valeur pour inverser la condition. | Par exemple lister 5 articles de la catégorie "Actualité", qui ne sont pas dans le futur, triés du plus récent au plus ancien : ``` {{#articles future=false parent="actualite" order="published DESC" limit=5}} <h3>{{$title}}</h3> {{/articles}} ``` Chaque élément de ces boucles contiendra les variables suivantes : | Nom de la variable | Description | Exemple | | :- | :- | :- | | `id` | Numéro unique de la page (ID) | `1312` | | `id_parent` | Numéro unique de la catégorie parente (ID) | `42` | | `type` | Type de page : `1` = catégorie, `2` = article | `2` | | `uri` | Adresse unique de la page | `bourse-aux-velos` | | `url` | Adresse HTTP de la page | `https://site.association.tld/bourse-aux-velos` | | `path` | Chemin complet de la page | `actualite/atelier/bourse-aux-velos` | | `parent` | Chemin de la catégorie parente | `actualite/atelier`| | `title` | Titre de la page | `Bourse aux vélos` | | `content` | Contenu brut de la page | `# Titre …` | | `html` | Rendu HTML du contenu de la page | `<div class="web-content"><h1>Titre</h1>…</div>` | | `has_attachments` | `true` si la page a des fichiers joints, `false` sinon | `true` | | `published` | Date de publication | `2023-01-01 01:01:01` | | `modified` | Date de modification | `2023-01-01 01:01:01` | Si une recherche a été effectuée, deux autres variables sont fournies : | Nom de la variable | Description | Exemple | | :- | :- | :- | | `snippet` | Extrait du contenu contenant le texte recherché (entouré de balises `<mark>`) | `L’ONU appelle la France à s’attaquer aux « profonds problèmes » de <mark>racisme</mark> au sein des forces de…` | | `url_highlight` | Adresse de la page, où le texte recherché sera mis en évidence | `https://.../onu-racisme#:~:text=racisme%20au%20sein` | ## files, documents, images <sup>(sql)</sup> Note : ces sections héritent de `sql` (voir plus haut). * `files` renvoie une liste de fichiers * `documents` renvoie une liste de fichiers qui ne sont pas des images * `images` renvoie une liste de fichiers qui sont des images À part cela ces trois types de section se comportent de manière identique. Note : seul les fichiers de la section site web sont accessibles, les fichiers de membres, de comptabilité, etc. ne sont pas disponibles. | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `parent` | **obligatoire** si `id_parent` n'est pas renseigné | Nom unique (URI) de l'article ou catégorie parente dont ont veut lister les fichiers | | `id_parent` | **obligatoire** si `parent` n'est pas renseigné | Numéro unique (ID) de l'article ou catégorie parente dont ont veut lister les fichiers | | `except_in_text` | *optionnel* | passer `true` à ce paramètre , et seuls les fichiers qui ne sont pas liés dans le texte de la page seront renvoyés | # Sections relatives aux modules ## form Permet de gérer la soumission d'un formulaire (`<form method="post"…>` en HTML). Si l'élément dont le nom spécifié dans le paramètre `on` a été envoyé en `POST`, alors le code à l'intérieur de la section est exécuté. Toute erreur à l'intérieur de la section arrêtera son exécution, et le message sera ajouté aux erreurs du formulaire. Une vérification de sécurité [anti-CSRF](https://fr.wikipedia.org/wiki/Cross-site_request_forgery) est également appliquée. Si cette vérification échoue, le message d'erreur "Merci de bien vouloir renvoyer le formulaire." sera renvoyé. Pour que cela marche il faut que le formulaire dispose d'un bouton de type "submit", généré à l'aide de la fonction `button`. Exemple : `{{:button type="submit" name="save" label="Enregistrer"}}`. En cas d'erreurs, le reste du contenu de la section ne sera pas exécuté. Les messages d'erreurs seront placés dans un tableau dans la variable `$form_errors`. Il est aussi possible de les afficher simplement avec la fonction `{{:form_errors}}`. Cela revient à faire une boucle sur la variable `$form_errors`. ``` {{#form on="save"}} {{if $_POST.titre|trim === ''}} {{:error message="Le titre est vide."}} {{/if}} {{* La ligne suivante ne sera pas exécutée si le titre est vide. *}} {{:save title=$_POST.titre|trim}} {{else}} {{:form_errors}} {{/form}} ``` Il est possible d'utiliser `{{:form_errors}}` en dehors du bloc `{{else}}` : ``` {{#form on="save"}} … {{/form}} … {{:form_errors}} ``` <!-- NOTE (bohwaz, 24/05/2023) : l'utilisation des règles de validation de Laravel me semble donner du code peu lisible, ce n'est donc pas documenté/complètement implémenté pour le moment. Si l'élément dont le nom spécifié dans le paramètre `on` a été envoyé en `POST`, alors le formulaire est vérifié selon les autres paramètres. Une vérification de sécurité anti-CSRF est également appliquée. Si cette vérification échoue, le message d'erreur "Merci de bien vouloir renvoyer le formulaire." sera renvoyé. Chaque paramètre supplémentaire indique un champ du formulaire qui doit être récupéré et validé. Le nom du paramètre doit correspondre au nom du champ dans le formulaire. La valeur du paramètre doit contenir une liste de règles de validations, séparées par des virgules `,`. Chaque règle peut prendre des paramètres, après deux points `:`. Exemple pour un champ de formulaire nommé `titre` dont on veut qu'il soit présent et fasse entre 5 et 100 caractères : `titre="required,min:5,max:100"` Si le titre fait moins de 5 caractères, le message d'erreur suivant sera renvoyé : `Le champ "titre" fait moins de 5 caractères.` On peut spécifier une règle spéciale nommée `label` pour changer le nom du champ : `titre="required,min:5,max:100,label:Titre du texte"`. Cela modifiera le message d'erreur : `Le champ "Titre du texte" fait moins de 5 caractères.` Chacun de ces paramètres sera disponible à l'intérieur de la section sous la forme d'une variable : ``` {{#form titre="required,min:5"}} {{:save title=$titre}} {{/form}} ``` Toute erreur dans le corps de la section `{{#form}}…{{/form}}` fera arrêter l'exécution, et le message d'erreur sera ajouté à la liste des erreurs du formulaire : ``` {{#form on="save"}} {{if !$_POST.titre|trim}} {{:error message="Pas de titre !"}} {{/if}} {{* La ligne suivante ne sera pas exécutée si le titre est vide. *}} {{:save title=$_POST.titre}} {{/form}} ``` ### Transformation des variables Certaines règles de validation ont un effet de transformation sur les variables présentes dans le corps de la section : * `string` s'assure que la variable est une chaîne de texte * `int` transforme la variable en nombre entier * `float` transforme la variable en nombre flottant * `bool` transforme la variable en booléen * `date` ou `date_format` transforment la variable en date ### Exemple Considérons ce formulaire par exemple : ``` <form method="post" action=""> <fieldset> <legend>Enregistrer un paiement</legend> <dl> {{:input type="text" required=true name="titre" label="Titre"}} {{:input type="money" required=true name="montant" label="Montant"}} </dl> <p class="submit"> {{:button type="submit" label="Enregistrer" name="save"}} </p> </fieldset> </form> ``` On pourrait l'enregistrer comme ceci : ``` {{if $_POST.save}} {{if $_POST.titre|trim === ''}} {{:assign error="Le titre est vide"}} {{elseif $_POST.montant|trim === '' || $_POST.montant|money_int < 0}} {{:assign error="Le montant est vide ou négatif"}} {{else}} {{:save title=$_POST.titre|trim amount=$_POST.montant|money_int}} {{/if}} {{/if}} {{if $error}} <p class="error block">{{$error}}</p> {{/if}} ``` Mais alors dans ce cas il faut multiplier les conditions pour les champs. La section `{{#form …}}` permet de simplifier ces tests, et s'assurer qu'aucune attaque CSRF n'a lieu : ``` {{#form on="save" titre="required,string,min:1,label:Titre" montant="required,money,min:0,label:Montant du paiement" }} {{:save title=$titre amount=$montant}} {{else}} {{:form_errors}} {{/form}} ``` ### Règles de validation | Nom de la règle | Description | Paramètres | | :- | :- | :- | | `required` | ... --> ## load <sup>(sql)</sup> Note : cette section hérite de `sql` (voir plus haut). Charge un ou des documents pour le module courant. | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `module` | optionnel | Nom unique du module lié (par exemple : `recu_don`). Si non spécifié, alors le nom du module courant sera utilisé. | | `key` | optionnel | Clé unique du document | | `id` | optionnel | Numéro unique du document | | `each` | optionnel | Traiter une clé du document comme un tableau | Il est possible d'utiliser d'autres paramètres : `{{#load cle="valeur"}}`. Cela va comparer `"valeur"` avec la valeur de la clé `cle` dans le document JSON. C'est l'équivalent d'écrire `where="json_extract(document, '$.cle') = 'valeur'"`. Pour des conditions plus complexes qu'une simple égalité, il est possible d'utiliser la syntaxe courte `$$…` dans le paramètre `where`. Ainsi `where="$$.nom LIKE 'Bourse%'` est l'équivalent de `where="json_extract(document, '$.nom') LIKE 'Bourse%'"`. Voir [la documentation de SQLite pour plus de détails sur la syntaxe de json_extract](https://www.sqlite.org/json1.html#jex). Note : un index SQL dynamique est créé pour chaque requête utilisant une clause `json_extract`. Chaque itération renverra ces deux variables : | Variable | Valeur | | :- | :- | | `$key` | Clé unique du document | | `$id` | Numéro unique du document | Ainsi que chaque élément du document JSON lui-même. ### Exemples Afficher le nom du document dont la clé est `facture_43` : ``` {{#load key="facture_43"}} {{$nom}} {{/load}} ``` Afficher la liste des devis du module `invoice` depuis un autre module par exemple : ``` {{#load module="invoice" type="quote"}} <h1>Titre du devis : {{$subject}}</h1> <h2>Montant : {{$total}}</h2> {{/load}} ``` ### Utilisation du paramètre `each` Le paramètre `each` est utile pour faire une boucle sur un tableau contenu dans le document. Ce paramètre doit contenir un chemin JSON valide. Par exemple `membres[1].noms` pour boucler sur le tableau `noms`, du premier élément du tableau `membres`. Voir la documentation [de la fonction json_each de SQLite pour plus de détails](https://www.sqlite.org/json1.html#jeach). Pour chaque itération de la section, la variable `{{$value}}` contiendra l'élément recherché dans le critère `each`. Par exemple nous pouvons avoir un élément `membres` dans notre document JSON qui contient un tableau de noms de membres : ``` {{:assign var="membres." value="Greta Thunberg}} {{:assign var="membres." value="Valérie Masson-Delmotte"}} {{:save membres=$membres}} ``` Nous pouvons utiliser `each` pour faire une liste : ``` {{:load each="membres"}} - {{$value}} {{/load}} ``` Ou pour récupérer les documents qui correspondent à un critère : ``` {{:load each="membres" where="value = 'Greta Thunberg'"}} Le document n°{{$id}} est celui qui parle de Greta. {{/load}} ``` ## list Attention : cette section n'hérite **PAS de `sql`**. Un peu comme `{{#load}}` cette section charge les documents d'un module, mais au sein d'une liste (tableau HTML). Cette liste gère automatiquement l'ordre selon les préférences des utilisateurs, ainsi que la pagination. Cette section est très puissante et permet de générer des listes simplement, une fois qu'on a saisi la logique de son fonctionnement. | Paramètre | Optionnel / obligatoire ? | Fonction | | :- | :- | :- | | `schema` | **requis** si `select` n'est pas fourni | Chemin vers un fichier de schéma JSON qui représenterait le document | | `select` | **requis** si `schema` n'est pas fourni | Liste des colonnes à sélectionner, sous la forme `$$.colonne AS "Colonne"`, chaque colonne étant séparée par un point-virgule. | | `module` | *optionnel* | Nom unique du module lié (par exemple : `recu_don`). Si non spécifié, alors le nom du module courant sera utilisé. | | `columns` | *optionnel* | Permet de n'afficher que certaines colonnes du schéma. Indiquer ici le nom des colonnes, séparées par des virgules. | | `order` | *optionnel* | Colonne utilisée par défaut pour le tri (si l'utilisateur n'a pas choisi le tri sur une autre colonne). Si `select` est utilisé, il faut alors indiquer ici le numéro de la colonne, et non pas son nom. | | `desc` | *optionnel* | Si ce paramètre est à `true`, l'ordre de tri sera inversé. | | `max` | *optionnel* | Nombre d'éléments à afficher dans la liste, sur chaque page. | | `where` | *optionnel* | Condition `WHERE` de la requête SQL. | | `debug` | *optionnel* | Si ce paramètre existe, la requête SQL exécutée sera affichée avant le début de la boucle. | | `explain` | *optionnel* | Si ce paramètre existe, l'explication de la requête SQL exécutée sera affichée avant le début de la boucle. | Pour déterminer quelles colonnes afficher dans le tableau, il faut utiliser soit le paramètre `schema` pour indiquer un fichier de schéma JSON qui sera utilisé pour donner le libellé des colonnes (via la `description` indiquée dans le schéma), soit le paramètre `select`, où il faut alors indiquer le nom et le libellé des colonnes sous la forme `$$.colonne1 AS "Libellé"; $$.colonne2 AS "Libellé 2"`. Comme pour `load`, il est possible d'utiliser des paramètres supplémentaires : `cle="valeur"`. Cela va comparer `"valeur"` avec la valeur de la clé `cle` dans le document JSON. C'est l'équivalent d'écrire `where="json_extract(document, '$.cle') = 'valeur'"`. Pour des conditions plus complexes qu'une simple égalité, il est possible d'utiliser la syntaxe courte `$$…` dans le paramètre `where`. Ainsi `where="$$.nom LIKE 'Bourse%'` est l'équivalent de `where="json_extract(document, '$.nom') LIKE 'Bourse%'"`. Voir [la documentation de SQLite pour plus de détails sur la syntaxe de json_extract](https://www.sqlite.org/json1.html#jex). Note : un index SQL dynamique est créé pour chaque requête utilisant une clause `json_extract`. Chaque itération renverra toujours ces deux variables : | Variable | Valeur | | :- | :- | | `$key` | Clé unique du document | | `$id` | Numéro unique du document | Ainsi que chaque élément du document JSON lui-même. La section ouvre un tableau HTML et le ferme automatiquement, donc le contenu de la section **doit** être une ligne de tableau HTML (`<tr>`). Dans chaque ligne du tableau il faut respecter l'ordre des colonnes indiqué dans `columns` ou `select`. Une dernière colonne est réservée aux boutons d'action : `<td class="actions">...</td>`. ### Exemples Lister le nom, la date et le montant des reçus fiscaux, à partir du schéma JSON suivant : ``` { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "date": { "description": "Date d'émission", "type": "string", "format": "date" }, "adresse": { "description": "Adresse du bénéficiaire", "type": "string" }, "nom": { "description": "Nom du bénéficiaire", "type": "string" }, "montant": { "description": "Montant", "type": "integer", "minimum": 0 } } } ``` Le code de la section sera alors comme suivant : ``` {{#list schema="./recu.schema.json" columns="nom, date, montant"}} <tr> <th>{{$nom}}</th> <td>{{$date|date_short}}</td> <td>{{$montant|raw|money_currency}}</td> <td class="actions"> {{:linkbutton shape="eye" label="Ouvrir" href="./voir.html?id=%d"|args:$id target="_dialog"}} </td> </tr> {{else}} <p class="alert block">Aucun reçu n'a été trouvé.</p> {{/list}} ``` Si le paramètre `columns` avait été omis, la colonne `adresse` aurait également été incluse. Il est à noter que si l'utilisation directe du schéma est bien pratique, cela ne permet pas de récupérer des informations plus complexes dans la structure JSON, par exemple une sous-clé ou l'application d'une fonction SQL. Dans ce cas il faut obligatoirement utiliser `select`. Par exemple ici on veut pouvoir afficher l'année, et trier sur l'année par défaut : ``` {{#list select="$$.nom AS 'Nom du donateur' ; strftime('%Y', $$.date) AS 'Année'" order=2}} <tr> <th>{{$nom}}</th> <td>{{$col2}}</td> <td class="actions"> {{:linkbutton shape="eye" label="Ouvrir" href="./voir.html?id=%d"|args:$id target="_dialog"}} </td> </tr> {{else}} <p class="alert block">Aucun reçu n'a été trouvé.</p> {{/list}} ``` On peut utiliser le nom des clés du document JSON, mais sinon pour faire référence à la valeur d'une colonne spécifique dans la boucle, il faut utiliser son numéro d'ordre (qui commence à `1`, pas zéro). Ici on veut afficher l'année, donc la seconde colonne, donc `$col1`. Noter aussi l'utilisation du numéro de la colonne de l'année (`2`) pour le paramètre `order`, qui avec `select` doit indiquer le numéro de la colonne à utiliser pour l'ordre. |
Modified doc/admin/markdown.md from [3957587aef] to [aba3e0f63e].
︙ | ︙ | |||
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | Il est aussi possible d'utiliser la syntaxe avec des paramètres nommés : ``` <<image file="Nom_fichier.jpg" align="center" caption="Légende">> ``` Les images qui ne sont pas mentionnées dans le texte seront affichées après le texte sous forme de galerie. ## Fichiers joints Pour créer un bouton permettant de voir ou télécharger un fichier joint à la page web, il suffit d'utiliser la syntaxe suivante : ``` <<file|Nom_fichier.ext|Libellé>> ``` * `Nom_fichier.ext` : remplacer par le nom du fichier (parmi les fichiers joints à la page) * `Libellé` : indique le libellé du qui sera affiché sur le bouton, si aucun libellé n'est indiqué alors c'est le nom du fichier qui sera affiché ## Sommaire / table des matières automatique Il est possible de placer le code `<<toc>>` pour générer un sommaire automatiquement à partir des titres et sous-titres : ``` <<toc>> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | Il est aussi possible d'utiliser la syntaxe avec des paramètres nommés : ``` <<image file="Nom_fichier.jpg" align="center" caption="Légende">> ``` Les images qui ne sont pas mentionnées dans le texte seront affichées après le texte sous forme de galerie. ## Galerie d'images Il est possible d'afficher une galerie d'images (sous forme d'images miniatures) avec la balise `<<gallery` qui contient la liste des images à mettre dans la galerie : ``` <<gallery Nom_fichier.jpg Nom_fichier_2.jpg >> ``` Si aucun nom de fichier n'est indiqué, alors toutes les images jointes à la page seront affichées : ``` <<gallery>> ``` ### Diaporama d'images On peut également afficher cette galerie sous forme de diaporama. Dans ce cas une seule image est affichée, et on peut passer de l'une à l'autre. La syntaxe est la même, mais on ajoute le mot `slideshow` après le mot `gallery` : ``` <<gallery slideshow Nom_fichier.jpg Nom_fichier_2.jpg >> ``` ## Fichiers joints Pour créer un bouton permettant de voir ou télécharger un fichier joint à la page web, il suffit d'utiliser la syntaxe suivante : ``` <<file|Nom_fichier.ext|Libellé>> ``` * `Nom_fichier.ext` : remplacer par le nom du fichier (parmi les fichiers joints à la page) * `Libellé` : indique le libellé du qui sera affiché sur le bouton, si aucun libellé n'est indiqué alors c'est le nom du fichier qui sera affiché ## Vidéos Pour inclure un lecteur vidéo dans la page web à partir d'un fichier vidéo joint à la page, il faut utiliser le code suivant : ``` <<video|Nom_du_fichier.ext>> ``` On peut aussi spécifier d'autres paramètres : * `file` : nom du fichier vidéo * `poster` : nom de fichier d'une image utilisée pour remplacer la vidéo avant qu'elle ne soit lue * `subtitles` : nom d'un fichier de sous-titres au format VTT (le format SRT n'est pas géré par les navigateurs) * `width` : largeur de la vidéo (en pixels) * `height` : hauteur de la vidéo (en pixels) Exemple : ``` <<video file="Ma_video.webm" poster="Ma_video_poster.jpg" width="640" height="360" subtitles="Ma_video_sous_titres.vtt">> ``` ## Sommaire / table des matières automatique Il est possible de placer le code `<<toc>>` pour générer un sommaire automatiquement à partir des titres et sous-titres : ``` <<toc>> |
︙ | ︙ |
Added doc/admin/modules.md version [c7da91affa].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | Title: Développer des modules pour Paheko {{{.nav * **[Modules](modules.html)** * [Documentation Brindille](brindille.html) * [Fonctions](brindille_functions.html) * [Sections](brindille_sections.html) * [Filtres](brindille_modifiers.html) }}} <<toc aside>> # Introduction Depuis la version 1.3, Paheko dispose d'extensions modifiables, nommées **Modules**. Les modules permettent de créer et modifier des formulaires, des modèles de documents simples, à imprimer, mais aussi de créer des "mini-applications" directement dans l'administration de l'association, avec le minimum de code, sans avoir à apprendre à programmer PHP. Les modules utilisent le langage [Brindille](brindille.html), aussi utilisé pour le site web (qui est lui-même un module). Avec Brindille on parle d'un **squelette** pour un fichier texte contenant du code Brindille. Les modules ne permettent pas d'exécuter du code PHP, ni de modifier la base de données en dehors des données du module, contrairement aux [plugins](https://fossil.kd2.org/paheko/wiki?name=Documentation/Plugin&p). Grâce à Brindille, les administrateurs de l'association peuvent modifier ou créer de nouveaux modules sans risques pour le serveur, car le code Brindille ne permet pas d'exécuter de fonctions dangereuses. Les **plugins** eux sont écrits en PHP et ne peuvent pas être modifiés par une association. Du fait des risques de sécurité, seuls les plugins officiels sont proposés sur Paheko.cloud. # Exemples Paheko fournit quelques modules par défaut, qui peuvent être modifiés ou servir d'inspiration pour de nouveaux modules : * Reçu de don simple * Reçu de paiement simple * Reçu fiscal * Cartes de membres * Heures d'ouverture * Modèles d'écritures comptables Ces exemples sont développés directement avec Brindille et peuvent être modifiés ou lus depuis le menu **Configuration**, onglet **Extensions**. Un module fourni dans Paheko peut être modifié, et en cas de problème il peut être remis à son état d'origine. D'autres exemples d'utilisation sont imaginables : * Auto-remplissage de la déclaration de la liste des dirigeants à la préfecture * Compte de résultat et bilan conforme au modèle du plan comptable * Formulaires partagés entre la partie privée, et le site web (voir par exemple le module "heures d'ouverture") * Gestion de matériel prêté par l'association # Pré-requis Une connaissance de la programmation informatique est souhaitable pour commencer à modifier ou créer des modules, mais cela n'est pas requis, il est possible d'apprendre progressivement. # Résumé technique * Utilisation de la syntaxe Brindille * Les modules peuvent utiliser toutes les fonctions et boucles de Brindille * Les modules peuvent stocker et récupérer des données dans la base SQLite dans une table clé-valeur spécifique à chaque module * Les données du module sont stockées en JSON, on peut faire des requêtes complètes avec l'extension [JSON de SQLite](https://www.sqlite.org/json1.html) * Les données peuvent être validées avant enregistrement en utilisant [JSON Schema](https://json-schema.org/understanding-json-schema/) * Un module peut également accéder aux données des autres modules * Un module peut aussi accéder à toutes les données de la base de données, sauf certaines données à risque (voir plus bas) * Un module ne peut pas modifier les données de la base de données * Paheko crée automatiquement des index sur les requêtes SQL des modules, permettant de rendre les requêtes rapides # Structure des répertoires Chaque module a un nom unique (composé uniquement de lettres minuscules, de tirets bas et de chiffres) et dispose d'un sous-répertoire dans le dossier `modules`. Ainsi le module `recu_don` serait dans le répertoire `modules/recu_don`. Dans ce répertoire le module peut avoir autant de fichiers qu'il veut, mais certains fichiers ont une fonction spéciale : * `module.ini` : contient les informations sur le module, voir ci-dessous pour les détails * `config.html` : si ce squelette existe, un bouton "Configurer" apparaîtra dans la liste des modules (Configuration -> Modules) et affichera ce squelette dans un dialogue * `icon.svg` : icône du module, qui sera utilisée sur la page d'accueil, si le bouton est activé, et dans la liste des modules. Attention l'élément racine du fichier doit porter l'id `img` pour que l'icône fonctionne (`<svg id="img"...>`), notamment pour que les couleurs du thème s'appliquent à l'icône. * `README.md` : si ce fichier existe, son contenu sera affiché dans les détails du module Les modules peuvent également avoir des `snippets`, ce sont des squelettes qui seront inclus à des endroits précis de l'interface, permettant de rajouter des fonctionnalités, ils sont situés dans le sous-répertoire `snippets` du module : * `snippets/transaction_details.html` : sera inclus en dessous de la fiche d'une écriture comptable * `snippets/user_details.html` : sera inclus en dessous de la fiche d'un membre * `snippets/home_button.html` : sera inclus dans la liste des boutons de la page d'accueil (ce fichier ne sera pas appelé si `home_button` est à `true` dans `module.ini`, il le remplace) ## Fichier module.ini Ce fichier décrit le module, au format INI (`clé=valeur`), en utilisant les clés suivantes : * `name` (obligatoire) : nom du module * `description` : courte description de la fonctionnalité apportée par le module * `author` : nom de l'auteur * `author_url` : adresse web HTTP menant au site de l'auteur * `home_button` : indique si un bouton pour ce module doit être affiché sur la page d'accueil (`true` ou `false`) * `menu` : indique si ce module doit être listé dans le menu de gauche (`true` ou `false`) * `restrict_section` : indique la section auquel le membre doit avoir accès pour pouvoir voir le menu de ce module, parmi `web, documents, users, accounting, connect, config` * `restrict_level` : indique le niveau d'accès que le membre doit avoir dans la section indiquée pour pouvoir voir le menu de ce module, parmi `read, write, admin`. Attention : les directives `restrict_section` et `restrict_level` ne contrôlent *que* l'affichage du lien vers le module dans le menu et dans les boutons de la page d'accueil, mais pas l'accès aux pages du module. # Variables spéciales Toutes les pages d'un module disposent de la variable `$module` qui contient l'entité du module en cours : * `$module.name` contient le nom unique (`recu_don` par exemple) * `$module.label` le libellé du module * `$module.description` la description * `$module.config` la configuration du module * `$module.url` l'adresse URL du module (`https://site-association.tld/m/recu_don/` par exemple) # Stockage de données Un module peut stocker des données de deux manières : dans sa configuration, ou dans son stockage de documents JSON. ## Configuration La première manière est de stocker des informations dans la configuration du module. Pour cela on utilise la fonction `save` et la clé `config` : ``` {{:save key="config" accounts_list="512A,512B" check_boxes=true}} ``` On pourra retrouver ces valeurs dans la variable `$module.config` : ``` {{if $module.config.check_boxes}} {{$module.config.accounts_list}} {{/if}} ``` ## Stockage de documents JSON Chaque module peut stocker ses données dans une base de données clé-document qui stockera les données dans des documents au format JSON dans une table SQLite. Grâce aux [fonctions JSON de SQLite](https://www.sqlite.org/json1.html) on pourra ensuite effectuer des recherches sur ces documents. Pour enregistrer il suffit d'utiliser la fonction `save` : ``` {{:save key="facture001" type="facture" date="2022-01-01" label="Vente de petits pains au chocolat" total="42"}} ``` Si la clé indiquée (dans le paramètre `key`) n'existe pas, l'enregistrement sera créé, sinon il sera mis à jour avec les valeurs données. ### Validation On peut utiliser un [schéma JSON](https://json-schema.org/understanding-json-schema/) pour valider que le document qu'on enregistre est valide : ``` {{:save validate_schema="./document.schema.json" type="facture" date="2022-01-01" label="Vente de petits pains au chocolat" total="42"}} ``` Le fichier `document.schema.json` devra être dans le même répertoire que le squelette et devra contenir un schéma valide. Voici un exemple : ``` { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "date": { "description": "Date d'émission", "type": "string", "format": "date" }, "type": { "description": "Type de document", "type": "string", "enum": ["devis", "facture"] }, "total": { "description": "Montant total", "type": "integer", "minimum": 0 }, "label": { "description": "Libellé", "type": "string" }, "description": { "description": "Description", "type": ["string", "null"] } }, "required": [ "type", "date", "total", "label"] } ``` Si le document fourni n'est pas conforme au schéma, il ne sera pas enregistré et une erreur sera affichée. #### Propriété non requise Si vous souhaitez utiliser dans votre document une propriété non requise, il ne faut pas la fournir en paramètre de la fonction `save`. Si elle est fournie mais vide, il faut aussi autoriser le type `null` (en minuscules) au type de votre propriété. Exemple : [...] "description": { "description": "Description", "type": ["string", "null"] } [...] ### Stockage JSON dans SQLite (pour information) Explication du fonctionnement technique derrière la fonction `save`. En pratique chaque enregistrement sera placé dans une table SQL dont le nom commence par `module_data_`. Ici la table sera donc nommée `module_data_factures` si le nom unique du module est `factures`. Le schéma de cette table est le suivant : ``` CREATE TABLE module_data_factures ( id INTEGER PRIMARY KEY NOT NULL, key TEXT NULL, document TEXT NOT NULL ); CREATE UNIQUE INDEX module_data_factures_key ON module_data_factures (key); ``` Comme on peut le voir, chaque ligne dans la table peut avoir une clé unique (`key`), et un ID ou juste un ID auto-incrémenté. La clé unique n'est pas obligatoire, mais peut être utile pour différencier certains documents. Par exemple le code suivant : ``` {{:save key="facture_43" nom="Facture de courses"}} ``` Est l'équivalent de la requête SQL suivante : ``` INSERT OR REPLACE INTO module_data_factures (key, document) VALUES ('facture_43', '{"nom": "Facture de courses"}'); ``` ### Récupération et liste de documents Il sera ensuite possible d'utiliser la boucle `load` pour récupérer les données : ``` {{#load id=42}} Ce document est de type {{$type}} créé le {{$date}}. <h2>{{$label}}</h2> À payer : {{$total}} € {{else}} Le document numéro 42 n'a pas été trouvé. {{/load}} ``` Cette boucle `load` permet aussi de faire des recherches sur les valeurs du document : ``` <ul> {{#load where="$$.type = 'facture'" order="date DESC"}} <li>{{$label}} ({{$total}} €)</li> {{/load}} </ul> ``` La syntaxe `$$.type` indique d'aller extraire la clé `type` du document JSON. C'est un raccourci pour la syntaxe SQLite `json_extract(document, '$.type')`. # Export et import de modules Il est possible d'exporter un module modifié. Cela créera un fichier ZIP contenant à la fois le code modifié et le code non modifié. De la même manière il est possible d'importer un module à partir d'un fichier ZIP d'export. Si vous créez votre fichier ZIP manuellement, attention à respecter le fait que le code du module doit se situer dans le répertoire `modules/nom_du_module` du fichier ZIP. Tout fichier ou répertoire situé en dehors de cette arborescence provoquera une erreur et l'impossibilité d'importer le module. # Restrictions * Il n'est pas possible de télécharger ou envoyer des données depuis un autre serveur * Il n'est pas possible d'écrire un fichier local ## Envoi d'e-mail Voir [la documentation de la fonction `{{:mail}}`](brindille_functions.html#mail) ## Tables et colonnes de la base de données Pour des raisons de sécurité, les modules ne peuvent pas accéder à toutes les données de la base de données. Les colonnes suivantes de la table `users` (liste des membres) renverront toujours `NULL` : * `password` * `pgp_key` * `otp_secret` Tenter de lire les données des tables suivantes résultera également en une erreur : * emails * emails_queue * compromised_passwords_cache * compromised_passwords_cache_ranges * api_credentials * plugins_signals * config * users_sessions * logs |
Modified doc/admin/skriv.md from [2506065a25] to [840d985008].
1 2 3 4 5 6 | Title: Référence rapide SkrivML - Paheko <<toc aside>> # Syntaxe SkrivML | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Title: Référence rapide SkrivML - Paheko <<toc aside>> # Syntaxe SkrivML Paheko propose la syntaxe [SkrivML](https://fossil.kd2.org/paheko/doc/trunk/doc/skrivml.html) pour le formatage du texte des pages du site web. ## Styles de texte | Style | Syntaxe | | :- | :- | | *Italique* | `Entourer le texte de ''deux apostrophes''` | | **Gras** | `Entourer le texte de **deux astérisques**` | |
︙ | ︙ |
Modified doc/admin/web.md from [425b2a29b8] to [9859ee4f6c].
1 2 3 4 5 6 7 8 9 10 11 | Title: Squelettes du site web dans Paheko {{{.nav * [Documentation Brindille](brindille.html) * [Fonctions](brindille_functions.html) * [Sections](brindille_sections.html) * [Filtres](brindille_modifiers.html) }}} # Les squelettes du site web | | | | < | < < < < < < | | | > | | | < > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | Title: Squelettes du site web dans Paheko {{{.nav * [Documentation Brindille](brindille.html) * [Fonctions](brindille_functions.html) * [Sections](brindille_sections.html) * [Filtres](brindille_modifiers.html) }}} # Les squelettes du site web Les squelettes sont un ensemble de fichiers qui permettent de modéliser l'apparence du site web selon ses préférences et besoins. La syntaxe utilisée dans les squelettes s'appelle **[Brindille](brindille.html)**. Voir la [documentation de Brindille](brindille.html) pour son fonctionnement. # Exemples de sites réalisés avec Paheko * [Faidherbe Alumni](https://www.alumni-faidherbe.fr/) * [ASBM Mortagne](https://asbm-mortagne.fr/) * [Vélocité 63](https://www.velocite63.fr/) * [La rustine, Dijon](https://larustine.org/) * [Tauto école](https://tauto-ecole.net/) [(les squelettes sont disponibles ici)](https://gitlab.com/noizette/squelettes-garradin-tauto-ecole/) * [La boîte à vélos](https://boiteavelos.chenove.net/) # Fonctionnement des squelettes Par défaut sont fournis plusieurs squelettes qui permettent d'avoir un site web basique mais fonctionnel : page d'accueil, menu avec les catégories de premier niveau, et pour afficher les pages, les catégories, les fichiers joints et images. Il y a également un squelette `atom.xml` permettant aux visiteurs d'accéder aux dernières pages publiées. Les squelettes peuvent être modifiés via l'onglet **Configuration** de la section **Site web** du menu principal. Une fois un squelette modifié, il apparaît dans la liste comme étant modifié, sinon il apparaît comme *défaut*. Si vous avez commis une erreur, il est possible de restaurer le squelette d'origine. ## Adresses des pages du site Les squelettes sont appelés en fonction des règles suivantes (dans l'ordre) : | Squelette appelé | Cas où le squelette est appelé | | :---- | :---- | | `adresse` | Si l'adresse `adresse` est appelée, et qu'un squelette du même nom existe | | `adresse/index.html` | Si l'adresse `adresse/` est appelée, et qu'un squelette `index.html` dans le répertoire du même nom existe | | `category.html` | Toute autre adresse se terminant par un slash `/`, si une catégorie du même nom existe | | `article.html` | Toute autre adresse, si une page du même nom existe | | `404.html` | Si aucune règle précédente n'a fonctionné | Ainsi l'adresse `https://monsite.paheko.cloud/Actualite/` appellera le squelette `category.html`, mais l'adresse `https://monsite.paheko.cloud/Actualite` (sans slash à la fin) appellera le squelette `article.html` si un article avec l'URI `Actualite` existe. Si un squelette `Actualite` (sans extension) existe, c'est lui qui sera appelé en priorité et ni `category.html` ni `article.html` ne seront appelés. Autre exemple : `https://monsite.paheko.cloud/atom.xml` appellera le squelette `atom.xml` s'il existe. Ceci vous permet de créer de nouvelles pages dynamiques sur le site, par exemple pour notre atelier vélo nous avons une page `https://larustine.org/velos` qui appelle le squelette `velos` (sans extension), qui va afficher la liste des vélos actuellement en stock dans notre hangar. Le type de fichier étant déterminé selon l'extension (`.html, .css, etc.`) pour les fichiers traités par Brindille, un fichier sans extension sera considéré comme un fichier texte par le navigateur. Si on veut que le squelette `velos` (sans extension) s'affiche comme du HTML il faut forcer le type en mettant le code `{{:http type="text/html"}}` au début du squelette (première ligne). ## Fichier content.css Ce fichier est particulier, car il définit le style du contenu des pages et des catégories. Ainsi il est également utilisé quand vous éditez un contenu dans l'administration. Donc si vous souhaitez modifier le style d'un élément du texte, il vaux mieux modifier ce fichier, sinon le rendu sera différent entre l'administration et le site public. # Cache Depuis la version 1.3, Paheko dispose d'un cache statique du site web. Cela veut dire que les pages du site web sont enregistrées sous la forme de fichiers HTML statiques, et le serveur web renvoie directement ce fichier sans faire appel à Paheko et son code PHP. Les fichiers liés aux pages web sont également mis en cache de cette manière, en utilisant des liens symboliques. Ce cache permet d'avoir un site web très rapide, même s'il reçoit des millions de visites. ## Désactiver le cache Le seul inconvénient c'est qu'une page mise en cache étant statique, si vous utilisez du contenu dynamique (par exemple afficher un texte différent selon la langue du visiteur) dans le squelette Brindille, alors cela ne fonctionnera plus. Dans ce cas-là, vous pouvez assigner la variable `nocache` dans le squelette pour désactiver le cache pour cette page : ``` {{:assign nocache=true}} ``` Pour permettre des usages du type "affichage en temps presque réel des horaires d'ouverture", le cache d'une page HTML est effacé et remis à jour au bout d'une heure. ## Exceptions Il est à noter que le cache n'est pas appelé dans les cas suivants : * si la requête vers la page est d'un autre type que `GET` ou `HEAD`, ainsi par exemple l'envoi d'un formulaire (`POST`) ne sera jamais mis en cache ; * si la requête vers la page contient des paramètres dans l'adresse (par exemple `velos.html?list=1` : cette page ne sera pas mise en cache) ; * si le visiteur est connecté à l'administration de l'association. Ainsi si vous avez des parties du squelette qui varient en fonction de si la personne est connectée, le cache ne posera pas de problème. Le cache est intégralement effacé à chaque modification du site web. Le cache ne concerne que les pages et fichiers du site web public. Il ne concerne pas les modules, les extensions, ou l'administration. Attention : * avec un serveur sous Windows, le cache est désactivé car Windows ne sait pas gérer les liens symboliques ; * seul Apache sait gérer le cache statique, le cache est désactivé avec les autres serveurs web (nginx, etc.). |
Modified src/.htaccess.www from [3ae6d113cf] to [1fa848cf6a].
︙ | ︙ | |||
20 21 22 23 24 25 26 | # Objectif: supprimer le /www/ de l'URL # Note: il est probable qu'il soit nécessaire d'adapter la configuration # à votre hébergeur ! <IfModule mod_rewrite.c> RewriteEngine on ## Remplacer dans les lignes suivantes | | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # Objectif: supprimer le /www/ de l'URL # Note: il est probable qu'il soit nécessaire d'adapter la configuration # à votre hébergeur ! <IfModule mod_rewrite.c> RewriteEngine on ## Remplacer dans les lignes suivantes ## /paheko/ par le nom du sous-répertoire où est installé Paheko RewriteBase /paheko/ FallbackResource /paheko/www/_route.php ## Ne pas modifier les lignes suivantes, les décommenter simplement ! RewriteCond %{REQUEST_URI} !www/ RewriteRule ^(.*)$ www/$1 [QSA,L] </IfModule> |
Modified src/Makefile from [d1651bfce0] to [e7ebe9535b].
|
| | > > > > > > | | > > > > > > > > > > > > | | > > > > > | > > > > | | | | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | .PHONY: dev-server release deps publish check-dependencies test minify phpstan www htaccess modules KD2_FILE := https://fossil.kd2.org/kd2fw/uv/KD2-7.4.zip MODULES_FILE := https://fossil.kd2.org/paheko-modules/zip/trunk/modules.zip deps: $(eval TMP_KD2=$(shell mktemp -d)) #cd ${TMP_KD2} wget ${KD2_FILE} -O ${TMP_KD2}/kd2.zip rm -rf "include/lib/KD2" unzip "${TMP_KD2}/kd2.zip" -d include/lib rm -rf ${TMP_KD2} modules: wget ${MODULES_FILE} -O modules.zip unzip -u modules.zip rm -f modules.zip dev-server: php -S localhost:8082 -d upload_max_filesize=256M -d post_max_size=256M -t www www/_route.php test: find . -name '*.php' -not -path './data/*' -print0 | xargs -0 -n1 php -l > /dev/null phpstan: phpstan.phar analyze -c ../tests/phpstan.neon include www psalm: @# This is required by psalm, but useless @-mkdir vendor @-echo '{"require": {}}' > vendor/autoload.php psalm.phar -c ../tests/psalm.xml doc: php ../tools/doc_md_to_html.php htaccess: # Removing DOCUMENT_ROOT is important for the cache when using .htaccess, keep it! cat apache-vhost.conf \ | sed 's/#RewriteBase/RewriteBase/' \ | sed 's/RewriteCond %{DOCUMENT_ROOT}%{REQUEST_/RewriteCond %{REQUEST_/' \ > www/.htaccess cat apache-htaccess.conf >> www/.htaccess release: test minify doc $(eval VERSION=$(shell cat VERSION)) rm -rf /tmp/paheko-build mkdir -p /tmp/paheko-build fossil zip ${VERSION} /tmp/paheko-build/src.zip --name paheko unzip -d /tmp/paheko-build /tmp/paheko-build/src.zip cd include/lib; \ rsync --files-from=dependencies.list -r ./ /tmp/paheko-build/paheko/src/include/lib/ mv www/admin/static/mini.css /tmp/paheko-build/paheko/src/www/admin/static/admin.css # Generate .htaccess file cd /tmp/paheko-build/paheko/src && make htaccess cd /tmp/paheko-build/paheko/src/www/admin/static; \ rm -f font/*.css font/*.json cd /tmp/paheko-build/paheko/src; \ rm -f Makefile include/lib/KD2/data/countries.en.json # Download modules and only keep the stable ones cd /tmp/paheko-build/paheko/src && \ wget https://fossil.kd2.org/paheko-modules/zip/trunk/modules.zip && \ unzip -o modules.zip && \ rm -rf `find modules/ -name 'ignore' -type f -execdir pwd \;` && \ rm -f modules.zip # Download plugins and only keep the stable ones cd /tmp/paheko-build/paheko/src/data && \ wget https://fossil.kd2.org/paheko-plugins/zip/dev/plugins.zip && \ unzip -o plugins.zip && \ rm -rf `find plugins/ -name 'ignore' -type f -execdir pwd \;` && \ rm -f plugins.zip mv /tmp/paheko-build/paheko/src /tmp/paheko-build/paheko-${VERSION} tar czvfh ../build/paheko-${VERSION}.tar.gz --hard-dereference -C /tmp/paheko-build paheko-${VERSION} deb: cd ../build/debian; ./makedeb.sh windows: cd ../build/windows; make installer publish: release deb windows $(eval VERSION=$(shell cat VERSION)) cd ../build && gpg --armor -u dev@paheko.cloud --detach-sign paheko-${VERSION}.tar.gz fossil uv sync #fossil uv ls | fgrep -v 'paheko-0.8.5' | grep '^paheko-.*\.(tar\.bz2|deb)' | xargs fossil uv rm cd ../build && \ fossil uv add paheko-${VERSION}.tar.gz && \ fossil uv add paheko-${VERSION}.tar.gz.asc cd ../build/debian && fossil uv add paheko-${VERSION}.deb cd ../tools && php make_installer.php > install.php && fossil uv add install.php && rm install.php fossil uv sync cd ../build/windows && make publish check-dependencies: grep -hEo '^use \\?KD2\\[^; ]+|\\KD2\\[^\(:; ]+' -R include/lib/Garradin www | sed -r 's/^use \\?KD2\\|^\\KD2\\//' | sort | uniq minify: cat `ls www/admin/static/styles/[0-9]*.css` | sed 's/\.\.\///' > www/admin/static/mini.css @# Minify is only gaining 500 gzipped bytes (4kB uncompressed) but making things hard to read/hack @#yui-compressor --nomunge www/admin/static/mini.css -o www/admin/static/mini.css |
Modified src/VERSION from [3b231fab53] to [a312fdaa17].
|
| | | 1 | 1.3.0-rc14 |
Added src/apache-htaccess.conf version [de974946e4].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Sinon le reste marchera, sauf les clients OC/NC <IfModule !mod_rewrite.c> # FallbackResource has a bug before Apache 2.4.15, requiring to disable DirectoryIndex # see https://bz.apache.org/bugzilla/show_bug.cgi?id=58292 # and https://serverfault.com/questions/559067/apache-hangs-for-five-seconds-with-fallbackresource-when-accessing DirectoryIndex disabled DirectoryIndex index.php # Redirect non-existing URLs to the router FallbackResource /_route.php # FallbackResource does not work for URLs ending with ".php" # see https://stackoverflow.com/a/66136226 ErrorDocument 404 /_route.php # NextCloud/ownCloud clients cannot work without mod_rewrite <IfModule mod_alias.c> Redirect 501 /remote.php Redirect 501 /status.php </IfModule> </IfModule> |
Added src/apache-vhost.conf version [04ec124c9b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | Options -Indexes -Multiviews +FollowSymlinks DirectoryIndex index.php index.html # Some security <IfModule mod_alias.c> RedirectMatch 404 _inc\.php </IfModule> # Recommended, if you have xsendfile module # see https://tn123.org/mod_xsendfile/ # Also enable X-SendFile in config.local.php # #<IfModule mod_xsendfile.c> # <Files *.php> # XSendFile On # XSendFilePath /home/paheko/ # </Files> #</IfModule> # This is to avoid caching mismatch when using mod_deflate # see https://github.com/symfony/symfony-docs/issues/12644 <IfModule mod_deflate.c> FileETag None </IfModule> # Allow uploads up to 256 MB where it's required <If "%{REQUEST_URI} =~ m!^/admin/(?:common/files|config/backup)/|^/(?:web)?dav/|^/remote\.php/(?:web)?dav/! && -n %{HTTP_COOKIE}"> <IfModule mod_php.c> php_value post_max_size 256M php_value upload_max_filesize 256M </IfModule> <IfModule mod_php7.c> php_value post_max_size 256M php_value upload_max_filesize 256M </IfModule> <IfModule !mod_php.c> <IfModule !mod_php7.c> SetEnv PHP_VALUE "post_max_size=256M" # There is no way to pass multiple PHP ini settings via PHP_VALUE :-( # so we use PHP_ADMIN_VALUE here. It works unless we have more than 2 settings to change. SetEnv PHP_ADMIN_VALUE "upload_max_filesize=256M" </IfModule> </IfModule> </If> <IfModule mod_rewrite.c> AddDefaultCharset utf-8 AddCharset utf-8 .html .css .js .txt RewriteEngine On #RewriteBase / RewriteRule \.cache - [R=404] RewriteRule \.well-known/assetlinks.json - [R=404] # Stop rewrite for /admin URL, except for /admin/p/ (plugins) RewriteCond %{REQUEST_URI} ^/?admin(?!/p/) RewriteRule ^ - [END] # Skip directly to router if possible # Do not try cache if method is not GET or HEAD RewriteCond %{REQUEST_METHOD} !GET|HEAD [OR] # Do not try to get from cache if URL is private, or belongs to modules/plugins RewriteCond %{REQUEST_URI} ^/admin|^/?(?:dav|wopi|p|m|api)/|\.php$ [OR] # NextCloud routes RewriteCond %{REQUEST_URI} ^/?(?:remote\.php|index\.php|ocs|avatars|status\.php)/ [OR] # Private files are not part of the cache RewriteCond %{REQUEST_URI} ^/?(?:documents|user|transaction|ext|attachments|versions)/ # Skip, go to router directly RewriteRule ^ - [skip=8] # Store MD5 hashes in environment variables RewriteCond %{REQUEST_URI} ^(.+)(?:\?|$) RewriteRule ^ "-" [E=CACHE_URI:%1] # Extract file extension (required for Apache to serve the correct mimetype) RewriteCond %{REQUEST_URI} (\.[a-z0-9]+)(?:\?|$) RewriteRule ^ "-" [E=CACHE_EXT:%1] # If no extension, default to .html RewriteCond %{REQUEST_URI} !\.[a-z0-9]+(?:\?|$) RewriteRule ^ "-" [E=CACHE_EXT:.html] RewriteCond expr "md5(%{ENV:CACHE_URI}) =~ /^(.+)$/" RewriteRule ^ "-" [E=CACHE_URI_MD5:%1] RewriteCond expr "md5(tolower(%{HTTP_HOST})) =~ /^((.{2}).+)$/" RewriteRule ^ "-" [E=CACHE_HOST_MD5:%1,E=CACHE_HOST2_MD5:%2] RewriteCond /.cache/%{ENV:CACHE_HOST_MD5}/%{ENV:CACHE_URI_MD5} (.+) RewriteRule ^ "-" [E=CACHE_PATH:%1] # Serve symlinks for files RewriteCond %{QUERY_STRING} ="" [OR] RewriteCond %{QUERY_STRING} ^h=[a-f0-9]+$ RewriteCond %{DOCUMENT_ROOT}%{ENV:CACHE_PATH}%{ENV:CACHE_EXT} -l RewriteRule ^ %{ENV:CACHE_PATH}%{ENV:CACHE_EXT} [END] # Do not try cache for pages if user is logged-in RewriteCond %{HTTP_COOKIE} !pko= # Serve static HTML pages RewriteCond %{QUERY_STRING} ="" RewriteCond %{DOCUMENT_ROOT}%{ENV:CACHE_PATH}%{ENV:CACHE_EXT} -f RewriteCond %{DOCUMENT_ROOT}%{ENV:CACHE_PATH}%{ENV:CACHE_EXT} !-l RewriteRule ^ %{ENV:CACHE_PATH}%{ENV:CACHE_EXT} [END] # Redirect to router RewriteRule ^ /_route.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},END,QSA] </IfModule> |
Modified src/config.dist.php from [fee27d0d97] to [9f1cf88fe4].
1 2 3 4 | <?php /** * Ce fichier représente un exemple des constantes de configuration | | | | | | > > > > | > > | < | | > > > > > > > > > > > | | < < < < < < < < < < < < < < | | | | > > > > > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | <?php /** * Ce fichier représente un exemple des constantes de configuration * disponibles pour Paheko. * * NE PAS MODIFIER CE FICHIER! * * Pour configurer Paheko, copiez ce fichier en 'config.local.php' * puis décommentez et modifiez ce dont vous avez besoin. */ // Nécessaire pour situer les constantes dans le bon namespace namespace Paheko; /** * Clé secrète, doit être unique à chaque instance de Paheko * * Ceci est utilisé afin de sécuriser l'envoi de formulaires * (protection anti-CSRF). * * Cette valeur peut être modifiée sans autre impact que la déconnexion des utilisateurs * actuellement connectés. * * Si cette constante n'est définie, Paheko ajoutera automatiquement * une valeur aléatoire dans le fichier config.local.php. */ //const SECRET_KEY = '3xUhIgGwuovRKOjVsVPQ5yUMfXUSIOX2GKzcebsz5OINrYC50r'; /** * @var null|int|array * * Forcer la connexion locale * * Si un numéro est spécifié, alors le membre avec l'ID correspondant à ce * numéro sera connecté (sans besoin de mot de passe). * * Exemple: LOCAL_LOGIN = 42 connectera automatiquement le membre avec id = 42 * Attention à ne pas utiliser en production ! * * Si le nombre spécifié est -1, alors c'est le premier membre trouvé qui * peut gérer la configuration (et donc modifier les droits des membres) * qui sera connecté. * * Si un tableau est spécifié, alors Paheko considérera que l'utilisateur * connecté fourni dans le tableau n'est pas un membre. * Voir la documentation sur l'utilisation avec SSO et LDAP pour plus de détails. * * Exemple : * const LOCAL_LOGIN = [ * 'user' => ['_name' => 'bohwaz'], * 'permissions' => ['users' => 9, 'config' => 9] * ]; * * Défault : null (connexion automatique désactivée) */ //const LOCAL_LOGIN = null; /** * Autoriser (ou non) l'import de sauvegarde qui a été modifiée ? * * Si mis à true, un avertissement et une confirmation seront demandés * Si mis à false, tout fichier SQLite importé qui ne comporte pas une signature * valide (hash SHA1) sera refusé. * * Ceci ne s'applique qu'à la page "Sauvegarde et restauration" de l'admin, * il est toujours possible de restaurer une base de données non signée en * la recopiant à la place du fichier association.sqlite * * Défaut : true */ //const ALLOW_MODIFIED_IMPORT = true; /** * Répertoire où se situe le code source de Paheko * * Défaut : répertoire racine de Paheko (__DIR__) */ //const ROOT = __DIR__; /** * Répertoire où sont situées les données de Paheko * (incluant la base de données SQLite, les sauvegardes, le cache, les fichiers locaux et les plugins) * * Défaut : sous-répertoire "data" de la racine */ //const DATA_ROOT = ROOT . '/data'; /** * Répertoire où est situé le cache, * exemples : graphiques de statistiques, templates Brindille, etc. * * Défaut : sous-répertoire 'cache' de DATA_ROOT */ //const CACHE_ROOT = DATA_ROOT . '/cache'; /** * Répertoire où est situé le cache partagé entre instances * Paheko utilisera ce répertoire pour stocker le cache susceptible d'être partagé entre instances, comme * le code PHP généré à partir des templates Smartyer. * * Défaut : sous-répertoire 'shared' de CACHE_ROOT */ //const SHARED_CACHE_ROOT = CACHE_ROOT . '/shared'; /** * Motif qui détermine l'emplacement des fichiers de cache du site web. * * Le site web peut créer des fichiers de cache pour les pages et catégories. * Ensuite le serveur web (Apache) servira ces fichiers directement, sans faire * appel au PHP, permettant de supporter beaucoup de trafic si le site web * a une vague de popularité. * * Certaines valeurs sont remplacées : * %host% = hash MD5 du hostname (utile en cas d'hébergement de plusieurs instances) * %host.2% = 2 premiers caractères du hash MD5 du hostname * * Utiliser NULL pour désactiver le cache. * * Défault : CACHE_ROOT . '/web/%host%' * * @var null|string */ //const WEB_CACHE_ROOT = CACHE_ROOT . '/web/%host%'; /** * Emplacement du fichier de base de données de Paheko * * Défaut : DATA_ROOT . '/association.sqlite' */ //const DB_FILE = DATA_ROOT . '/association.sqlite'; /** |
︙ | ︙ | |||
135 136 137 138 139 140 141 | * La clé est le nom du signal, et la valeur est la fonction. * * Défaut: [] (tableau vide) */ //const SYSTEM_SIGNALS = [['files.delete' => 'MyNamespace\Signals::deleteFile'], ['entity.Accounting\Transaction.save.before' => 'MyNamespace\Signals::saveTransaction']]; /** | | | | > | | > > > | | | | | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | * La clé est le nom du signal, et la valeur est la fonction. * * Défaut: [] (tableau vide) */ //const SYSTEM_SIGNALS = [['files.delete' => 'MyNamespace\Signals::deleteFile'], ['entity.Accounting\Transaction.save.before' => 'MyNamespace\Signals::saveTransaction']]; /** * Adresse URI de la racine du site Paheko * (doit se terminer par un slash) * * Défaut : découverte automatique à partir de SCRIPT_NAME */ //const WWW_URI = '/asso/'; /** * Adresse URL HTTP(S) publique de Paheko * * Défaut : découverte automatique à partir de HTTP_HOST ou SERVER_NAME + WWW_URI * @var null|string */ //const WWW_URL = 'http://paheko.chezmoi.tld' . WWW_URI; /** * Adresse URL HTTP(S) de l'admin Paheko * * Note : il est possible d'avoir un autre domaine que WWW_URL. * * Défaut : WWW_URL + 'admin/' * @var null|string */ //const ADMIN_URL = 'https://admin.paheko.chezmoi.tld/'; /** * Affichage des erreurs * Si "true" alors un message expliquant l'erreur et comment rapporter le bug s'affiche * en cas d'erreur. Sinon rien ne sera affiché. * * Défaut : TRUE (pour aider le debug de l'auto-hébergement) * * Il est fortement conseillé de mettre cette valeur à FALSE en production ! */ //const SHOW_ERRORS = false; /** * Envoi des erreurs par e-mail * * Si renseigné, un email sera envoyé à l'adresse indiquée à chaque fois qu'une erreur * d'exécution sera rencontrée. * Si "false" alors aucun email ne sera envoyé. * Note : les erreurs sont déjà toutes loguées dans error.log à la racine de DATA_ROOT * * Défaut : false */ //const MAIL_ERRORS = false; /** * Envoi des erreurs à une API compatible AirBrake/Errbit/Paheko * * Si renseigné avec une URL HTTP(S) valide, chaque erreur système sera envoyée * automatiquement à cette URL. * * Si laissé à null, aucun rapport ne sera envoyé. * * Paheko accepte aussi les rapports d'erreur venant d'autres instances. * * Pour cela utiliser l'URL https://login:password@paheko.site.tld/api/errors/report * (voir aussi API_USER et API_PASSWORD) * * Les erreurs seront ensuite visibles dans * Configuration -> Fonctions avancées -> Journal d'erreurs * * Défaut : null */ |
︙ | ︙ | |||
269 270 271 272 273 274 275 276 277 278 279 280 281 282 | * Cette option peut significativement ralentir le chargement des pages. * * Défaut : null (= désactivé) * @var string|null */ // const SQL_DEBUG = __DIR__ . '/debug_sql.sqlite'; /** * Mode de journalisation de SQLite * * Paheko recommande le mode 'WAL' de SQLite, qui permet à SQLite * d'être extrêmement rapide. * * Cependant, sur certains hébergeurs utilisant NFS, ce mode peut | > | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | * Cette option peut significativement ralentir le chargement des pages. * * Défaut : null (= désactivé) * @var string|null */ // const SQL_DEBUG = __DIR__ . '/debug_sql.sqlite'; /** /** * Mode de journalisation de SQLite * * Paheko recommande le mode 'WAL' de SQLite, qui permet à SQLite * d'être extrêmement rapide. * * Cependant, sur certains hébergeurs utilisant NFS, ce mode peut |
︙ | ︙ | |||
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | * @see https://stackoverflow.com/questions/52378361/which-nfs-implementation-is-safe-for-sqlite-database-accessed-by-multiple-proces * * Défaut : 'TRUNCATE' * @var string */ //const SQLITE_JOURNAL_MODE = 'TRUNCATE'; /** * Activer la possibilité de faire une mise à jour semi-automatisée * depuis fossil.kd2.org. * * Si mis à TRUE, alors un bouton sera accessible depuis le menu "Configuration" * pour faire une mise à jour en deux clics. * * Il est conseillé de désactiver cette fonctionnalité si vous ne voulez pas * permettre à un utilisateur de casser l'installation ! * * Si cette constante est désactivée, mais que ENABLE_TECH_DETAILS est activé, * la vérification de nouvelle version se fera quand même, mais plutôt que de proposer | > > > > > > > > > > > > > > > > | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | * @see https://stackoverflow.com/questions/52378361/which-nfs-implementation-is-safe-for-sqlite-database-accessed-by-multiple-proces * * Défaut : 'TRUNCATE' * @var string */ //const SQLITE_JOURNAL_MODE = 'TRUNCATE'; /** * Activation du log HTTP (option de développement) * * Si cette constante est renseignée par un fichier texte, *TOUTES* les requêtes HTTP * ainsi que leur contenu y sera enregistré. * * C'est surtout utile pour débuguer les problèmes de WebDAV par exemple. * * ATTENTION : cela signifie que des informations personnelles (mot de passe etc.) * peuvent se retrouver dans le log. Ne pas utiliser à moins de tester en développement. * * Default : null (= désactivé) * @var string|null */ // const HTTP_LOG_FILE = __DIR__ . '/http.log'; /** * Activer la possibilité de faire une mise à jour semi-automatisée * depuis fossil.kd2.org. * * Si mis à TRUE, alors un bouton sera accessible depuis le menu "Configuration" * pour faire une mise à jour en deux clics. * * Il est conseillé de désactiver cette fonctionnalité si vous ne voulez pas * permettre à un utilisateur de casser l'installation ! * * Si cette constante est désactivée, mais que ENABLE_TECH_DETAILS est activé, * la vérification de nouvelle version se fera quand même, mais plutôt que de proposer * la mise à jour, Paheko proposera de se rendre sur le site officiel pour * télécharger la mise à jour. * * Défaut : true * * @var bool */ |
︙ | ︙ | |||
350 351 352 353 354 355 356 | * - Lighttpd * * N'activer que si vous êtes sûr que le module est installé et activé (sinon * les fichiers ne pourront être vus ou téléchargés). * Nginx n'est PAS supporté, car X-Accel-Redirect ne peut gérer que des fichiers * qui sont *dans* le document root du vhost, ce qui n'est pas le cas ici. * | | | | > > > > > > > > > > > > > > > > > | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | * - Lighttpd * * N'activer que si vous êtes sûr que le module est installé et activé (sinon * les fichiers ne pourront être vus ou téléchargés). * Nginx n'est PAS supporté, car X-Accel-Redirect ne peut gérer que des fichiers * qui sont *dans* le document root du vhost, ce qui n'est pas le cas ici. * * Pour activer X-SendFile mettre dans la config du virtualhost de Paheko: * XSendFile On * XSendFilePath /var/www/paheko * * (remplacer le chemin par le répertoire racine de Paheko) * * Détails : https://tn123.org/mod_xsendfile/ * * Défaut : false */ //const ENABLE_XSENDFILE = false; /** * Serveur NTP utilisé pour les connexions avec TOTP * (utilisé seulement si le code OTP fourni est faux) * * Désactiver (false) si vous êtes sûr que votre serveur est toujours à l'heure. * * Défaut : fr.pool.ntp.org */ //const NTP_SERVER = 'fr.pool.ntp.org'; /** * Désactiver l'envoi d'e-mails * * Si positionné à TRUE, l'envoi d'e-mail ne sera pas proposé, et il ne sera * pas non plus possible de récupérer un mot de passe perdu. * Les parties de l'interface relatives à l'envoi d'e-mail seront cachées. * * Ce réglage est utilisé pour la version autonome sous Windows, car Windows * ne permet pas l'envoi d'e-mails. * * Défaut : false * @var bool */ //const DISABLE_EMAIL = false; /** * Hôte du serveur SMTP, mettre à false (défaut) pour utiliser la fonction * mail() de PHP * * Défaut : false */ |
︙ | ︙ | |||
402 403 404 405 406 407 408 | * Login utilisateur pour le server SMTP * * mettre à null pour utiliser un serveur local ou anonyme * * Défaut : null */ | | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | * Login utilisateur pour le server SMTP * * mettre à null pour utiliser un serveur local ou anonyme * * Défaut : null */ //const SMTP_USER = 'paheko@monserveur.com'; /** * Mot de passe pour le serveur SMTP * * mettre à null pour utiliser un serveur local ou anonyme * * Défaut : null |
︙ | ︙ | |||
427 428 429 430 431 432 433 434 435 | * STARTTLS = utilisation de STARTTLS (moyennement sécurisé) * * Défaut : STARTTLS */ //const SMTP_SECURITY = 'STARTTLS'; /** * Adresse e-mail destinée à recevoir les erreurs de mail | > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | * STARTTLS = utilisation de STARTTLS (moyennement sécurisé) * * Défaut : STARTTLS */ //const SMTP_SECURITY = 'STARTTLS'; /** * Nom du serveur utilisé dans le HELO SMTP * * Si NULL, alors le nom renseigné comme SERVER_NAME (premier nom du virtual host Apache) * sera utilisé. * * Defaut : NULL * * @var null|string */ //const SMTP_HELO_HOSTNAME = 'mail.domain.tld'; /** * Adresse e-mail destinée à recevoir les erreurs de mail * (adresses invalides etc.) — Return-Path * * Si laissé NULL, alors l'adresse e-mail de l'association sera utilisée. * En cas d'hébergement de plusieurs associations, il est conseillé * d'utiliser une adresse par association. * * Voir la documentation de configuration sur des exemples de scripts * permettant de traiter les mails reçus à cette adresse. * * Défaut : null */ //const MAIL_RETURN_PATH = 'returns@monserveur.com'; /** * Adresse e-mail expéditrice des messages (Sender) * * Si vous envoyez des mails pour plusieurs associations, il est souhaitable * de forcer l'adresse d'expéditeur des messages pour passer les règles SPF et DKIM. * * Dans ce cas l'adresse de l'association sera indiquée en "Reply-To", et * l'adresse contenue dans MAIL_SENDER sera dans le From. * * Si laissé NULL, c'est l'adresse de l'association indiquée dans la configuration * qui sera utilisée. * * Défaut : null */ //const MAIL_SENDER = 'associations@monserveur.com'; /** * Mot de passe pour l'accès à l'API permettant de gérer les mails d'erreur * (voir MAIL_RETURN_PATH) * * Cette adresse HTTP permet de gérer un bounce email reçu en POST. * C'est utile si votre serveur de mail est capable de faire une requête HTTP * à la réception d'un message. |
︙ | ︙ | |||
527 528 529 530 531 532 533 | */ //const DISABLE_INSTALL_FORM = false; /** * Stockage des fichiers * * Indiquer ici le nom d'une classe de stockage de fichiers | | | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | */ //const DISABLE_INSTALL_FORM = false; /** * Stockage des fichiers * * Indiquer ici le nom d'une classe de stockage de fichiers * (parmis celles disponibles dans lib/Paheko/Files/Backend) * * Indiquer NULL si vous souhaitez stocker les fichier dans la base * de données SQLite (valeur par défaut). * * Classes de stockage possibles : * - SQLite : enregistre dans la base de données (défaut) * - FileSystem : enregistrement des fichiers dans le système de fichier |
︙ | ︙ | |||
576 577 578 579 580 581 582 | * * Défaut : null (dans ce cas c'est le stockage qui détermine la taille disponible, donc généralement l'espace dispo sur le disque dur !) */ //const FILE_STORAGE_QUOTA = 10*1024*1024; // Forcer le quota alloué à 10 Mo, quel que soit le backend de stockage /** | > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | * * Défaut : null (dans ce cas c'est le stockage qui détermine la taille disponible, donc généralement l'espace dispo sur le disque dur !) */ //const FILE_STORAGE_QUOTA = 10*1024*1024; // Forcer le quota alloué à 10 Mo, quel que soit le backend de stockage /** * FILE_VERSIONING_POLICY * Forcer la politique de versionnement des fichiers. * * null: laisser le choix de la politique (dans la configuration) * 'none': ne rien conserver * 'min': conserver 5 versions (1 minute, 1 heure, 1 jour, 1 semaine, 1 mois) * 'avg': conserver 20 versions * 'max': conserver 50 versions * * Note : indiquer 'none' fait qu'aucune nouvelle version ne sera créée, * mais les versions existantes sont conservées. * * Si ce paramètre n'est pas NULL, alors il faudra aussi définir FILE_VERSIONING_MAX_SIZE. * * Défaut : null (laisser le choix dans la configuration) * * @var null|string */ //const FILE_VERSIONING_POLICY = 'min'; /** * FILE_VERSIONING_MAX_SIZE * Forcer la taille maximale des fichiers à versionner (en Mio) * * N'a aucun effet si le versionnement de fichiers est désactivé. * * Défaut : null (laisser le choix de la taille dans la configuration) * * @var int|null */ //const FILE_VERSIONING_MAX_SIZE = 10; /** * Adresse de découverte d'un client d'édition de documents (WOPI) * (type OnlyOffice, Collabora, MS Office) * * Cela permet de savoir quels types de fichiers sont éditables * avec l'éditeur web. * * Si NULL, alors l'édition de documents est désactivée. * * Défaut : null */ //const WOPI_DISCOVERY_URL = 'http://localhost:9980/hosting/discovery'; /** * PDF_COMMAND * Commande qui sera exécutée pour créer un fichier PDF à partir d'un HTML. * * Si laissé sur 'auto', Paheko essaiera de détecter une solution entre * PrinceXML, Chromium, wkhtmltopdf ou weasyprint (dans cet ordre). * Si aucune solution n'est disponible, une erreur sera affichée. * * Il est possible d'indiquer NULL pour désactiver l'export en PDF. * * Il est possible d'indiquer uniquement le nom du programme : * 'chromium', 'prince', 'weasyprint', ou 'wkhtmltopdf'. |
︙ | ︙ | |||
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | * Si vous utilisez une extension pour générer les PDF (comme DomPDF), alors * laisser cette constante sur 'auto'. * * Exemples : * 'weasyprint' * 'wkhtmltopdf -q --print-media-type --enable-local-file-access %s %s' * * Défaut : 'auto' * @var null|string */ //const PDF_COMMAND = 'auto'; /** * PDF_USAGE_LOG * Chemin vers le fichier où enregistrer la date de chaque export en PDF * * Ceci est utilisé notamment pour estimer le prix de la licence PrinceXML. * * Défaut : NULL * @var null|string */ //const PDF_USAGE_LOG = null; /** * CALC_CONVERT_COMMAND * Outil de conversion de formats de tableur vers un format propriétaire * | > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | * Si vous utilisez une extension pour générer les PDF (comme DomPDF), alors * laisser cette constante sur 'auto'. * * Exemples : * 'weasyprint' * 'wkhtmltopdf -q --print-media-type --enable-local-file-access %s %s' * * Si vous utilisez Prince, un message mentionnant l'utilisation de Prince * sera joint aux e-mails utilisant des fichiers PDF, conformément à la licence : * https://www.princexml.com/purchase/license_faq/#non-commercial * * Défaut : 'auto' * @var null|string */ //const PDF_COMMAND = 'auto'; /** * PDF_USAGE_LOG * Chemin vers le fichier où enregistrer la date de chaque export en PDF * * Ceci est utilisé notamment pour estimer le prix de la licence PrinceXML. * * Défaut : NULL * @var null|string */ //const PDF_USAGE_LOG = null; /** * CALC_CONVERT_COMMAND * Outil de conversion de formats de tableur vers un format propriétaire * * Paheko gère nativement les exports en ODS (OpenDocument : LibreOffice) * et CSV, et imports en CSV. * * En indiquant ici le nom d'un outil, Paheko autorisera aussi * l'import en XLSX, XLS et ODS, et l'export en XLSX. * * Pour cela il procédera simplement à une conversion entre les formats natifs * ODS/CSV et XLSX ou XLS. * * Note : installer ces commandes peut introduire des risques de sécurité sur le serveur. * * Les outils supportés sont : * - ssconvert (apt install gnumeric) (plus rapide) * - unoconv (apt install unoconv) (utilise LibreOffice) * - unoconvert (https://github.com/unoconv/unoserver/) en spécifiant l'interface * * Défault : null (= fonctionnalité désactivée) * @var string|null */ //const CALC_CONVERT_COMMAND = 'unoconv'; //const CALC_CONVERT_COMMAND = 'ssconvert'; //const CALC_CONVERT_COMMAND = 'unoconvert --interface localhost --port 2022'; /** * DOCUMENT_THUMBNAIL_COMMANDS * Indique les commandes à utiliser pour générer des miniatures pour les documents * (LibreOffice, OOXML, PDF, SVG, etc.) * * Les options possibles sont (par ordre de rapidité) : * - mupdf : les miniatures PDF/SVG/XPS/EPUB sont générées avec mutool * (apt install mupdf-tools) * - collabora : les miniatures sont générées par le serveur Collabora, via * l'API dont l'URL est indiquée dans WOPI_DISCOVERY_URL * - unoconvert : les miniatures des documents Office/LO sont générées * avec unoconvert <https://github.com/unoconv/unoserver/> * * Il est conseillé d'utiliser mupdf en priorité pour les PDF, il est plus rapide et léger. * * Note : cette option créera de nombreux fichiers de cache, et risque d'augmenter * la charge serveur de manière importante. * * Défaut : null (fonctionnalité désactivée) * @var null|array */ //const DOCUMENT_THUMBNAIL_COMMANDS = ['mupdf', 'collabora']; /** * PDFTOTEXT_COMMAND * Outil de conversion de PDF au format texte. * * Utilisé pour indexer un fichier PDF pour pouvoir rechercher dans son contenu * parmi les documents. * * Il est possible de spécifier ici la commande suivante : * - mupdf (apt install mupdf-tools) * * Toute autre commande sera ignorée. * * Défaut : null (= fonctionnalité désactivée) */ //const PDFTOTEXT_COMMAND = 'pdftotext'; /** * API_USER et API_PASSWORD * Login et mot de passe système de l'API * * Une API est disponible via l'URL https://login:password@paheko.association.tld/api/... * Voir https://fossil.kd2.org/paheko/wiki?name=API pour la documentation * * Ces deux constantes permettent d'indiquer un nom d'utilisateur * et un mot de passe pour accès à l'API. * * Cet utilisateur est distinct de ceux définis dans la page de gestion des * identifiants d'accès à l'API, et aura accès à TOUT en écriture/administration. * * Défaut: null */ //const API_USER = 'coraline'; //const API_PASSWORD = 'thisIsASecretPassword42'; /** * DISABLE_INSTALL_PING * * Lors de l'installation, ou d'une mise à jour, la version installée de Paheko, * ainsi que celle de PHP et de SQLite, sont envoyées à Paheko.cloud. * * Cela permet de savoir quelles sont les versions utilisées, et également de compter * le nombre d'installations effectuées. * * Aucune donnée personnelle n'est envoyée. Un identifiant anonyme est envoyé, * permettant d'identifier l'installation et éviter les doublons. |
︙ | ︙ | |||
703 704 705 706 707 708 709 | * Il faut recopier cette clé dans le fichier config.local.php * dans la constante CONTRIBUTOR_LICENSE. * * Merci de ne pas essayer de contourner cette licence et de contribuer au * financement de notre travail :-) */ //const CONTRIBUTOR_LICENSE = 'XXXXX'; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | * Il faut recopier cette clé dans le fichier config.local.php * dans la constante CONTRIBUTOR_LICENSE. * * Merci de ne pas essayer de contourner cette licence et de contribuer au * financement de notre travail :-) */ //const CONTRIBUTOR_LICENSE = 'XXXXX'; /** * Informations légale sur l'hébergeur * * Ce texte (HTML) est affiché en bas de la page "mentions légales" * (.../admin/legal.php) * * S'il est omis, l'association sera indiquée comme étant auto-hébergée. * * Défaut : null * * @var string|null */ //const LEGAL_HOSTING_DETAILS = 'OVH<br />5 rue de l'hébergement<br />ROUBAIX'; /** * Message d'avertissement * * Sera affiché en haut de toutes les pages de l'administration. * * Code HTML autorisé. * Utiliser NULL pour désactiver le message. * * Défaut : null * * @var null|string */ //const ALERT_MESSAGE = 'Ceci est un compte de test.'; |
Deleted src/include/data/1.0.0-beta6_migration.sql version [13c95a32fe].
|
| < < < < < < < < < < < < < |
Deleted src/include/data/1.0.0-beta8_migration.sql version [ff1b70a076].
|
| < < |
Deleted src/include/data/1.0.0-rc10_migration.sql version [ab6262425c].
|
| < < < < |
Deleted src/include/data/1.0.0-rc14_migration.sql version [2be7aec0e4].
|
| < < < < |
Deleted src/include/data/1.0.0-rc16_migration.sql version [2408d33901].
|
| < < |
Deleted src/include/data/1.0.0-rc3_migration.sql version [46b4d521e5].
|
| < |
Deleted src/include/data/1.0.0_migration.sql version [5b1e5033eb].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/1.0.0_schema.sql version [292ae06778].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/1.0.1_migration.sql version [d72d553917].
|
| < < < < < < < < < < < < < < < |
Deleted src/include/data/1.0.3_migration.sql version [9ded2b030d].
|
| < < |
Deleted src/include/data/1.0.6_migration.sql version [6e98c5399a].
|
| < < |
Deleted src/include/data/1.0.7_migration.sql version [f53124e2db].
|
| < < < < < |
Deleted src/include/data/1.1.0_migration.sql version [9f5de55bec].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/1.1.15_migration.sql version [f806b6152c].
|
| < < < < < |
Deleted src/include/data/1.1.19_migration.sql version [a29354b289].
|
| < < < |
Deleted src/include/data/1.1.3_migration.sql version [18eac8e4eb].
|
| < < < < |
Deleted src/include/data/1.1.7_migration.sql version [1dab4145d3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/1.1.8_migration.sql version [cc434f178d].
|
| < < < < < |
Deleted src/include/data/champs_membres.ini version [1af4967b02].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/include/data/dictionary.fr from [df70718a94] to [d3245db784].
︙ | ︙ | |||
3726 3727 3728 3729 3730 3731 3732 | magasin association chelou teuf ordinateur tablette smartphone | | | 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 | magasin association chelou teuf ordinateur tablette smartphone paheko association asso comptabilité compta gestion |
Modified src/include/data/schema.sql from [bb4040c594] to [57116110a2].
|
| | | 1 | ../migrations/1.3/schema.sql |
Added src/include/data/users_fields_presets.ini version [40e7316b2b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | ; Ce fichier contient la configuration par défaut des champs des fiches membres. ; La configuration est ensuite enregistrée au format INI dans la table ; config de la base de données. ; ; Syntaxe : ; ; [nom_du_champ] ; Nom unique du champ, ne peut contenir que des lettres et des tirets bas ; type = text ; label = "Super champ trop cool" ; required = true ; ; Description des options possibles pour chaque champ : ; ; type: (défaut: text) OBLIGATOIRE ; certains types gérés par <input type> de HTML5 : ; text, number, date, datetime, url, email, checkbox, file, password, tel ; champs spécifiques : ; - country = sélecteur de pays ; - textarea = texte multi lignes ; - multiple = multiples cases à cocher (jusqu'à 32, binaire) ; - select = un choix parmis plusieurs ; label: OBLIGATOIRE ; Titre du champ ; help: ; Texte d'aide sur les fiches membres ; options[]: ; pour définir les options d'un champ de type select ou multiple ; required: ; true = obligatoire, la fiche membre ne pourra être enregistrée si ce champ est vide ; false = facultatif (défaut) ; user_access_level: ; 2 = modifiable par le membre ; 1 = visible par le membre (défaut) ; 0 = visible uniquement par un admin ; management_access_level: ; 9 = visible par les membres ayant accès en administration ; 2 = visible uniquement par les personnes ayant accès en écriture aux membres ; 1 = visible par les personnes ayant accès en lecture aux membres ; list_table: 'true' si doit être listé par défaut dans la liste des membres ; sql: SQL code for GENERATED columns ; depends[]: list of fields that need to be existing in order to install this field [numero] type = number label = "Numéro de membre" required = true list_table = true default = true [pronom] type = "select" label = "Pronom" required = false default = false list_table = true options[] = "elle" options[] = "il" options[] = "iel" install_help = "Pour identifier la personne par rapport à son genre" [nom] type = text label = "Nom & prénom" required = true list_table = true default = true [email] ; ce champ est facultatif et de type 'email' type = email label = "Adresse E-Mail" required = false default = true [password] ; ce champ est obligatoirement présent et de type 'password' ; le titre ne peut être modifié label = "Mot de passe" type = password required = false default = true [adresse] type = textarea label = "Adresse postale" help = "Indiquer ici le numéro, le type de voie, etc." default = true [code_postal] type = text label = "Code postal" default = true [ville] type = text label = "Ville" list_table = true default = true [pays] type = country label = "Pays" default = false [telephone] type = tel label = "Numéro de téléphone" default = true [lettre_infos] type = checkbox label = "Inscription à la lettre d'information" install_help = "Case à cocher pour indiquer que le membre souhaite recevoir la lettre d'information de l'association" default = true [annee_naissance] type = year label = "Année de naissance" install_help = "Recommandé, plutôt que la date de naissance qui est une information très sensible." default = false ;[age_annee] ;type = generated ;label = "Âge" ;install_help = "Déterminé en utilisant l'année de naissance" ;depends[] = annee_naissance ;default = false ;sql = "strftime('%Y', date('now')) - annee_naissance" [date_naissance] type = date label = "Date de naissance complète" default = false install_help = "Attention, cette information est très sensible, il est déconseillé par le RGPD de la demander aux membres. Il est préférable de demander seulement l'année de naissance." ;[age_date] ;type = generated ;label = "Âge" ;install_help = "Déterminé en utilisant la date de naissance" ;depends[] = date_naissance ;default = false ;sql = "CAST(strftime('%Y.%m%d', date('now')) - strftime('%Y.%m%d', date_naissance) as int)" [photo] type = file label = "Photo" default = false [date_inscription] type = date label = "Date d'inscription" help = "Date à laquelle le membre a été inscrit à l'association pour la première fois" default = true default_value = '=NOW' ;[anciennete] ;type = generated ;label = "Ancienneté" ;install_help = "Nombre d'années depuis la date d'inscription" ;depends[] = date_inscription ;default = false ;sql = "CAST(strftime('%Y.%m%d', date('now')) - strftime('%Y.%m%d', date_inscription) as int)" |
Modified src/include/init.php from [df194f0caa] to [7293080d28].
1 2 | <?php | | > | > > > > | < | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | <?php namespace Paheko; use KD2\ErrorManager; use KD2\Security; use KD2\Form; use KD2\Translate; use KD2\DB\EntityManager; const CONFIG_FILE = 'config.local.php'; require_once __DIR__ . '/lib/KD2/ErrorManager.php'; ErrorManager::enable(ErrorManager::DEVELOPMENT); ErrorManager::setLogFile(__DIR__ . '/data/error.log'); /* * Version de Paheko */ function paheko_version() { if (defined('Paheko\VERSION')) { return VERSION; } $file = __DIR__ . '/../VERSION'; if (file_exists($file)) { $version = trim(file_get_contents($file)); } else { $version = 'unknown'; } define('Paheko\VERSION', $version); return $version; } function paheko_manifest() { $file = __DIR__ . '/../../manifest.uuid'; if (@file_exists($file)) { return substr(trim(file_get_contents($file)), 0, 10); } return false; } /** * Le code de Paheko ne s'écrit pas tout seul comme par magie, * merci de soutenir notre travail en faisant une contribution :) */ function paheko_contributor_license(): ?int { static $level = null; if (null !== $level) { return $level; } |
︙ | ︙ | |||
86 87 88 89 90 91 92 | } /* * Configuration globale */ // Configuration externalisée | | < | | | | | | | | > > > > > > > | < < < < < | | | | | | > < > > > > > > > > > > > > | | > > > > > > > > | | < | < | < | | < < < < < < < | < > > > > > > > | | | | | > > > > > > | > > > > > > > | | | | > > > > > > | | > > | > > > > | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | } /* * Configuration globale */ // Configuration externalisée if (file_exists(__DIR__ . '/../' . CONFIG_FILE)) { require __DIR__ . '/../' . CONFIG_FILE; } // Configuration par défaut, si les constantes ne sont pas définies dans CONFIG_FILE // (fallback) if (!defined('Paheko\ROOT')) { define('Paheko\ROOT', dirname(__DIR__)); } \spl_autoload_register(function (string $classname): void { $classname = ltrim($classname, '\\'); // Plugins if (substr($classname, 0, 14) == 'Paheko\\Plugin\\') { $classname = substr($classname, 14); $plugin_name = substr($classname, 0, strpos($classname, '\\')); $filename = str_replace('\\', '/', substr($classname, strpos($classname, '\\')+1)); $path = Plugins::getPath(strtolower($plugin_name)); // Plugin does not exist, just abort if (!$path) { return; } $path = $path . '/lib/' . $filename . '.php'; } else { // PSR-0 autoload $filename = str_replace('\\', '/', $classname); $path = ROOT . '/include/lib/' . $filename . '.php'; } if (file_exists($path)) { require_once $path; } }, true); if (!defined('Paheko\DATA_ROOT')) { define('Paheko\DATA_ROOT', ROOT . '/data'); } if (!defined('Paheko\WWW_URI')) { try { $uri = \KD2\HTTP::getRootURI(ROOT); } catch (\UnexpectedValueException $e) { $uri = null; } if ($uri == '/www/') { $uri = '/'; } elseif ($uri !== null) { readfile(ROOT . '/sous-domaine.html'); exit; } define('Paheko\WWW_URI', $uri); unset($uri); } $host = null; if (!defined('Paheko\WWW_URL')) { $host = \KD2\HTTP::getHost(); } if (WWW_URI === null || (!empty($host) && $host == 'host.unknown')) { $title = 'Impossible de détecter automatiquement l\'URL du site web.'; $info = 'Consulter l\'aide pour configurer manuellement l\'URL avec la directive WWW_URL et WWW_URI.'; $url ='https://fossil.kd2.org/paheko/wiki?name=Installation'; if (PHP_SAPI == 'cli') { printf("\n/!\\ %s\n%s\n-> %s\n\n", $title, $info, $url); } else { printf('<h2 style="color: red">%s</h2><p><a href="%s">%s</a></p>', $title, $url, $info); } exit(1); } if (!defined('Paheko\WWW_URL') && $host !== null) { define('Paheko\WWW_URL', \KD2\HTTP::getScheme() . '://' . $host . WWW_URI); } static $default_config = [ 'CACHE_ROOT' => DATA_ROOT . '/cache', 'SHARED_CACHE_ROOT' => DATA_ROOT . '/cache/shared', 'WEB_CACHE_ROOT' => DATA_ROOT . '/cache/web/%host%', 'DB_FILE' => DATA_ROOT . '/association.sqlite', 'DB_SCHEMA' => ROOT . '/include/data/schema.sql', 'PLUGINS_ROOT' => DATA_ROOT . '/plugins', 'ALLOW_MODIFIED_IMPORT' => true, 'SHOW_ERRORS' => true, 'MAIL_ERRORS' => false, 'ERRORS_REPORT_URL' => null, 'REPORT_USER_EXCEPTIONS' => 0, 'ENABLE_TECH_DETAILS' => true, 'HTTP_LOG_FILE' => null, 'ENABLE_UPGRADES' => true, 'USE_CRON' => false, 'ENABLE_XSENDFILE' => false, 'DISABLE_EMAIL' => false, 'SMTP_HOST' => false, 'SMTP_USER' => null, 'SMTP_PASSWORD' => null, 'SMTP_PORT' => 587, 'SMTP_SECURITY' => 'STARTTLS', 'SMTP_HELO_HOSTNAME' => null, 'MAIL_RETURN_PATH' => null, 'MAIL_BOUNCE_PASSWORD' => null, 'MAIL_SENDER' => null, 'ADMIN_URL' => WWW_URL . 'admin/', 'NTP_SERVER' => 'fr.pool.ntp.org', 'ADMIN_COLOR1' => '#20787a', 'ADMIN_COLOR2' => '#85b9ba', 'ADMIN_BACKGROUND_IMAGE' => WWW_URL . 'admin/static/bg.png', 'FORCE_CUSTOM_COLORS' => false, 'DISABLE_INSTALL_FORM' => false, 'FILE_STORAGE_BACKEND' => 'SQLite', 'FILE_STORAGE_CONFIG' => null, 'FILE_STORAGE_QUOTA' => null, 'FILE_VERSIONING_POLICY' => null, 'FILE_VERSIONING_MAX_SIZE' => null, 'API_USER' => null, 'API_PASSWORD' => null, 'PDF_COMMAND' => 'auto', 'PDF_USAGE_LOG' => null, 'PDFTOTEXT_COMMAND' => null, 'CALC_CONVERT_COMMAND' => null, 'DOCUMENT_THUMBNAIL_COMMANDS' => null, 'CONTRIBUTOR_LICENSE' => null, 'SQL_DEBUG' => null, 'SYSTEM_SIGNALS' => [], 'LOCAL_LOGIN' => null, 'LEGAL_HOSTING_DETAILS' => null, 'ALERT_MESSAGE' => null, 'DISABLE_INSTALL_PING' => false, 'WOPI_DISCOVERY_URL' => null, 'SQLITE_JOURNAL_MODE' => 'TRUNCATE', ]; foreach ($default_config as $const => $value) { $const = sprintf('Paheko\\%s', $const); if (!defined($const)) { define($const, $value); } } // Check SMTP_SECURITY value if (SMTP_SECURITY) { $const = '\KD2\SMTP::' . strtoupper(SMTP_SECURITY); if (!defined($const)) { throw new \LogicException('Configuration: SMTP_SECURITY n\'a pas une valeur reconnue. Valeurs acceptées: STARTTLS, TLS, SSL, NONE.'); } } // Used for private files, just in case WWW_URL is not the same domain as ADMIN_URL define('Paheko\BASE_URL', str_replace('/admin/', '/', ADMIN_URL)); const HELP_URL = 'https://paheko.cloud/aide?from=%s'; const HELP_PATTERN_URL = 'https://paheko.cloud/%s'; const WEBSITE = 'https://fossil.kd2.org/paheko/'; const PING_URL = 'https://paheko.cloud/ping/'; const PLUGINS_URL = 'https://paheko.cloud/plugins/list.json'; const USER_TEMPLATES_CACHE_ROOT = CACHE_ROOT . '/utemplates'; const STATIC_CACHE_ROOT = CACHE_ROOT . '/static'; const SHARED_USER_TEMPLATES_CACHE_ROOT = SHARED_CACHE_ROOT . '/utemplates'; const SMARTYER_CACHE_ROOT = SHARED_CACHE_ROOT . '/compiled'; // Used to get around some providers misconfiguration issues if (isset($_SERVER['HTTP_X_OVHREQUEST_ID'])) { define('Paheko\HOSTING_PROVIDER', 'OVH'); } else { define('Paheko\HOSTING_PROVIDER', null); } // PHP devrait être assez intelligent pour chopper la TZ système mais nan // il sait pas faire (sauf sur Debian qui a le bon patch pour ça), donc pour // éviter le message d'erreur à la con on définit une timezone par défaut // Pour utiliser une autre timezone, il suffit de définir date.timezone dans // un .htaccess ou dans CONFIG_FILE if (!ini_get('date.timezone') || ini_get('date.timezone') === 'UTC') { if (($tz = @date_default_timezone_get()) && $tz !== 'UTC') { ini_set('date.timezone', $tz); } else { ini_set('date.timezone', 'Europe/Paris'); } } class ValidationException extends UserException { } class APIException extends \LogicException { } // activer le gestionnaire d'erreurs/exceptions ErrorManager::setEnvironment(SHOW_ERRORS ? ErrorManager::DEVELOPMENT : ErrorManager::PRODUCTION | ErrorManager::CLI_DEVELOPMENT); ErrorManager::setLogFile(DATA_ROOT . '/error.log'); // activer l'envoi de mails si besoin est if (MAIL_ERRORS) { ErrorManager::setEmail(MAIL_ERRORS); } if (ERRORS_REPORT_URL) { ErrorManager::setRemoteReporting(ERRORS_REPORT_URL, true); } ErrorManager::setContext([ 'root_directory' => ROOT, 'paheko_data_root' => DATA_ROOT, 'paheko_version' => paheko_version(), ]); ErrorManager::setProductionErrorTemplate(defined('Paheko\ERRORS_TEMPLATE') && ERRORS_TEMPLATE ? ERRORS_TEMPLATE : '<!DOCTYPE html><html><head><title>Erreur interne</title> <style type="text/css"> body {font-family: sans-serif; background: #fff; } code, p, h1 { max-width: 400px; margin: 1em auto; display: block; } code { text-align: right; color: #666; } a { color: blue; } form { text-align: center; } </style></head><body><h1>Erreur interne</h1><p>Désolé mais le serveur a rencontré une erreur interne et ne peut répondre à votre requête. Merci de ré-essayer plus tard.</p> <p>Si vous suspectez un bug dans Paheko, vous pouvez suivre <a href="https://fossil.kd2.org/paheko/wiki?name=Rapporter+un+bug&p">ces instructions</a> pour le rapporter.</p> <if(sent)><p>Un-e responsable a été notifié-e et cette erreur sera corrigée dès que possible.</p></if> <if(logged)><code>L\'erreur a été enregistrée dans les journaux système (error.log) sous la référence : <b>{$ref}</b></code></if> <p><a href="' . WWW_URL . '">← Retour à la page d\'accueil</a></p> </body></html>'); ErrorManager::setHtmlHeader('<!DOCTYPE html><html><head><meta charset="utf-8" /><style type="text/css"> body { font-family: sans-serif; background: #fff; } * { margin: 0; padding: 0; } u, code b, i, h3 { font-style: normal; font-weight: normal; text-decoration: none; } #icn { color: #fff; font-size: 2em; float: right; margin: 1em; padding: 1em; background: #900; border-radius: 50%; } section header { background: #fdd; padding: 1em; } section article { margin: 1em; } section article h3, section article h4 { font-size: 1em; font-family: mono; } code { border: 1px dotted #ccc; display: block; } code b { margin-right: 1em; color: #999; } code u { background: #fcc; display: inline-block; width: 100%; } table { border-collapse: collapse; margin: 1em; } td, th { border: 1px solid #ccc; padding: .2em .5em; text-align: left; vertical-align: top; } input { padding: .3em; margin: .5em; font-size: 1.2em; cursor: pointer; } </style></head><body> <pre id="icn"> \__/<br /> (xx)<br />//||\\\\</pre> <section> <article> <h1>Une erreur s\'est produite</h1> <if(report)><form method="post" action="{$report_url}"><p><input type="hidden" name="report" value="{$report_json}" /><input type="submit" value="Rapporter l\'erreur aux développeur⋅euses de Paheko →" /></p></form></if> </article> </section> '); function user_error(UserException $e) { if (REPORT_USER_EXCEPTIONS > 0) { \Paheko\Form::reportUserException($e); } if (PHP_SAPI == 'cli') { echo $e->getMessage(); } else { // Flush any previous output, such as module HTML code etc. @ob_end_clean(); if ($e->getCode() >= 400) { http_response_code($e->getCode()); } // Don't use Template class as there might be an error there due do the context (eg. install/upgrade) $tpl = new \KD2\Smartyer(ROOT . '/templates/error.tpl'); $tpl->setCompiledDir(SMARTYER_CACHE_ROOT); $tpl->assign('error', $e->getMessage()); $tpl->assign('html_error', $e->getHTMLMessage()); $tpl->assign('admin_url', ADMIN_URL); $tpl->display(); } exit; } if (REPORT_USER_EXCEPTIONS < 2) { // Message d'erreur simple pour les erreurs de l'utilisateur ErrorManager::setCustomExceptionHandler('\Paheko\UserException', '\Paheko\user_error'); } // Clé secrète utilisée pour chiffrer les tokens CSRF etc. if (!defined('Paheko\SECRET_KEY')) { $key = base64_encode(random_bytes(64)); Install::setLocalConfig('SECRET_KEY', $key); define('Paheko\SECRET_KEY', $key); } // Intégration du secret pour les tokens CSRF Form::tokenSetSecret(SECRET_KEY); EntityManager::setGlobalDB(DB::getInstance()); Translate::setLocale('fr_FR'); // This is specific to OVH and other hosting providers who don't set up their servers properly // see https://www.prestashop.com/forums/topic/393496-prestashop-16-webservice-authentification-on-ovh/ if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) { @list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); } /* * Vérifications pour enclencher le processus d'installation ou de mise à jour */ if (!defined('Paheko\INSTALL_PROCESS')) { $exists = file_exists(DB_FILE); if (!$exists) { if (in_array('install.php', get_included_files())) { die('Erreur de redirection en boucle : problème de configuration ?'); } Utils::redirect(ADMIN_URL . 'install.php'); } $v = DB::getInstance()->version(); if (version_compare($v, paheko_version(), '<')) { if (!empty($_POST)) { readfile(ROOT . '/templates/static/upgrade_post.html'); exit; } Utils::redirect(ADMIN_URL . 'upgrade.php'); } } |
Deleted src/include/lib/Garradin/API.php version [15a246b4fb].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/API_Credentials.php version [55a0e25e82].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Accounts.php version [d233ba835a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/AssistedReconciliation.php version [7eaa670dc7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Charts.php version [5ce026c347].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Export.php version [872ac881da].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Graph.php version [dad1eda3f9].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Import.php version [9708fc44ff].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Projects.php version [4318061708].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Reports.php version [9fc7c83c35].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Transactions.php version [fe8c92f672].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Accounting/Years.php version [119db6c791].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/CSV.php version [6e243dfec5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/CSV_Custom.php version [5243427abe].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Config.php version [6f4c0c0f4e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/DB.php version [b153f0e4eb].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/DynamicList.php version [6e9f9ec3ec].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/API_Credentials.php version [f8f4575a16].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Accounting/Account.php version [9713ee2215].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Accounting/Chart.php version [fe9131dd28].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Accounting/Line.php version [d840a29496].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Accounting/Project.php version [58624a9c0e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Accounting/Transaction.php version [33c4de1c1b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Accounting/Year.php version [b488c48138].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Files/File.php version [e97bbb4fd4].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Services/Fee.php version [7689846f7f].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Services/Reminder.php version [52650ee9cf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Services/Service.php version [1019ca2d5b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Services/Service_User.php version [b960ae24c8].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Users/Category.php version [2e075cd1f0].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Users/Email.php version [a217d30bd0].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Entities/Web/Page.php version [21fb3dd712].
|
|