Changes In Branch dev Through [076971cb89] Excluding Merge-Ins
This is equivalent to a diff from a0c15d9d73 to 076971cb89
2018-09-13
| ||
22:06 | Générer une erreur quand même quand la suppression échoue et que le fichier existe toujours check-in: 1bdf70a9d5 user: bohwaz tags: dev | |
22:03 | Parfois le fichier a déjà disparu ! check-in: 076971cb89 user: bohwaz tags: dev | |
22:01 | Ne pas faire d'erreur en cas de problème à la création, car des fois il y a des race conditions check-in: 3b0487da74 user: bohwaz tags: dev | |
2018-08-26
| ||
01:19 | Evitons les conflits de noms de champs quand quelqu'un a déjà créé un champ nommé "catégorie" check-in: 96c5022fb3 user: bohwaz tags: trunk, stable | |
2018-08-02
| ||
22:58 | Merge avec trunk check-in: e9ab0666a3 user: bohwaz tags: dev | |
22:52 | Erreur plus explicite quand on essaye de modifier une écriture qui n'existe pas check-in: a0c15d9d73 user: bohwaz tags: trunk, stable | |
14:18 | Ne pas afficher l'ID check-in: b5b5a3632c user: bohwaz tags: trunk, stable | |
2018-07-20
| ||
22:15 | Erreur plus explicite quand on essaye de modifier une écriture qui n'existe pas check-in: 1f94d65a20 user: bohwaz tags: dev | |
Modified src/README from [fbebcdff15] to [b24af5ed67].
1 2 3 4 5 6 7 8 9 10 | Garradin - Gestionnaire d'association libre =========================================== Inclus les bibliothèques suivantes : - Gibberish AES https://github.com/mdp/gibberish-aes Copyright : Mark Percival 2008 - http://markpercival.us Licence : MIT | < < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | Garradin - Gestionnaire d'association libre =========================================== Inclus les bibliothèques suivantes : - Gibberish AES https://github.com/mdp/gibberish-aes Copyright : Mark Percival 2008 - http://markpercival.us Licence : MIT - KD2fw Copyright : 2001-2018 BohwaZ Licence : GNU AGPL v3 |
Modified src/VERSION from [d1cc680d2c] to [37225f3c32].
|
| | | 1 | 0.9.0 |
Modified src/config.dist.php from [1f09233dd8] to [4b1bdaf310].
︙ | ︙ | |||
234 235 236 237 238 239 240 | * STARTTLS = utilisation de STARTTLS (moyennement sécurisé) * * Défaut : STARTTLS */ const SMTP_SECURITY = 'STARTTLS'; /** | | | | < < < > | > > | | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | * STARTTLS = utilisation de STARTTLS (moyennement sécurisé) * * Défaut : STARTTLS */ const SMTP_SECURITY = 'STARTTLS'; /** * Activer les sauvegardes automatiques * * Utile à désactiver si vous avez déjà des sauvegardes effectuées * automatiquement au niveau du système. * * Sinon les sauvegardes seront effectuées soit par la tâche cron * soit à l'affichage de la page d'accueil (si nécessaire). * * Voir paramètre USE_CRON aussi * * Défaut : true */ const ENABLE_AUTOMATIC_BACKUPS = true; |
Modified src/cron.php from [d4a8acbd51] to [0a002d599e].
1 2 3 4 5 6 7 8 | <?php namespace Garradin; require_once __DIR__ . '/include/init.php'; // Exécution des tâches automatiques | | < | 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 Garradin; require_once __DIR__ . '/include/init.php'; // Exécution des tâches automatiques if (ENABLE_AUTOMATIC_BACKUPS && $config->get('frequence_sauvegardes') && $config->get('nombre_sauvegardes')) { $s = new Sauvegarde; $s->auto(); } // Exécution des rappels automatiques $rappels = new Rappels; if ($rappels->countAll()) { $rappels->sendPending(); } // Nettoyage du cache statique Static_Cache::clean(); |
Deleted src/include/data/0.4.0.sql version [19c558523f].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/0.4.3.sql version [074264b547].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/0.6.0.sql version [95aac309bf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added src/include/data/0.9.0.sql version [9f23495ff4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | -- Désactivation de l'accès aux membres, pour les groupes qui n'avaient que le droit de lecture -- car maintenant ce droit permet de voir les fiches de membres complètes UPDATE membres_categories SET droit_membres = 0 WHERE droit_membres = 1; -- Suppression de la colonne description des catégories ALTER TABLE membres_categories RENAME TO membres_categories_old; -- Mise à jour table compta_rapprochement: la foreign key sur membres est passée -- à ON DELETE SET NULL ALTER TABLE compta_rapprochement RENAME TO compta_rapprochement_old; -- Re-créer la table -- Créer également les nouvelles tables email .read schema.sql -- Copie des données, sauf la colonne description INSERT INTO membres_categories SELECT id, nom, droit_wiki, droit_membres, droit_compta, droit_inscription, droit_connexion, droit_config, cacher, id_cotisation_obligatoire FROM membres_categories_old; -- Suppression des anciennes tables DROP TABLE membres_categories_old; -- Migration des données INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old; DROP TABLE compta_rapprochement_old; -- Cette variable n'est plus utilisée DELETE FROM config WHERE cle = 'email_envoi_automatique'; ALTER TABLE plugins ADD COLUMN menu_condition TEXT NULL; -- Supprimer le début dans le nom des plugins UPDATE plugins_signaux SET callback = replace(callback, 'Garradin\Plugin\', ''); |
Modified src/include/data/schema.sql from [80be656e5d] to [efe750515a].
︙ | ︙ | |||
9 10 11 12 13 14 15 | -- compta_categorie_dons => id_categorie CREATE TABLE IF NOT EXISTS membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY NOT NULL, nom TEXT NOT NULL, | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | -- compta_categorie_dons => id_categorie CREATE TABLE IF NOT EXISTS membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY NOT NULL, nom TEXT NOT NULL, droit_wiki INTEGER NOT NULL DEFAULT 1, droit_membres INTEGER NOT NULL DEFAULT 1, droit_compta INTEGER NOT NULL DEFAULT 1, droit_inscription INTEGER NOT NULL DEFAULT 0, droit_connexion INTEGER NOT NULL DEFAULT 1, droit_config INTEGER NOT NULL DEFAULT 0, |
︙ | ︙ | |||
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | officiel INTEGER NOT NULL DEFAULT 0, nom TEXT NOT NULL, description TEXT NULL, auteur TEXT NULL, url TEXT NULL, version TEXT NOT NULL, menu INTEGER NOT NULL DEFAULT 0, config TEXT NULL ); CREATE TABLE IF NOT EXISTS plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE IF NOT EXISTS compta_rapprochement -- Rapprochement entre compta et relevés de comptes ( id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), | > | | 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 | officiel INTEGER NOT NULL DEFAULT 0, nom TEXT NOT NULL, description TEXT NULL, auteur TEXT NULL, url TEXT NULL, version TEXT NOT NULL, menu INTEGER NOT NULL DEFAULT 0, menu_condition TEXT NULL, config TEXT NULL ); CREATE TABLE IF NOT EXISTS plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE IF NOT EXISTS compta_rapprochement -- Rapprochement entre compta et relevés de comptes ( id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL ); CREATE TABLE IF NOT EXISTS fichiers -- Données sur les fichiers ( id INTEGER NOT NULL PRIMARY KEY, nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg) |
︙ | ︙ | |||
382 383 384 385 386 387 388 | CREATE TABLE IF NOT EXISTS fichiers_compta_journal -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES compta_journal (id), PRIMARY KEY(fichier, id) ); | > > > > > > > > > > > > | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | CREATE TABLE IF NOT EXISTS fichiers_compta_journal -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES compta_journal (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS recherches -- Recherches enregistrées ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé intitule TEXT NOT NULL, creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation), cible TEXT NOT NULL, -- "membres" ou "compta_journal" type TEXT NOT NULL, -- "json" ou "sql" contenu TEXT NOT NULL ); |
Modified src/include/init.php from [5ff1d716c3] to [bfe2446b5f].
︙ | ︙ | |||
105 106 107 108 109 110 111 | 'SMTP_HOST' => false, 'SMTP_USER' => null, 'SMTP_PASSWORD' => null, 'SMTP_PORT' => 587, 'SMTP_SECURITY' => 'STARTTLS', 'ADMIN_URL' => WWW_URL . 'admin/', 'NTP_SERVER' => 'fr.pool.ntp.org', | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | 'SMTP_HOST' => false, 'SMTP_USER' => null, 'SMTP_PASSWORD' => null, 'SMTP_PORT' => 587, 'SMTP_SECURITY' => 'STARTTLS', 'ADMIN_URL' => WWW_URL . 'admin/', 'NTP_SERVER' => 'fr.pool.ntp.org', 'ENABLE_AUTOMATIC_BACKUPS' => true, ]; foreach ($default_config as $const => $value) { $const = sprintf('Garradin\\%s', $const); if (!defined($const)) |
︙ | ︙ |
Modified src/include/lib/Garradin/Config.php from [868d015351] to [52d2a7f213].
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | * Singleton simple * @return Config */ static public function getInstance() { return self::$_instance ?: self::$_instance = new Config; } /** * Empêche de cloner l'objet * @return void */ private function __clone() { | > > > > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | * Singleton simple * @return Config */ static public function getInstance() { return self::$_instance ?: self::$_instance = new Config; } static public function deleteInstance() { self::$_instance = null; } /** * Empêche de cloner l'objet * @return void */ private function __clone() { |
︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 'champ_identite' => $string, 'version' => $string, 'couleur1' => $string, 'couleur2' => $string, 'image_fond' => $string, ]; $db = DB::getInstance(); $this->config = $db->getAssoc('SELECT cle, valeur FROM config ORDER BY cle;'); foreach ($this->config as $key=>&$value) | > > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 'champ_identite' => $string, 'version' => $string, 'couleur1' => $string, 'couleur2' => $string, 'image_fond' => $string, 'desactiver_site' => $bool, ]; $db = DB::getInstance(); $this->config = $db->getAssoc('SELECT cle, valeur FROM config ORDER BY cle;'); foreach ($this->config as $key=>&$value) |
︙ | ︙ |
Modified src/include/lib/Garradin/DB.php from [1dead0b7c1] to [7fa1101431].
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | // Activer les contraintes des foreign keys $this->db->exec('PRAGMA foreign_keys = ON;'); $this->db->createFunction('transliterate_to_ascii', ['Garradin\Utils', 'transliterateToAscii']); } } /** * Import a file containing SQL commands * Allows to use the statement ".read other_file.sql" to load other files * @param string $file Path to file containing SQL commands * @return boolean */ | > > > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | // Activer les contraintes des foreign keys $this->db->exec('PRAGMA foreign_keys = ON;'); $this->db->createFunction('transliterate_to_ascii', ['Garradin\Utils', 'transliterateToAscii']); } } public function close() { parent::close(); self::$_instance = null; } /** * Import a file containing SQL commands * Allows to use the statement ".read other_file.sql" to load other files * @param string $file Path to file containing SQL commands * @return boolean */ |
︙ | ︙ |
Modified src/include/lib/Garradin/Install.php from [e286e959c9] to [ba81d4bd4a].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php namespace Garradin; /** * Pour procéder à l'installation de l'instance Garradin * Utile pour automatiser l'installation sans passer par la page d'installation */ class Install { static public function install($nom_asso, $adresse_asso, $email_asso, $nom_categorie, $nom_membre, $email_membre, $passe_membre, $site_asso = WWW_URL) { $db = DB::getInstance(true); // Taille de la page de DB, on force à 4096 (défaut dans les dernières // versions de SQLite mais pas les vieilles) $db->exec('PRAGMA page_size = 4096;'); | > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; /** * Pour procéder à l'installation de l'instance Garradin * Utile pour automatiser l'installation sans passer par la page d'installation */ class Install { static public function reset(Membres\Session $session, $password, array $options = []) { $config = (object) Config::getInstance()->getConfig(); $user = $session->getUser(); if (!$session->checkPassword($password, $user->passe)) { throw new UserException('Le mot de passe ne correspond pas.'); } (new Sauvegarde)->create(date('Y-m-d-His-') . 'avant-remise-a-zero'); DB::getInstance()->close(); Config::deleteInstance(); unlink(DB_FILE); return self::install($config->nom_asso, $config->adresse_asso, $config->email_asso, 'Bureau', $user->identite, $user->email, $password, $config->site_asso); } static public function install($nom_asso, $adresse_asso, $email_asso, $nom_categorie, $nom_membre, $email_membre, $passe_membre, $site_asso = WWW_URL) { $db = DB::getInstance(true); // Taille de la page de DB, on force à 4096 (défaut dans les dernières // versions de SQLite mais pas les vieilles) $db->exec('PRAGMA page_size = 4096;'); |
︙ | ︙ | |||
127 128 129 130 131 132 133 | // Vérifier que les répertoires vides existent, sinon les créer $paths = [DATA_ROOT, PLUGINS_ROOT, CACHE_ROOT, CACHE_ROOT . '/static', CACHE_ROOT . '/compiled']; foreach ($paths as $path) { if (!file_exists($path)) { | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | // Vérifier que les répertoires vides existent, sinon les créer $paths = [DATA_ROOT, PLUGINS_ROOT, CACHE_ROOT, CACHE_ROOT . '/static', CACHE_ROOT . '/compiled']; foreach ($paths as $path) { if (!file_exists($path)) { @mkdir($path, 0777, true); } if (!is_dir($path)) { throw new UserException('Le répertoire '.$path.' n\'existe pas ou n\'est pas un répertoire.'); } |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres.php from [79cc6c1e41] to [9cbfc1c785].
︙ | ︙ | |||
290 291 292 293 294 295 296 | } public function getIDWithNumero($numero) { return DB::getInstance()->firstColumn('SELECT id FROM membres WHERE numero = ?;', (int) $numero); } | | > > > > > > > > > > > > > > > > > > > > > > > > | | < > > > > | > | | | > > > > > > | > | > | | > > > > > > | > | > > > > | > | > > > > > > > > > > > > > > > | > | > > | > > > > | | | > > | > | > | > > > > | > | > > > > > | > > > > > > | > > | > | < > > > | > > | > > > > | | | | > | | > | | | > > > > | | > > > | > | > | > > | < | > | > > > > > > | > > | | > | > | > | > > > > | > | | 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 | } public function getIDWithNumero($numero) { return DB::getInstance()->firstColumn('SELECT id FROM membres WHERE numero = ?;', (int) $numero); } public function buildSQLSearchQuery(array $groups, $order, $desc = false, $limit = 100) { $db = DB::getInstance(); $config = Config::getInstance(); $champs = $config->get('champs_membres'); $colonnes = []; $query_groups = []; foreach ($groups as $group) { if (!isset($group['conditions'], $group['operator']) || !is_array($group['conditions']) || ($group['operator'] != 'AND' && $group['operator'] != 'OR')) { // Ignorer les groupes de conditions invalides continue; } $query_group_conditions = []; foreach ($group['conditions'] as $condition) { if (!isset($condition['column'], $condition['operator']) || (isset($condition['values']) && !is_array($condition['values']))) { // Ignorer les conditions invalides continue; } if (!$champs->get($condition['column'])) { // Ignorer une condition qui se rapporte à une colonne // qui n'existe pas, cas possible si on reprend une recherche // après avoir modifié les fiches de membres continue; } $colonnes[] = $condition['column']; $champ = $champs->get($condition['column']); if ($champs->isText($condition['column'])) { $query = sprintf('transliterate_to_ascii(%s) COLLATE NOCASE %s', $db->quoteIdentifier($condition['column']), $condition['operator']); } else { $query = sprintf('%s %s', $db->quoteIdentifier($condition['column']), $condition['operator']); } $values = isset($condition['values']) ? $condition['values'] : []; $values = array_map(['Garradin\Utils', 'transliterateToAscii'], $values); if ($champ->type == 'tel') { // Normaliser le numéro de téléphone $values = array_map(['Garradin\Utils', 'normalizePhoneNumber'], $values); } if ($condition['operator'] == '&') { $new_query = []; foreach ($values as $value) { $new_query[] = sprintf('%s (1 << %d)', $query, (int) $value); } $query = '(' . implode(' AND ', $new_query) . ')'; } elseif (strpos($query, '??') !== false) { $values = array_map([$db, 'quote'], $values); $query = str_replace('??', implode(', ', $values), $query); } elseif (preg_match('/%\?%|%\?|\?%/', $query, $match)) { $value = str_replace(['%_'], ['\\%', '\\_'], reset($values)); $value = str_replace('?', $value, $match[0]); $query = str_replace($match[0], sprintf('%s ESCAPE \'\\\'', $db->quote($value)), $query); } elseif (strpos($query, '?') !== false) { $expected = substr_count($query, '?'); $found = count($values); if ($expected != $found) { throw new \RuntimeException(sprintf('Operator %s expects at least %d parameters, only %d supplied', $condition['operator'], $expected, $found)); } for ($i = 0; $i < $expected; $i++) { $pos = strpos($query, '?'); $query = substr_replace($query, $db->quote(array_shift($values)), $pos, 1); } } $query_group_conditions[] = $query; } $query_groups[] = implode(' ' . $group['operator'] . ' ', $query_group_conditions); } $colonnes = array_unique($colonnes); if (!in_array($config->get('champ_identite'), $colonnes)) { array_unshift($colonnes, $config->get('champ_identite')); } $colonnes = array_map([$db, 'quoteIdentifier'], $colonnes); if ($champs->isText($order)) { $order = sprintf('transliterate_to_ascii(%s) COLLATE NOCASE', $db->quoteIdentifier($order)); } else { $order = $db->quoteIdentifier($order); } $sql_query = sprintf('SELECT id, %s FROM membres WHERE %s ORDER BY %s %s LIMIT %d;', implode(', ', $colonnes), '(' . implode(') AND (', $query_groups) . ')', $order, $desc ? 'DESC' : 'ASC', (int) $limit); return $sql_query; } public function getSearchHeaderFields(array $result) { if (!count($result)) { return false; } $champs = Config::getInstance()->get('champs_membres'); $fields = []; foreach (reset($result) as $field=>$value) { if ($config = $champs->get($field)) { $fields[$field] = $config; } } return $fields; } public function searchSQL($query) { $db = DB::getInstance(); if (!preg_match('/LIMIT\s+/i', $query)) { $query = preg_replace('/;?\s*$/', '', $query); $query .= ' LIMIT 100'; } if (preg_match('/;\s*(.+?)$/', $query)) { throw new UserException('Une seule requête peut être envoyée en même temps.'); } $st = $db->prepare($query); if (!$st->readOnly()) { throw new UserException('Seules les requêtes en lecture sont autorisées.'); } $res = $st->execute(); $out = []; while ($row = $res->fetchArray(SQLITE3_ASSOC)) { if (array_key_exists('passe', $row)) { unset($row['passe']); } $out[] = (object) $row; } return $out; } public function schemaSQL() { $db = DB::getInstance(); $tables = [ 'membres' => $db->firstColumn('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'membres\';'), 'categories'=> $db->firstColumn('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'membres_categories\';'), ]; return $tables; } public function listByCategory($cat, $fields, $page = 1, $order = null, $desc = false) { $begin = ($page - 1) * self::ITEMS_PER_PAGE; $db = DB::getInstance(); $config = Config::getInstance(); |
︙ | ︙ | |||
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | } static protected function _deleteMembres($membres) { foreach ($membres as &$id) { $id = (int) $id; } Plugin::fireSignal('membre.suppression', $membres); $db = DB::getInstance(); // Suppression du membre return $db->delete('membres', $db->where('id', $membres)); } | > > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } static protected function _deleteMembres($membres) { foreach ($membres as &$id) { $id = (int) $id; // Suppression des fichiers liés $files = Fichiers::listLinkedFiles(Fichiers::LIEN_MEMBRES, $id, null); foreach ($files as $file) { $file = new Fichiers($file->id, $file); $file->remove(); } } Plugin::fireSignal('membre.suppression', $membres); $db = DB::getInstance(); // Suppression du membre return $db->delete('membres', $db->where('id', $membres)); } } |
Modified src/include/lib/Garradin/Membres/Categories.php from [af4fccf952] to [5b61a5fe1b].
︙ | ︙ | |||
45 46 47 48 49 50 51 | } } public function add($data) { $this->_checkData($data); | < < < < < | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | } } public function add($data) { $this->_checkData($data); foreach ($this->droits as $key=>$value) { if (!isset($data['droit_'.$key])) $data['droit_'.$key] = $value; else $data['droit_'.$key] = (int)$data['droit_'.$key]; } |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Champs.php from [6839687f0f] to [a027cb81e3].
︙ | ︙ | |||
248 249 250 251 252 253 254 | } elseif ($config->type == 'number' || $config->type == 'multiple') { $rules[] = 'numeric'; } elseif ($config->type == 'select') { | | | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | } elseif ($config->type == 'number' || $config->type == 'multiple') { $rules[] = 'numeric'; } elseif ($config->type == 'select') { $rules[] = 'in:' . range(0, count($config->options) - 1); } elseif ($config->type == 'checkbox') { $rules[] = 'boolean'; } if ($name == 'passe') |
︙ | ︙ | |||
528 529 530 531 532 533 534 | /** * Enregistre les changements de champs en base de données * @param boolean $enable_copy Recopier les anciennes champs dans les nouveaux ? * @return boolean true */ public function save($enable_copy = true) { | | | | | | | | | | > | 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 | /** * Enregistre les changements de champs en base de données * @param boolean $enable_copy Recopier les anciennes champs dans les nouveaux ? * @return boolean true */ public function save($enable_copy = true) { $db = DB::getInstance(); $config = Config::getInstance(); // Champs à créer $create = [ 'id INTEGER PRIMARY KEY, -- Numéro attribué automatiquement', 'id_categorie INTEGER NOT NULL,', 'date_connexion TEXT NULL CHECK (date_connexion IS NULL OR datetime(date_connexion) = date_connexion), -- Date de dernière connexion', 'date_inscription TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date_inscription) IS NOT NULL AND date(date_inscription) = date_inscription), -- Date d\'inscription', 'secret_otp TEXT NULL, -- Code secret pour TOTP', 'clef_pgp TEXT NULL, -- Clé publique PGP' ]; // Clés à créer, permet aussi de clôturer la syntaxe du tableau, noter l'absence de virgule dans cette ligne $create_keys = [ 'FOREIGN KEY (id_categorie) REFERENCES membres_categories (id)' ]; // Champs à recopier $copy = [ 'id' => 'id', |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Import.php from [032b787733] to [6fc6eacc71].
︙ | ︙ | |||
8 9 10 11 12 13 14 | use Garradin\Utils; use Garradin\UserException; use KD2\ODSWriter; class Import { | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < | < | < < < < < < < < < | < > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > | > > | > > | > > > > > > > > | > > > > > > | > < < | | 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 | use Garradin\Utils; use Garradin\UserException; use KD2\ODSWriter; class Import { public function getCSVAsArray($path) { if (!file_exists($path) || !is_readable($path)) { throw new \RuntimeException('Fichier inconnu : '.$path); } $fp = fopen($path, 'r'); if (!$fp) { return false; } $delim = Utils::find_csv_delim($fp); Utils::skip_bom($fp); $line = 0; $out = []; $nb_columns = null; while (!feof($fp)) { $row = fgetcsv($fp, 4096, $delim); $line++; if (empty($row)) { continue; } if (null === $nb_columns) { $nb_columns = count($row); } if (count($row) != $nb_columns) { throw new UserException('Erreur sur la ligne ' . $line . ' : incohérence dans le nombre de colonnes avec la première ligne.'); } $out[$line] = $row; } fclose($fp); return $out; } /** * Importer un CSV générique * @param string $path Chemin vers le CSV * @param array $translation_table Tableau indiquant la correspondance à effectuer entre les colonnes * du CSV et les champs de Garradin. Par exemple : ['Date création fiche' => 'date_inscription'] * @return boolean TRUE en cas de succès */ public function fromArray(array $table, $translation_table, $skip_lines = 0) { $db = DB::getInstance(); $db->begin(); $membres = new Membres; $champs = Config::getInstance()->get('champs_membres'); $nb_columns = count($translation_table); if ($skip_lines) { $table = array_slice($table, $skip_lines, null, true); } foreach ($table as $line => $row) { if (empty($row)) { continue; } if (count($row) != $nb_columns) { $db->rollback(); throw new UserException('Erreur sur la ligne ' . $line . ' : le nombre de colonnes est incorrect.'); } $data = []; foreach ($translation_table as $column_index => $garradin_field) { // Champs qu'on ne veut pas importer if (empty($garradin_field)) { continue; } // Concaténer plusieurs champs, si on choisit d'indiquer plusieurs fois // le même champ pour plusieurs colonnes (par exemple pour mettre nom et prénom // dans un seul champ) if (isset($data[$garradin_field])) { $champ = $champs->get($garradin_field); if ($champ->type == 'text') { $data[$garradin_field] .= ' ' . $row[$column_index]; } elseif ($champ->type == 'textarea') { $data[$garradin_field] .= "\n" . $row[$column_index]; } else { throw new UserException(sprintf('Erreur sur la ligne %d : impossible de concaténer des colonnes avec le champ %s : n\'est pas un champ de type texte', $line, $champ->title)); } } else { $data[$garradin_field] = $row[$column_index]; } } try { $membres->add($data, false); } catch (UserException $e) { $db->rollback(); throw new UserException('Erreur sur la ligne ' . $line . ' : ' . $e->getMessage()); } } $db->commit(); return true; } /** * Importer un CSV de la liste des membres depuis un export Garradin * @param string $path Chemin vers le CSV * @param int $current_user_id * @return boolean TRUE en cas de succès */ public function fromGarradinCSV($path, $current_user_id) { if (!file_exists($path) || !is_readable($path)) { throw new \RuntimeException('Fichier inconnu : '.$path); } $fp = fopen($path, 'r'); |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Session.php from [b9cd12a177] to [f12dc2b07a].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin\Membres; use Garradin\Config; use Garradin\DB; use Garradin\Utils; use Garradin\Membres; use Garradin\UserException; use const Garradin\SECRET_KEY; use const Garradin\WWW_URL; use const Garradin\ADMIN_URL; | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace Garradin\Membres; use Garradin\Config; use Garradin\DB; use Garradin\Utils; use Garradin\Membres; use Garradin\UserException; use const Garradin\SECRET_KEY; use const Garradin\WWW_URL; use const Garradin\ADMIN_URL; use KD2\Security; use KD2\Security_OTP; use KD2\QRCode; class Session extends \KD2\UserSession { |
︙ | ︙ | |||
108 109 110 111 112 113 114 | protected function deleteAllRememberMeSelectors($user_id) { return $this->db->delete('membres_sessions', $this->db->where('id_membre', $user_id)); } // Ajout de la gestion de LOCAL_LOGIN | | | > > | > | 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 | protected function deleteAllRememberMeSelectors($user_id) { return $this->db->delete('membres_sessions', $this->db->where('id_membre', $user_id)); } // Ajout de la gestion de LOCAL_LOGIN public function isLogged($disable_local_login = false) { $logged = parent::isLogged(); if (!$disable_local_login && defined('\Garradin\LOCAL_LOGIN') && is_int(\Garradin\LOCAL_LOGIN) && \Garradin\LOCAL_LOGIN > 0) { if (!$logged || ($logged && $this->user->id != \Garradin\LOCAL_LOGIN)) { $logged = $this->create(\Garradin\LOCAL_LOGIN); } } return $logged; } // Ici checkOTP utilise NTP en second recours public function checkOTP($secret, $code) |
︙ | ︙ | |||
189 190 191 192 193 194 195 | $query = sprintf('%s.%s.%s', $id, $expire, $hash); $message = "Bonjour,\n\nVous avez oublié votre mot de passe ? Pas de panique !\n\n"; $message.= "Il vous suffit de cliquer sur le lien ci-dessous pour recevoir un nouveau mot de passe.\n\n"; $message.= ADMIN_URL . 'password.php?c=' . $query; $message.= "\n\nSi vous n'avez pas demandé à recevoir ce message, ignorez-le, votre mot de passe restera inchangé."; | | < | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | $query = sprintf('%s.%s.%s', $id, $expire, $hash); $message = "Bonjour,\n\nVous avez oublié votre mot de passe ? Pas de panique !\n\n"; $message.= "Il vous suffit de cliquer sur le lien ci-dessous pour recevoir un nouveau mot de passe.\n\n"; $message.= ADMIN_URL . 'password.php?c=' . $query; $message.= "\n\nSi vous n'avez pas demandé à recevoir ce message, ignorez-le, votre mot de passe restera inchangé."; return Utils::sendEmail($membre->email, 'Mot de passe perdu ?', $message, $membre->id, $membre->clef_pgp); } static public function recoverPasswordConfirm($code) { if (substr_count($code, '.') !== 2) { return false; |
︙ | ︙ | |||
241 242 243 244 245 246 247 | $message.= "Votre nouveau mot de passe : ".$password."\n\n"; $message.= "Si vous n'avez pas demandé à recevoir ce message, merci de nous le signaler."; $password = Membres::hashPassword($password); $db->update('membres', ['passe' => $password], 'id = :id', ['id' => (int)$id]); | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | $message.= "Votre nouveau mot de passe : ".$password."\n\n"; $message.= "Si vous n'avez pas demandé à recevoir ce message, merci de nous le signaler."; $password = Membres::hashPassword($password); $db->update('membres', ['passe' => $password], 'id = :id', ['id' => (int)$id]); return Utils::sendEmail($membre->email, 'Nouveau mot de passe', $message, $membre->id, $membre->clef_pgp); } public function editUser($data) { (new Membres)->edit($this->user->id, $data, false); $this->refresh(); |
︙ | ︙ | |||
286 287 288 289 290 291 292 | return $out; } public function sendMessage($dest, $sujet, $message, $copie = false) { $user = $this->getUser(); | < > | | < | | | | 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 | return $out; } public function sendMessage($dest, $sujet, $message, $copie = false) { $user = $this->getUser(); $content = "Ce message vous a été envoyé par :\n"; $content.= sprintf("%s\n%s\n\n", $user->identite, $user->email); $content.= str_repeat('=', 70) . "\n\n"; $content.= $message; if ($copie) { Utils::sendEmail($user->email, $sujet, $content, $user->id); } return Utils::sendEmail($dest, $sujet, $content); } public function editSecurity(Array $data = []) { $allowed_fields = ['passe', 'clef_pgp', 'secret_otp']; foreach ($data as $key=>$value) |
︙ | ︙ |
Modified src/include/lib/Garradin/Plugin.php from [a13d03f59d] to [0e12346d98].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; class Plugin { protected $id = null; protected $plugin = null; protected $config_changed = false; protected $mimes = [ 'css' => 'text/css', 'gif' => 'image/gif', | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php namespace Garradin; class Plugin { const PLUGIN_ID_SYNTAX = '[a-z]+(?:_[a-z]+)*'; protected $id = null; protected $plugin = null; protected $config_changed = false; protected $mimes = [ 'css' => 'text/css', 'gif' => 'image/gif', |
︙ | ︙ | |||
21 22 23 24 25 26 27 | 'pdf' => 'application/pdf', 'png' => 'image/png', 'swf' => 'application/shockwave-flash', 'xml' => 'text/xml', 'svg' => 'image/svg+xml', ]; | < < | > > | > > > | 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 | 'pdf' => 'application/pdf', 'png' => 'image/png', 'swf' => 'application/shockwave-flash', 'xml' => 'text/xml', 'svg' => 'image/svg+xml', ]; static public function getPath($id, $fail_with_exception = true) { if (file_exists(PLUGINS_ROOT . '/' . $id . '.tar.gz')) { return 'phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz'; } elseif (is_dir(PLUGINS_ROOT . '/' . $id)) { return PLUGINS_ROOT . '/' . $id; } if ($fail_with_exception) { throw new \LogicException(sprintf('Le plugin "%s" n\'existe pas dans le répertoire des plugins.', $id)); } return false; } /** * Construire un objet Plugin pour un plugin * @param string $id Identifiant du plugin * @throws UserException Si le plugin n'est pas installé (n'existe pas en DB) */ |
︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 | $this->plugin->config = json_decode($this->plugin->config); if (!is_object($this->plugin->config)) { $this->plugin->config = new \stdClass; } $this->id = $id; } /** * Enregistrer les changements dans la config */ | > > > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | $this->plugin->config = json_decode($this->plugin->config); if (!is_object($this->plugin->config)) { $this->plugin->config = new \stdClass; } // Juste pour vérifier que le fichier source du plugin existe bien self::getPath($id); $this->id = $id; } /** * Enregistrer les changements dans la config */ |
︙ | ︙ | |||
186 187 188 189 190 191 192 | $file = preg_replace('!^[./]*!', '', $file); if (preg_match('!(?:\.\.|[/\\\\]\.|\.[/\\\\])!', $file)) { throw new \RuntimeException('Chemin de fichier incorrect.'); } | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | $file = preg_replace('!^[./]*!', '', $file); if (preg_match('!(?:\.\.|[/\\\\]\.|\.[/\\\\])!', $file)) { throw new \RuntimeException('Chemin de fichier incorrect.'); } $forbidden = ['install.php', 'garradin_plugin.ini', 'upgrade.php', 'uninstall.php']; if (in_array($file, $forbidden)) { throw new UserException('Le fichier ' . $file . ' ne peut être appelé par cette méthode.'); } if (!file_exists($this->path() . '/www/' . $file)) |
︙ | ︙ | |||
258 259 260 261 262 263 264 | * Renvoie TRUE si le plugin a besoin d'être mis à jour * (si la version notée dans la DB est différente de la version notée dans garradin_plugin.ini) * @return boolean TRUE si le plugin doit être mis à jour, FALSE sinon */ public function needUpgrade() { $infos = (object) parse_ini_file($this->path() . '/garradin_plugin.ini', false); | | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | * Renvoie TRUE si le plugin a besoin d'être mis à jour * (si la version notée dans la DB est différente de la version notée dans garradin_plugin.ini) * @return boolean TRUE si le plugin doit être mis à jour, FALSE sinon */ public function needUpgrade() { $infos = (object) parse_ini_file($this->path() . '/garradin_plugin.ini', false); if (version_compare($this->plugin->version, $infos->version, '!=')) return true; return false; } /** |
︙ | ︙ | |||
280 281 282 283 284 285 286 | { $plugin = $this; include $this->path() . '/upgrade.php'; } $infos = (object) parse_ini_file($this->path() . '/garradin_plugin.ini', false); | | > > > > | < > > | < > > > > > > > > | 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 | { $plugin = $this; include $this->path() . '/upgrade.php'; } $infos = (object) parse_ini_file($this->path() . '/garradin_plugin.ini', false); return DB::getInstance()->update('plugins', [ 'nom' => $infos->nom, 'description'=> $infos->description, 'auteur' => $infos->auteur, 'url' => $infos->url, 'version' => $infos->version, 'menu' => (int)(bool)$infos->menu, 'menu_condition' => $infos->menu && isset($infos->menu_condition) ? trim($infos->menu_condition) : null, ], 'id = :id', ['id' => $this->id]); } /** * Associer un signal à un callback du plugin * @param string $signal Nom du signal (par exemple boucle.agenda pour la boucle de type AGENDA) * @param mixed $callback Callback, sous forme d'un nom de fonction ou de méthode statique * @return boolean TRUE */ public function registerSignal($signal, $callback) { $callable_name = ''; if (!is_callable($callback, true, $callable_name) || !is_string($callable_name)) { throw new \LogicException('Le callback donné n\'est pas valide.'); } // pour empêcher d'appeler des méthodes de Garradin après un import de base de données "hackée" if (strpos($callable_name, 'Garradin\\Plugin\\') !== 0) { throw new \LogicException('Le callback donné n\'utilise pas le namespace Garradin\\Plugin'); } $db = DB::getInstance(); // Signaux exclusifs, qui ne peuvent être attribués qu'à un seul plugin if (strpos($signal, 'boucle.') === 0) { $registered = $db->firstColumn('SELECT plugin FROM plugins_signaux WHERE signal = ? AND plugin != ?;', $signal, $this->id); if ($registered) { throw new \LogicException('Le signal ' . $signal . ' est exclusif et déjà associé au plugin "'.$registered.'"'); } } $callable_name = str_replace('Garradin\\Plugin\\', '', $callable_name); $st = $db->prepare('INSERT OR REPLACE INTO plugins_signaux VALUES (:signal, :plugin, :callback);'); $st->bindValue(':signal', $signal); $st->bindValue(':plugin', $this->id); $st->bindValue(':callback', $callable_name); return $st->execute(); } |
︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 346 347 348 | $db = DB::getInstance(); $plugins = $db->getGrouped('SELECT id, * FROM plugins ORDER BY nom;'); $system = explode(',', PLUGINS_SYSTEM); foreach ($plugins as &$row) { $row->system = in_array($row->id, $system); } return $plugins; } /** * Vérifie que les plugins système sont bien installés et sinon les réinstalle | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | $db = DB::getInstance(); $plugins = $db->getGrouped('SELECT id, * FROM plugins ORDER BY nom;'); $system = explode(',', PLUGINS_SYSTEM); foreach ($plugins as &$row) { $row->system = in_array($row->id, $system); $row->disabled = !self::getPath($row->id, false); } return $plugins; } /** * Vérifie que les plugins système sont bien installés et sinon les réinstalle |
︙ | ︙ | |||
375 376 377 378 379 380 381 | return true; } /** * Liste les plugins qui doivent être affichés dans le menu * @return array Tableau associatif id => nom (ou un tableau vide si aucun plugin ne doit être affiché) */ | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 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 | return true; } /** * Liste les plugins qui doivent être affichés dans le menu * @return array Tableau associatif id => nom (ou un tableau vide si aucun plugin ne doit être affiché) */ static public function listMenu($user) { $db = DB::getInstance(); $list = $db->getGrouped('SELECT id, nom, menu_condition FROM plugins WHERE menu = 1 ORDER BY nom;'); foreach ($list as $id => &$row) { if (!self::getPath($row->id, false)) { // Ne pas lister les plugins dont le code a disparu continue; } if (!$row->menu_condition) { $row = $row->nom; continue; } $condition = strtr($row->menu_condition, [ '{Membres::DROIT_AUCUN}' => Membres::DROIT_AUCUN, '{Membres::DROIT_ACCES}' => Membres::DROIT_ACCES, '{Membres::DROIT_ECRITURE}' => Membres::DROIT_ECRITURE, '{Membres::DROIT_ADMIN}' => Membres::DROIT_ADMIN, ]); $condition = preg_replace_callback('/\{\$user\.(\w+)\}/', function ($m) use ($user) { return $user->{$m[1]}; }, $condition); $query = 'SELECT 1 WHERE ' . $condition . ';'; $st = $db->prepare($query); if (!$st->readOnly()) { throw new \LogicException('Requête plugin pour affichage dans le menu n\'est pas en lecture : ' . $query); } $res = $st->execute(); if (!$res->fetchArray(\SQLITE3_NUM)) { unset($list[$id]); continue; } $row = $row->nom; } unset($row); return $list; } /** * Liste les plugins téléchargés mais non installés * @return array Liste des plugins téléchargés */ static public function listDownloaded() { $installed = self::listInstalled(); $list = []; $dir = dir(PLUGINS_ROOT); while ($file = $dir->read()) { if (substr($file, 0, 1) == '.') continue; if (preg_match('!^(' . self::PLUGIN_ID_SYNTAX . ')\.tar\.gz$!', $file, $match)) { // Sélectionner les archives PHAR $file = $match[1]; } elseif (is_dir(PLUGINS_ROOT . '/' . $file) && preg_match('!^' . self::PLUGIN_ID_SYNTAX . '$!', $file) && is_file(sprintf('%s/%s/garradin_plugin.ini', PLUGINS_ROOT, $file))) { // Rien à faire, le nom valide du plugin est déjà dans "$file" } else { // ignorer tout ce qui n'est pas un répertoire ou une archive PHAR valides |
︙ | ︙ | |||
635 636 637 638 639 640 641 642 643 644 645 646 647 648 | 'officiel' => (int)(bool)$official, 'nom' => $infos->nom, 'description'=> $infos->description, 'auteur' => $infos->auteur, 'url' => $infos->url, 'version' => $infos->version, 'menu' => (int)(bool)$infos->menu, 'config' => $config, ]); if (file_exists($path . '/install.php')) { $plugin = new Plugin($id); require $plugin->path() . '/install.php'; | > | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | 'officiel' => (int)(bool)$official, 'nom' => $infos->nom, 'description'=> $infos->description, 'auteur' => $infos->auteur, 'url' => $infos->url, 'version' => $infos->version, 'menu' => (int)(bool)$infos->menu, 'menu_condition' => $infos->menu && isset($infos->menu_condition) ? trim($infos->menu_condition) : null, 'config' => $config, ]); if (file_exists($path . '/install.php')) { $plugin = new Plugin($id); require $plugin->path() . '/install.php'; |
︙ | ︙ | |||
665 666 667 668 669 670 671 | /** * Déclenche le signal donné auprès des plugins enregistrés * @param string $signal Nom du signal * @param array $params Paramètres du callback (array ou null) * @return NULL NULL si aucun plugin n'a été appelé, true sinon */ | | | | < < | < | < | | > | | 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | /** * Déclenche le signal donné auprès des plugins enregistrés * @param string $signal Nom du signal * @param array $params Paramètres du callback (array ou null) * @return NULL NULL si aucun plugin n'a été appelé, true sinon */ static public function fireSignal($signal, $params = null, &$callback_return = null) { $list = DB::getInstance()->get('SELECT * FROM plugins_signaux WHERE signal = ?;', $signal); foreach ($list as $row) { $return = call_user_func_array('Garradin\\Plugin\\' . $row->callback, [&$params, &$callback_return]); if ($return) { return $return; } } return !empty($list) ? false : null; } } |
Modified src/include/lib/Garradin/Rappels_Envoyes.php from [4ab2f9f384] to [7f341d0949].
︙ | ︙ | |||
146 147 148 149 150 151 152 | $replace['nb_jours'] = abs($replace['nb_jours']); $replace['delai'] = abs($replace['delai']); $subject = $this->replaceTagsInContent($data->sujet, $replace); $text = $this->replaceTagsInContent($data->texte, $replace); // Envoi du mail | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | $replace['nb_jours'] = abs($replace['nb_jours']); $replace['delai'] = abs($replace['delai']); $subject = $this->replaceTagsInContent($data->sujet, $replace); $text = $this->replaceTagsInContent($data->texte, $replace); // Envoi du mail Utils::sendEmail($data->email, $subject, $text, $data->id); // Enregistrement en DB $this->add([ 'id_cotisation' => $data->id_cotisation, 'id_membre' => $data->id, 'id_rappel' => $data->id_rappel, 'media' => Rappels_Envoyes::MEDIA_EMAIL, |
︙ | ︙ |
Modified src/include/lib/Garradin/Squelette_Filtres.php from [b4203fb585] to [a2925f4fde].
︙ | ︙ | |||
251 252 253 254 255 256 257 | static public function supprimer_tags($value, $replace = '') { return preg_replace('!<[^>]*>!', $replace, $value); } static public function supprimer_skriv($value) { | < < < | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | static public function supprimer_tags($value, $replace = '') { return preg_replace('!<[^>]*>!', $replace, $value); } static public function supprimer_skriv($value) { $value = self::formatter_texte($value); return self::supprimer_tags($value); } static public function couper($texte, $taille, $etc = ' (...)') { if (strlen($texte) > $taille) { $texte = substr($texte, 0, $taille); |
︙ | ︙ |
Modified src/include/lib/Garradin/Template.php from [8050b58d78] to [f146e5dca4].
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 | private function __clone() { } public function __construct() { if (!file_exists(CACHE_ROOT . '/compiled')) { mkdir(CACHE_ROOT . '/compiled', 0777, true); } | > > > | < | > > > > > > | 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 | private function __clone() { } public function __construct() { parent::__construct(); if (!file_exists(CACHE_ROOT . '/compiled')) { mkdir(CACHE_ROOT . '/compiled', 0777, true); } $this->setTemplatesDir(ROOT . '/templates'); $this->setCompiledDir(CACHE_ROOT . '/compiled'); // Hash de la version pour les éléments statiques (cache) // On ne peut pas utiliser la version directement comme query string // pour les éléments statiques (genre /admin/static/admin.css?v0.9.0) // car cela dévoilerait la version de Garradin utilisée, posant un souci // en cas de faille, on cache donc la version utilisée, chaque instance // aura sa propre version $this->assign('version_hash', substr(sha1(VERSION . ROOT . SECRET_KEY), 0, 10)); $this->assign('www_url', WWW_URL); $this->assign('self_url', Utils::getSelfUrl()); $this->assign('self_url_no_qs', Utils::getSelfUrl(false)); $this->assign('is_logged', false); |
︙ | ︙ |
Modified src/include/lib/Garradin/Utils.php from [4680da7c34] to [df58911e4f].
︙ | ︙ | |||
371 372 373 374 375 376 377 | $str = preg_replace('/<em>(\V*?)<\/em>/', '\'\'$1\'\'', $str); $str = preg_replace('/<li>(\V*?)<\/li>/', '* $1', $str); $str = preg_replace('/<ul>|<\/ul>/', '', $str); $str = preg_replace('/<a href="([^"]*?)">(\V*?)<\/a>/', '[[$2 | $1]]', $str); return $str; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | $str = preg_replace('/<em>(\V*?)<\/em>/', '\'\'$1\'\'', $str); $str = preg_replace('/<li>(\V*?)<\/li>/', '* $1', $str); $str = preg_replace('/<ul>|<\/ul>/', '', $str); $str = preg_replace('/<a href="([^"]*?)">(\V*?)<\/a>/', '[[$2 | $1]]', $str); return $str; } static public function clearCaches($path = false) { if (!$path) { self::clearCaches('compiled'); self::clearCaches('static'); return true; } $path = CACHE_ROOT . '/' . $path; $dir = dir($path); while ($file = $dir->read()) { if ($file[0] != '.') { if (file_exists($path . DIRECTORY_SEPARATOR . $file)) { @unlink($path . DIRECTORY_SEPARATOR . $file); } } } $dir->close(); return true; } |
︙ | ︙ | |||
739 740 741 742 743 744 745 | array_walk($row, function (&$field) { $field = strtr($field, ['"' => '""', "\r\n" => "\n"]); }); return sprintf("\"%s\"\r\n", implode('","', $row)); } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | array_walk($row, function (&$field) { $field = strtr($field, ['"' => '""', "\r\n" => "\n"]); }); return sprintf("\"%s\"\r\n", implode('","', $row)); } static public function sendEmail($recipient, $subject, $content, $id_membre = null, $pgp_key = null) { // Ne pas envoyer de mail à des adresses invalides if (!SMTP::checkEmailIsValid($recipient, false)) { throw new UserException('Adresse email invalide: ' . $recipient); } $config = Config::getInstance(); $subject = sprintf('[%s] %s', $config->get('nom_asso'), $subject); // Tentative d'envoi du message en utilisant un plugin $email_sent_via_plugin = Plugin::fireSignal('email.envoi', compact('recipient', 'subject', 'content', 'id_membre', 'pgp_key')); if (!$email_sent_via_plugin) { // L'envoi d'email n'a pas été effectué par un plugin, utilisons l'envoi interne // via mail() ou SMTP donc return self::mail($recipient, $subject, $content, $id_membre, $pgp_key); } return true; } static public function mail($to, $subject, $content, $id_membre, $pgp_key) { $headers = []; $config = Config::getInstance(); $content = wordwrap($content); $content = trim($content); $content .= sprintf("\n\n-- \n%s\n%s\n\n", $config->get('nom_asso'), $config->get('site_asso')); $content .= "Vous recevez ce message car vous êtes inscrit comme membre de\nl'association.\n"; $content .= "Pour ne plus recevoir de message de notre part merci de nous contacter :\n" . $config->get('email_asso'); $content = preg_replace("#(?<!\r)\n#si", "\r\n", $content); if ($pgp_key) { $content = Security::encryptWithPublicKey($pgp_key, $content); } $headers['From'] = sprintf('"%s" <%s>', sprintf('=?UTF-8?B?%s?=', base64_encode($config->get('nom_asso'))), $config->get('email_asso')); $headers['Return-Path'] = $config->get('email_asso'); $headers['MIME-Version'] = '1.0'; $headers['Content-type'] = 'text/plain; charset=UTF-8'; $hash = sha1(uniqid() . var_export([$headers, $to, $subject, $content], true)); $headers['Message-ID'] = sprintf('%s@%s', $hash, isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : gethostname()); if (SMTP_HOST) { $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.'); } $secure = constant($const); $smtp = new SMTP(SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD, $secure); return $smtp->send($to, $subject, $content, $headers); } else { // Encodage du sujet $subject = sprintf('=?UTF-8?B?%s?=', base64_encode($subject)); $raw_headers = ''; // Sérialisation des entêtes foreach ($headers as $name=>$value) { $raw_headers .= sprintf("%s: %s\r\n", $name, $value); } return \mail($to, $subject, $content, $raw_headers); } } } |
Modified src/templates/admin/_head.tpl from [aa97d73757] to [fbf813131c].
1 2 3 4 5 6 7 | <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <meta charset="utf-8" /> <title>{$title}</title> <link rel="icon" type="image/png" href="{$admin_url}static/icon.png" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, target-densitydpi=device-dpi" /> | | | | | | | | | | 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 | <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <meta charset="utf-8" /> <title>{$title}</title> <link rel="icon" type="image/png" href="{$admin_url}static/icon.png" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, target-densitydpi=device-dpi" /> <link rel="stylesheet" type="text/css" href="{$admin_url}static/admin.css?{$version_hash}1" media="all" /> {if isset($js) || isset($custom_js)} <script type="text/javascript" src="{$admin_url}static/scripts/global.js?{$version_hash}"></script> {/if} {if isset($custom_js)} {foreach from=$custom_js item="js"} <script type="text/javascript" src="{$admin_url}static/scripts/{$js}?{$version_hash}"></script> {/foreach} {/if} {if isset($custom_css)} {foreach from=$custom_css item="css"} <link rel="stylesheet" type="text/css" href="{$admin_url}static/{$css}?{$version_hash}" media="all" /> {/foreach} {/if} {if isset($plugin_css)} {foreach from=$plugin_css item="css"} <link rel="stylesheet" type="text/css" href="{plugin_url file=$css}?{$version_hash}" /> {/foreach} {/if} {if isset($plugin_js)} {foreach from=$plugin_js item="js"} <script type="text/javascript" src="{plugin_url file=$js}?{$version_hash}"></script> {/foreach} {/if} <link rel="stylesheet" type="text/css" href="{$admin_url}static/print.css?{$version_hash}" media="print" /> <link rel="stylesheet" type="text/css" href="{$admin_url}static/handheld.css?{$version_hash}" media="handheld,screen and (max-width:981px)" /> {if isset($config)} {custom_colors config=$config} {/if} </head> <body{if !empty($body_id)} id="{$body_id}"{/if} data-url="{$admin_url}"> |
︙ | ︙ | |||
65 66 67 68 69 70 71 | </li> {if $session->canAccess('membres', Garradin\Membres::DROIT_ACCES)} <li class="member list{if $current == 'membres'} current{elseif $current_parent == 'membres'} current_parent{/if}"><a href="{$admin_url}membres/"><b class="icn">👪</b><i> Membres</i></a> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)} <ul> <li class="member new{if $current == 'membres/ajouter'} current{/if}"><a href="{$admin_url}membres/ajouter.php">Ajouter</a></li> <li class="member cotisations{if $current == 'membres/cotisations'} current{/if}"><a href="{$admin_url}membres/cotisations/">Cotisations</a></li> | < < < < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | </li> {if $session->canAccess('membres', Garradin\Membres::DROIT_ACCES)} <li class="member list{if $current == 'membres'} current{elseif $current_parent == 'membres'} current_parent{/if}"><a href="{$admin_url}membres/"><b class="icn">👪</b><i> Membres</i></a> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)} <ul> <li class="member new{if $current == 'membres/ajouter'} current{/if}"><a href="{$admin_url}membres/ajouter.php">Ajouter</a></li> <li class="member cotisations{if $current == 'membres/cotisations'} current{/if}"><a href="{$admin_url}membres/cotisations/">Cotisations</a></li> </ul> {/if} </li> {/if} {if $session->canAccess('compta', Garradin\Membres::DROIT_ACCES)} <li class="compta{if $current == 'compta'} current{elseif $current_parent == 'compta'} current_parent{/if}"><a href="{$admin_url}compta/"><b>€</b><i> Comptabilité</i></a> <ul> |
︙ | ︙ |
Modified src/templates/admin/config/_menu.tpl from [b62a4fdea8] to [53db92aa96].
1 | <ul class="actions"> | | > | | | < | | 1 2 3 4 5 6 7 8 | <ul class="actions"> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/">Général</a></li> <li{if $current == 'categories'} class="current"{/if}><a href="{$admin_url}config/categories/">Catégories de membres</a></li> <li{if $current == 'fiches_membres'} class="current"{/if}><a href="{$admin_url}config/membres.php">Fiche des membres</a></li> <li{if $current == 'site'} class="current"{/if}><a href="{$admin_url}config/site.php">Site public</a></li> <li{if $current == 'donnees'} class="current"{/if}><a href="{$admin_url}config/donnees/">Sauvegarde et restauration</a></li> <li{if $current == 'plugins'} class="current"{/if}><a href="{$admin_url}config/plugins.php">Extensions</a></li> </ul> |
Added src/templates/admin/config/categories/index.tpl version [7ab8e26a24].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | {include file="admin/_head.tpl" title="Catégories de membres" current="config"} {include file="admin/config/_menu.tpl" current="categories"} <table class="list"> <thead> <th>Nom</th> <td class="num">Membres</td> <td>Droits</td> <td></td> </thead> <tbody> {foreach from=$liste item="cat"} <tr> <th>{$cat.nom}</th> <td class="num">{$cat.nombre}</td> <td class="droits"> {format_droits droits=$cat} </td> <td class="actions"> <a class="icn" href="{$admin_url}membres/?cat={$cat.id}" title="Liste des membres">👪</a> <a class="icn" href="{$admin_url}config/categories/modifier.php?id={$cat.id}" title="Modifier">✎</a> {if $cat.id != $user.id_categorie} <a class="icn" href="{$admin_url}config/categories/supprimer.php?id={$cat.id}" title="Supprimer">✘</a> {/if} </td> </tr> {/foreach} </tbody> </table> <form method="post" action="{$self_url}"> <fieldset> <legend>Ajouter une catégorie</legend> <dl> <dt><label for="f_nom">Nom</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="nom" id="f_nom" value="{form_field name=nom}" required="required" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="new_cat"} <input type="submit" name="save" value="Enregistrer →" /> </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/admin/config/categories/modifier.tpl version [7b22c4c7fb].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | {include file="admin/_head.tpl" title="Modifier une catégorie de membre" current="config"} {include file="admin/config/_menu.tpl" current="categories"} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Informations générales</legend> <dl> <dt><label for="f_nom">Nom</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="nom" id="f_nom" value="{form_field data=$cat name=nom}" required="required" /></dd> <dt> <input type="checkbox" name="cacher" value="1" id="f_cacher" {if $cat.cacher}checked="checked"{/if} /> <label for="f_cacher">Catégorie cachée</label> </dt> <dd class="help"> Si coché cette catégorie ne sera visible qu'aux administrateurs et ne recevra pas de messages collectifs ou de rappels. </dd> </dl> </fieldset> <fieldset> <legend>Cotisation obligatoire</legend> <dl> <dt><label for="f_id_cotisation_obligatoire">Cotisation obligatoire</label></dt> <dd> <select name="id_cotisation_obligatoire" id="f_id_cotisation_obligatoire"> <option value="">-- Non</option> {foreach from=$cotisations item="cotisation"} <option value="{$cotisation.id}" {form_field name="id_cotisation_obligatoire" selected=$cotisation.id data=$cat}> {$cotisation.intitule} — {$cotisation.montant|escape|html_money} {$config.monnaie} — {if $cotisation.duree}pour {$cotisation.duree} jours {elseif $cotisation.debut} du {$cotisation.debut|format_sqlite_date_to_french} au {$cotisation.fin|format_sqlite_date_to_french} {else} ponctuelle {/if} </option> {/foreach} </select> </dd> </dl> </fieldset> <fieldset> <legend>Droits</legend> <dl class="droits"> <dt><label for="f_droit_connexion_aucun">Les membres de cette catégorie peuvent-ils se connecter ?</label></dt> {if $readonly} <dd class="help"> Il n'est pas possible de désactiver ce droit pour votre propre catégorie. </dd> {/if} <dd> <input type="radio" name="droit_connexion" value="{$membres::DROIT_AUCUN}" id="f_droit_connexion_aucun" {if $cat.droit_connexion == $membres::DROIT_AUCUN}checked="checked"{/if} {$readonly} /> <label for="f_droit_connexion_aucun"><b class="aucun">C</b> Non</label> </dd> <dd> <input type="radio" name="droit_connexion" value="{$membres::DROIT_ACCES}" id="f_droit_connexion_acces" {if $cat.droit_connexion == $membres::DROIT_ACCES}checked="checked"{/if} {$readonly} /> <label for="f_droit_connexion_acces"><b class="acces">C</b> Oui</label> </dd> </dl> <dl class="droits"> <dt><label for="f_droit_inscription_aucun">Les membres de cette catégorie peuvent-ils s'inscrire d'eux-même ?</label></dt> <dd> <input type="radio" name="droit_inscription" value="{$membres::DROIT_AUCUN}" id="f_droit_inscription_aucun" {if $cat.droit_inscription == $membres::DROIT_AUCUN}checked="checked"{/if} /> <label for="f_droit_inscription_aucun"><b class="aucun">I</b> Non</label> </dd> <dd> <input type="radio" name="droit_inscription" value="{$membres::DROIT_ACCES}" id="f_droit_inscription_acces" {if $cat.droit_inscription == $membres::DROIT_ACCES}checked="checked"{/if} /> <label for="f_droit_inscription_acces"><b class="acces">I</b> Oui</label> </dd> </dl> <dl class="droits"> <dt><label for="f_droit_membres_aucun">Gestion des membres :</label></dt> <dd> <input type="radio" name="droit_membres" value="{$membres::DROIT_AUCUN}" id="f_droit_membres_aucun" {if $cat.droit_membres == $membres::DROIT_AUCUN}checked="checked"{/if} /> <label for="f_droit_membres_aucun"><b class="aucun">M</b> Pas d'accès</label> </dd> <dd> <input type="radio" name="droit_membres" value="{$membres::DROIT_ACCES}" id="f_droit_membres_acces" {if $cat.droit_membres == $membres::DROIT_ACCES}checked="checked"{/if} /> <label for="f_droit_membres_acces"><b class="acces">M</b> Lecture uniquement</label> </dd> <dd> <input type="radio" name="droit_membres" value="{$membres::DROIT_ECRITURE}" id="f_droit_membres_ecriture" {if $cat.droit_membres == $membres::DROIT_ECRITURE}checked="checked"{/if} /> <label for="f_droit_membres_ecriture"><b class="ecriture">M</b> Lecture & écriture</label> </dd> <dd> <input type="radio" name="droit_membres" value="{$membres::DROIT_ADMIN}" id="f_droit_membres_admin" {if $cat.droit_membres == $membres::DROIT_ADMIN}checked="checked"{/if} /> <label for="f_droit_membres_admin"><b class="admin">M</b> Administration</label> </dd> </dl> <dl class="droits"> <dt><label for="f_droit_compta_aucun">Comptabilité :</label></dt> <dd> <input type="radio" name="droit_compta" value="{$membres::DROIT_AUCUN}" id="f_droit_compta_aucun" {if $cat.droit_compta == $membres::DROIT_AUCUN}checked="checked"{/if} /> <label for="f_droit_compta_aucun"><b class="aucun">€</b> Pas d'accès</label> </dd> <dd> <input type="radio" name="droit_compta" value="{$membres::DROIT_ACCES}" id="f_droit_compta_acces" {if $cat.droit_compta == $membres::DROIT_ACCES}checked="checked"{/if} /> <label for="f_droit_compta_acces"><b class="acces">€</b> Lecture uniquement</label> </dd> <dd> <input type="radio" name="droit_compta" value="{$membres::DROIT_ECRITURE}" id="f_droit_compta_ecriture" {if $cat.droit_compta == $membres::DROIT_ECRITURE}checked="checked"{/if} /> <label for="f_droit_compta_ecriture"><b class="ecriture">€</b> Lecture & écriture</label> </dd> <dd> <input type="radio" name="droit_compta" value="{$membres::DROIT_ADMIN}" id="f_droit_compta_admin" {if $cat.droit_compta == $membres::DROIT_ADMIN}checked="checked"{/if} /> <label for="f_droit_compta_admin"><b class="admin">€</b> Administration</label> </dd> </dl> <dl class="droits"> <dt><label for="f_droit_wiki_aucun">Wiki :</label></dt> <dd> <input type="radio" name="droit_wiki" value="{$membres::DROIT_AUCUN}" id="f_droit_wiki_aucun" {if $cat.droit_wiki == $membres::DROIT_AUCUN}checked="checked"{/if} /> <label for="f_droit_wiki_aucun"><b class="aucun">W</b> Pas d'accès</label> </dd> <dd> <input type="radio" name="droit_wiki" value="{$membres::DROIT_ACCES}" id="f_droit_wiki_acces" {if $cat.droit_wiki == $membres::DROIT_ACCES}checked="checked"{/if} /> <label for="f_droit_wiki_acces"><b class="acces">W</b> Lecture uniquement</label> </dd> <dd> <input type="radio" name="droit_wiki" value="{$membres::DROIT_ECRITURE}" id="f_droit_wiki_ecriture" {if $cat.droit_wiki == $membres::DROIT_ECRITURE}checked="checked"{/if} /> <label for="f_droit_wiki_ecriture"><b class="ecriture">W</b> Lecture & écriture</label> </dd> <dd> <input type="radio" name="droit_wiki" value="{$membres::DROIT_ADMIN}" id="f_droit_wiki_admin" {if $cat.droit_wiki == $membres::DROIT_ADMIN}checked="checked"{/if} /> <label for="f_droit_wiki_admin"><b class="admin">W</b> Administration</label> </dd> </dl> <dl class="droits"> <dt><label for="f_droit_config_aucun">Les membres de cette catégorie peuvent-ils modifier la configuration ?</label></dt> {if $readonly} <dd class="help"> Il n'est pas possible de désactiver ce droit pour votre propre catégorie. </dd> {/if} <dd> <input type="radio" name="droit_config" value="{$membres::DROIT_AUCUN}" id="f_droit_config_aucun" {if $cat.droit_config == $membres::DROIT_AUCUN}checked="checked"{/if} {$readonly} /> <label for="f_droit_config_aucun"><b class="aucun">☑</b> Non</label> </dd> <dd> <input type="radio" name="droit_config" value="{$membres::DROIT_ADMIN}" id="f_droit_config_admin" {if $cat.droit_config == $membres::DROIT_ADMIN}checked="checked"{/if} {$readonly} /> <label for="f_droit_config_admin"><b class="admin">☑</b> Oui</label> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="edit_cat_"|cat:$cat.id} <input type="submit" name="save" value="Enregistrer →" /> </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/admin/config/categories/supprimer.tpl version [9ebed2a419].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | {include file="admin/_head.tpl" title="Supprimer une catégorie de membre" current="config"} {include file="admin/config/_menu.tpl" current="categories"} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Supprimer la catégorie de membres ?</legend> <h3 class="warning"> Êtes-vous sûr de vouloir supprimer la catégorie « {$cat.nom} » ? </h3> <p class="help"> Attention, la catégorie ne doit plus contenir de membres pour pouvoir être supprimée. </p> <p class="help"> Notez que si des pages du wiki étaient restreintes à la lecture ou à l'écriture aux seuls membres de ce groupe, elles redeviendront lisibles et modifiables par tous les membres ayant accès au wiki ! </p> </fieldset> <p class="submit"> {csrf_field key="delete_cat_"|cat:$cat.id} <input type="submit" name="delete" value="Supprimer →" /> </p> </form> {include file="admin/_foot.tpl"} |
Deleted src/templates/admin/config/donnees.tpl version [396a0ea87b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added src/templates/admin/config/donnees/_menu.tpl version [c98481c3a3].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | <ul class="actions sub"> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/donnees/">Sauvegarder et restaurer</a></li> <li{if $current == 'import'} class="current"{/if}><a href="{$admin_url}config/donnees/import.php">Import et export</a></li> <li{if $current == 'local'} class="current"{/if}><a href="{$admin_url}config/donnees/local.php">Gestion des sauvegardes</a></li> {if Garradin\ENABLE_AUTOMATIC_BACKUPS} <li{if $current == 'automatique'} class="current"{/if}><a href="{$admin_url}config/donnees/automatique.php">Configuration de la sauvegarde automatique</a></li> {/if} <li{if $current == 'reset'} class="current"{/if}><a href="{$admin_url}config/donnees/reset.php">Remise à zéro</a></li> </ul> |
Added src/templates/admin/config/donnees/automatique.tpl version [1804eff257].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | {include file="admin/_head.tpl" title="Sauvegarde et restauration" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="automatique"} {form_errors} {if $ok == 'config'} <p class="confirm">La configuration a bien été enregistrée.</p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Configuration de la sauvegarde automatique</legend> <p class="help"> En activant cette option une sauvegarde sera automatiquement créée à chaque intervalle donné. Par exemple en activant une sauvegarde hebdomadaire, une copie des données sera réalisée une fois par semaine, sauf si aucune modification n'a été effectuée sur les données ou que personne ne s'est connecté. </p> <dl> <dt><label for="f_frequency">Intervalle de sauvegarde</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> <select name="frequence_sauvegardes" required="required" id="f_frequency"> <option value="0"{form_field name=frequence_sauvegardes data=$config selected=0}>Aucun — les sauvegardes automatiques sont désactivées</option> <option value="1"{form_field name=frequence_sauvegardes data=$config selected=1}>Quotidien, tous les jours</option> <option value="7"{form_field name=frequence_sauvegardes data=$config selected=7}>Hebdomadaire, tous les 7 jours</option> <option value="15"{form_field name=frequence_sauvegardes data=$config selected=15}>Bimensuel, tous les 15 jours</option> <option value="30"{form_field name=frequence_sauvegardes data=$config selected=30}>Mensuel</option> <option value="90"{form_field name=frequence_sauvegardes data=$config selected=90}>Trimestriel</option> <option value="365{form_field name=frequence_sauvegardes data=$config selected=365}">Annuel</option> </select> </dd> <dt><label for="f_max_backups">Nombre de sauvegardes conservées</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd class="help"> Par exemple avec l'intervalle mensuel, en indiquant de conserver 12 sauvegardes, vous pourrez garder un an d'historique de sauvegardes. </dd> <dd class="help"> <strong>Attention :</strong> si vous choisissez un nombre important et un intervalle réduit, l'espace disque occupé par vos sauvegardes va rapidement augmenter. </dd> <dd><input type="number" name="nombre_sauvegardes" value="{form_field name=nombre_sauvegardes data=$config}" if="f_max_backups" min="1" max="90" required="required" /></dd> </dl> <p> {csrf_field key="backup_config"} <input type="submit" name="config" value="Enregistrer →" /> </p> </fieldset> </form> {include file="admin/_foot.tpl"} |
Added src/templates/admin/config/donnees/import.tpl version [79252f8a0f].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | {include file="admin/_head.tpl" title="Import & export" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="import"} <fieldset> <dl> <dt>Membres</dt> <dd><a href="{$admin_url}membres/import.php">Import de la liste des membres</a></dd> <dd><a href="{$admin_url}membres/import.php?export=ods">Export de la liste des membres au format tableur Calc / Excel</a></dd> <dd><a href="{$admin_url}membres/import.php?export=csv">Export de la liste des membres au format CSV</a></dd> <dt>Comptabilité</dt> <dd><a href="{$admin_url}compta/import.php">Import des données comptables</a></dd> <dd><a href="{$admin_url}compta/import.php?export=ods">Export des données comptables au format tableur Calc / Excel</a></dd> <dd><a href="{$admin_url}compta/import.php?export=csv">Export des données comptables au format CSV</a></dd> </dl> </fieldset> {include file="admin/_foot.tpl"} |
Added src/templates/admin/config/donnees/index.tpl version [734344c866].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | {include file="admin/_head.tpl" title="Sauvegarde et restauration" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="index"} {form_errors} {if $code == Garradin\Sauvegarde::INTEGRITY_FAIL && Garradin\ALLOW_MODIFIED_IMPORT} <p class="alert">Pour passer outre, renvoyez le fichier en cochant la case « Ignorer les erreurs ». Attention, si vous avez effectué des modifications dans la base de données, cela peut créer des bugs !</p> {/if} {if $ok} <p class="confirm"> {if $ok == 'restore'}La restauration a bien été effectuée. Si vous désirez revenir en arrière, vous pouvez utiliser la sauvegarde automatique nommée <em>{$now_date}.avant_restauration.sqlite</em>, sinon vous pouvez l'effacer. {if $ok_code & Garradin\Sauvegarde::NOT_AN_ADMIN} </p> <p class="alert"> <strong>Vous n'êtes pas administrateur dans cette sauvegarde.</strong> Garradin a donné les droits d'administration à toutes les catégories afin d'empêcher de ne plus pouvoir se connecter. Merci de corriger les droits des catégories maintenant. {/if} {elseif $ok == 'remove'}La sauvegarde a été supprimée. {/if} </p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Téléchargement d'une sauvegarde</legend> <p class="help"> Info : la base de données fait actuellement {$db_size|format_bytes} (dont {$files_size|format_bytes} pour les documents et images). </p> <p> {csrf_field key="backup_download"} <input type="submit" name="download" value="Télécharger une copie de la base de données sur mon ordinateur →" /> </p> </fieldset> </form> <form method="post" action="{$self_url_no_qs}" enctype="multipart/form-data"> <fieldset> <legend><label for="f_file">Restaurer depuis un fichier de sauvegarde</label></legend> <p class="alert"> Attention, l'intégralité des données courantes seront effacées et remplacées par celles contenues dans le fichier fourni. </p> <p class="help"> Une sauvegarde des données courantes sera effectuée avant le remplacement, en cas de besoin d'annuler cette restauration. </p> <p> {csrf_field key="backup_restore"} <input type="hidden" name="MAX_FILE_SIZE" value="{$max_file_size}" /> <input type="file" name="file" id="f_file" required="required" /> (maximum {$max_file_size|format_bytes}) <input type="submit" name="restore_file" value="Restaurer depuis le fichier sélectionné →" /> </p> {if $code && ($code == Garradin\Sauvegarde::INTEGRITY_FAIL && Garradin\ALLOW_MODIFIED_IMPORT)} <p> <label><input type="checkbox" name="force_import" value="1" /> Ignorer les erreurs, je sais ce que je fait</label> </p> {/if} </fieldset> </form> {include file="admin/_foot.tpl"} |
Added src/templates/admin/config/donnees/local.tpl version [422efd646c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | {include file="admin/_head.tpl" title="Gestion des sauvegardes" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="local"} {form_errors} {if $ok} <p class="confirm"> {if $ok == 'create'}Une nouvelle sauvegarde a été créée. {elseif $ok == 'restore'}La restauration a bien été effectuée. Si vous désirez revenir en arrière, vous pouvez utiliser la sauvegarde automatique nommée <em>date-du-jour.avant_restauration.sqlite</em>, sinon vous pouvez l'effacer. {if $ok_code & Garradin\Sauvegarde::NOT_AN_ADMIN} </p> <p class="alert"> <strong>Vous n'êtes pas administrateur dans cette sauvegarde.</strong> Garradin a donné les droits d'administration à toutes les catégories afin d'empêcher de ne plus pouvoir se connecter. Merci de corriger les droits des catégories maintenant. {/if} {elseif $ok == 'remove'}La sauvegarde a été supprimée. {/if} </p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Copies de sauvegarde disponibles</legend> {if empty($liste)} <p class="help">Aucune copie de sauvegarde disponible.</p> {else} <dl> <dt><label for="f_select">Sélectionner une sauvegarde</label></dt> <dd> <select name="file" id="f_select"> {foreach from=$liste key="f" item="d"} <option value="{$f}">{$f} — {$d|date_fr:'d/m/Y à H:i'}</option> {/foreach} </select> </dd> <dd class="help"> Attention, en cas de restauration, l'intégralité des données courantes seront effacées et remplacées par celles contenues dans la sauvegarde sélectionnée. Cependant, afin de prévenir toute erreur une sauvegarde des données sera réalisée avant la restauration. </dd> </dl> <p> {csrf_field key="backup_manage"} <input type="submit" name="restore" value="Restaurer cette sauvegarde" /> <input type="submit" name="remove" value="Supprimer cette sauvegarde" /> </p> {/if} </fieldset> </form> <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Sauvegarde manuelle</legend> <p> {csrf_field key="backup_create"} <input type="submit" name="create" value="Créer une nouvelle sauvegarde des données →" /> </p> </fieldset> </form> {include file="admin/_foot.tpl"} |
Added src/templates/admin/config/donnees/reset.tpl version [b44198b72b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | {include file="admin/_head.tpl" title="Remise à zéro" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="reset"} {form_errors} {if $ok !== null} <p class="confirm">La remise à zéro a été effectuée. Une sauvegarde a également été créée.</p> </p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Remise à zéro</legend> <p class="error"> Attention : toutes les données seront effacées ! Ceci inclut les membres, les opérations comptables, les pages du wiki, etc. Seul votre compte membre sera re-créé avec le même email et mot de passe. </p> <p class="help"> Une sauvegarde sera automatiquement créée avant de procéder à la remise à zéro. </p> <dl> <dt><label for="f_passe_verif">Votre mot de passe</label> (pour vérification)</dt> <dd><input type="password" name="passe_verif" id="f_passe_verif" /></dd> </dl> <p> {csrf_field key="reset"} <input type="submit" name="reset_ok" value="Oui, je veux remettre à zéro" /> </p> </fieldset> </form> {include file="admin/_foot.tpl"} |
Deleted src/templates/admin/config/import.tpl version [e2b6c250be].
|
| < < < < < < < < < < < < < < < < |
Modified src/templates/admin/config/index.tpl from [8b2246c56b] to [6078c55f63].
1 2 3 4 | {include file="admin/_head.tpl" title="Configuration" current="config"} {include file="admin/config/_menu.tpl" current="index"} | | | 1 2 3 4 5 6 7 8 9 10 11 12 | {include file="admin/_head.tpl" title="Configuration" current="config"} {include file="admin/config/_menu.tpl" current="index"} {if $ok && !$form->hasErrors()} <p class="confirm"> La configuration a bien été enregistrée. </p> {/if} {form_errors} |
︙ | ︙ |
Modified src/templates/admin/config/membres.tpl from [79611cc039] to [fcc1959f81].
1 2 | {include file="admin/_head.tpl" current="config" js=1} | | | 1 2 3 4 5 6 7 8 9 10 | {include file="admin/_head.tpl" current="config" js=1} {include file="admin/config/_menu.tpl" current="fiches_membres"} {if isset($status) && $status == 'OK'} <p class="confirm"> La configuration a bien été enregistrée. </p> {elseif isset($status) && $status == 'ADDED'} <p class="confirm"> |
︙ | ︙ |
Modified src/templates/admin/config/plugins.tpl from [f3dbb74805] to [d99e6b054a].
︙ | ︙ | |||
25 26 27 28 29 30 31 | </form> {else} {if !empty($liste_installes)} <table class="list"> <thead> <tr> <th>Extension</th> | | | > > > > > > > | 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 | </form> {else} {if !empty($liste_installes)} <table class="list"> <thead> <tr> <th>Extension</th> <td></td> <td>Version installée</td> <td></td> </tr> </thead> <tbody> {foreach from=$liste_installes item="plugin"} <tr{if $plugin.disabled} class="disabled"{/if}> <th> <h4>{$plugin.nom}</h4> <small>{$plugin.description}</small> </th> {if $plugin.disabled} <td colspan="3"> <span class="alert">Code source du plugin non trouvé dans le répertoire <em>plugins</em> !</span><br /> Ce plugin ne peut fonctionner ou être désinstallé. </td> {else} <td> <a href="{$plugin.url}" onclick="return !window.open(this.href);">{$plugin.auteur}</a> </td> <td> {$plugin.version} </td> <td class="actions"> {if empty($plugin.system)} <a href="{$admin_url}config/plugins.php?delete={$plugin.id}">Désinstaller</a> {/if} {if !empty($plugin.config)} {if empty($plugin.system)}|{/if} <a href="{plugin_url id=$plugin.id file="config.php"}">Configurer</a> {/if} </td> {/if} </tr> {/foreach} </tbody> </table> {else} <p class="help"> Aucune extension n'est installée. |
︙ | ︙ |
Modified src/templates/admin/config/site.tpl from [012fc113de] to [04150e10c9].
1 2 3 4 5 6 | {include file="admin/_head.tpl" title="Configuration — Site public" current="config" js=1} {form_errors} {include file="admin/config/_menu.tpl" current="site"} | > > > > > > > > > > > | | 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 | {include file="admin/_head.tpl" title="Configuration — Site public" current="config" js=1} {form_errors} {include file="admin/config/_menu.tpl" current="site"} {if $config.desactiver_site} <div class="alert"> <h3>Site public désactivé</h3> <p>Le site public est désactivé, les visiteurs sont redirigés automatiquement vers la page de connexion.</p> <form method="post" action="{$self_url}"> <p class="submit"> {csrf_field key="config_site"} <input type="submit" name="activer_site" value="Réactiver le site public →" /> </p> </form> </div> {elseif isset($edit)} <form method="post" action="{$self_url}"> <h3>Éditer un squelette</h3> {if $ok} <p class="confirm"> Modifications enregistrées. </p> |
︙ | ︙ | |||
33 34 35 36 37 38 39 | var skel_list = {$sources|escape:json}; var skel_current = "{$edit.file|escape:'js'}"; </script> <script type="text/javascript" src="{$admin_url}static/scripts/skel_editor.js"></script> {else} <fieldset> | | > > > > > > > > > > > > > | > > > > > | 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 | var skel_list = {$sources|escape:json}; var skel_current = "{$edit.file|escape:'js'}"; </script> <script type="text/javascript" src="{$admin_url}static/scripts/skel_editor.js"></script> {else} <fieldset> <legend>Activation du site public</legend> <dl> <dt> <form method="post" action="{$self_url}"> <input type="submit" name="desactiver_site" value="Désactiver le site public" /> {csrf_field key="config_site"} </form> </dt> <dd class="help"> En désactivant le site public, les visiteurs seront automatiquement redirigés vers la page de connexion.<br /> Cette option est utile si vous avez déjà un site web et ne souhaitez pas utiliser la fonctionnalité site web de Garradin. </dd> </dl> </fieldset> <fieldset> <legend>Gérer le contenu du site public</legend> <p class="help"> Le contenu affiché sur le site est celui présent dans le wiki, il suffit de sélectionner « Cette page est visible ur le site de l'association » à l'édition d'une page wiki. Il est également possible de <a href="{$admin_url}wiki/creer.php?public">créer une nouvelle page publique sur le wiki</a>. </p> </fieldset> <form method="post" action="{$self_url}"> <fieldset class="templatesList"> <legend>Squelettes du site</legend> {if $reset_ok} |
︙ | ︙ |
Modified src/templates/admin/index.tpl from [82c846a0c8] to [68896b2b83].
1 2 3 4 5 6 7 8 | {include file="admin/_head.tpl" title="Bonjour %s !"|args:$user.identite current="home"} <ul class="actions"> <li><a href="{$admin_url}mes_infos.php">Modifier mes informations personnelles</a></li> {if $cotisation} <li> {if !$cotisation.a_jour} <b class="error">Cotisation en retard !</b> | > > | 1 2 3 4 5 6 7 8 9 10 | {include file="admin/_head.tpl" title="Bonjour %s !"|args:$user.identite current="home"} {$banniere|raw} <ul class="actions"> <li><a href="{$admin_url}mes_infos.php">Modifier mes informations personnelles</a></li> {if $cotisation} <li> {if !$cotisation.a_jour} <b class="error">Cotisation en retard !</b> |
︙ | ︙ |
Modified src/templates/admin/login.tpl from [a6078916db] to [ae198371c7].
|
| | | 1 2 3 4 5 6 7 8 | {include file="admin/_head.tpl" title="Connexion" js=1} {form_errors} {show_error if=$fail message="Connexion impossible. Vérifiez l'adresse e-mail et le mot de passe."} {if !$ssl_enabled && $prefer_ssl} <p class="alert"> <strong>Message de sécurité</strong><br /> |
︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 | </p> <p class="help"> <a href="{$admin_url}password.php">Pas de mot de passe ou mot de passe perdu ?</a> </p> </form> {include file="admin/_foot.tpl"} | > > > > | 43 44 45 46 47 48 49 50 51 52 53 54 55 | </p> <p class="help"> <a href="{$admin_url}password.php">Pas de mot de passe ou mot de passe perdu ?</a> </p> </form> <script type="text/javascript"> g.enhancePasswordField($('#f_passe')); </script> {include file="admin/_foot.tpl"} |
Deleted src/templates/admin/membres/categories/index.tpl version [9c762d5e02].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/categories/modifier.tpl version [206fa39a37].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/categories/supprimer.tpl version [145753eeb5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/templates/admin/membres/cotisations.tpl from [90b6408dfe] to [c69a2595d3].
1 2 3 4 | {include file="admin/_head.tpl" title="Cotisations du membre" current="membres/cotisations"} <ul class="actions"> <li><a href="{$admin_url}membres/fiche.php?id={$membre.id}"><b>{$membre.identite}</b></a></li> | | | 1 2 3 4 5 6 7 8 9 10 11 12 | {include file="admin/_head.tpl" title="Cotisations du membre" current="membres/cotisations"} <ul class="actions"> <li><a href="{$admin_url}membres/fiche.php?id={$membre.id}"><b>{$membre.identite}</b></a></li> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}<li><a href="{$admin_url}membres/modifier.php?id={$membre.id}">Modifier</a></li>{/if} {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN) && $user.id != $membre.id} <li><a href="{$admin_url}membres/supprimer.php?id={$membre.id}">Supprimer</a></li> {/if} <li class="current"><a href="{$admin_url}membres/cotisations.php?id={$membre.id}">Suivi des cotisations</a></li> </ul> <dl class="cotisation"> |
︙ | ︙ |
Modified src/templates/admin/membres/fiche.tpl from [184a802b43] to [cbce2b6a23].
1 2 3 4 | {include file="admin/_head.tpl" title="%s (%s)"|args:$membre.identite:$categorie.nom current="membres"} <ul class="actions"> <li class="current"><a href="{$admin_url}membres/fiche.php?id={$membre.id}"><b>{$membre.identite}</b></a></li> | | | 1 2 3 4 5 6 7 8 9 10 11 12 | {include file="admin/_head.tpl" title="%s (%s)"|args:$membre.identite:$categorie.nom current="membres"} <ul class="actions"> <li class="current"><a href="{$admin_url}membres/fiche.php?id={$membre.id}"><b>{$membre.identite}</b></a></li> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}<li><a href="{$admin_url}membres/modifier.php?id={$membre.id}">Modifier</a></li>{/if} {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN) && $user.id != $membre.id} <li><a href="{$admin_url}membres/supprimer.php?id={$membre.id}">Supprimer</a></li> {/if} <li><a href="{$admin_url}membres/cotisations.php?id={$membre.id}">Suivi des cotisations</a></li> </ul> <dl class="cotisation"> |
︙ | ︙ | |||
42 43 44 45 46 47 48 | {else} Aucune cotisation enregistrée {/if} </dt> <dd> <a href="{$admin_url}membres/cotisations.php?id={$membre.id}">Voir l'historique</a> </dd> | > | | | | | | | > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | {else} Aucune cotisation enregistrée {/if} </dt> <dd> <a href="{$admin_url}membres/cotisations.php?id={$membre.id}">Voir l'historique</a> </dd> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)} <dd><form method="get" action="{$admin_url}membres/cotisations/ajout.php"><input type="submit" value="Enregistrer une cotisation →" /><input type="hidden" name="id" value="{$membre.id}" /></form></dd> {if !empty($nb_operations)} <dt>Écritures comptables</dt> <dd>{$nb_operations} écritures comptables — <a href="{$admin_url}compta/operations/membre.php?id={$membre.id}">Voir la liste des écritures ajoutées par ce membre</a> </dd> {/if} {/if} </dl> <aside class="describe"> <dl class="describe"> <dt>Catégorie</dt> <dd>{$categorie.nom} <span class="droits">{format_droits droits=$categorie}</span></dd> <dt>Inscription</dt> |
︙ | ︙ | |||
76 77 78 79 80 81 82 | {/if} {/if} </dd> </dl> </aside> <dl class="describe"> | | | | | | | > | | < | | | | | | | 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 | {/if} {/if} </dd> </dl> </aside> <dl class="describe"> {foreach from=$champs key="c" item="c_config"} <dt>{$c_config.title}</dt> <dd> {if $c_config.type == 'checkbox'} {if $membre->$c}Oui{else}Non{/if} {elseif empty($membre->$c)} <em>(Non renseigné)</em> {elseif $c == $c_config.champ_identite} <strong>{$membre->$c}</strong> {elseif $c_config.type == 'email'} <a href="mailto:{$membre->$c|escape:'url'}">{$membre->$c}</a> {if $c == 'email'} | <a href="{$admin_url}membres/message.php?id={$membre.id}"><b class="icn action">✉</b> Envoyer un message</a> {/if} {elseif $c_config.type == 'tel'} <a href="tel:{$membre->$c}">{$membre->$c|format_tel}</a> {elseif $c_config.type == 'country'} {$membre->$c|get_country_name} {elseif $c_config.type == 'date' || $c_config.type == 'datetime'} {$membre->$c|format_sqlite_date_to_french} {elseif $c_config.type == 'password'} ******* {elseif $c_config.type == 'multiple'} <ul> {foreach from=$c_config.options key="b" item="name"} {if $membre->$c & (0x01 << $b)} <li>{$name}</li> {/if} {/foreach} </ul> {else} {$membre->$c|escape|rtrim|nl2br} {/if} </dd> {/foreach} </dl> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/import.tpl from [239f90c5ba] to [f967ae9cb7].
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | {if $ok} <p class="confirm"> L'import s'est bien déroulé. </p> {/if} <form method="post" action="{$self_url}" enctype="multipart/form-data"> <fieldset> <legend>Importer depuis un fichier</legend> <dl> <dt><label for="f_file">Fichier à importer</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="file" name="upload" id="f_file" required="required" /></dd> <dt><label for="f_type">Type de fichier</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> <input type="radio" name="type" id="f_type" value="garradin" {form_field name=type checked="garradin" default="garradin"} /> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | < < < < | < | < < < < < < < < < < < < < < < < > > < < < < < < < < < < < < < < | 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 | {if $ok} <p class="confirm"> L'import s'est bien déroulé. </p> {/if} <form method="post" action="{$self_url}" enctype="multipart/form-data"> {if $csv_file} <fieldset> <legend>Importer depuis un fichier CSV générique</legend> <p class="help">{$csv_file|count} lignes trouvées dans le fichier</p> <dl> <dt><label><input type="checkbox" name="skip_first_line" value="1" checked="checked" /> Ne pas importer la première ligne</label></dt> <dd class="help">Décocher cette case si la première ligne ne contient pas l'intitulé des colonnes mais des données.</dd> <dt><label>Correspondance des champs</label></dt> <dd class="help">Indiquer la correspondance entre colonnes du CSV et champs des fiches membre.</dd> <dd> <table class="list auto"> <tbody> {foreach from=$csv_first_line key="index" item="csv_field"} <tr> <th>{$csv_field}</th> <td> <select name="csv_translate[{$index}]"> <option value="">-- Ne pas importer ce champ</option> {foreach from=$garradin_champs item="champ" key="name"} {if $champ.type == 'multiple' || $champ.type == 'file' || $name == 'passe'}{continue}{/if} <option value="{$name}">{$champ.title}</option> {/foreach} </select> </td> </tr> {/foreach} </tbody> </table> </dd> <dd class="help">Pour fusionner des colonnes, il suffit d'indiquer le même nom de champ pour plusieurs colonnes.</dd> </dl> </fieldset> <input type="hidden" name="csv_encoded" value="{$csv_file|escape:'json'|escape}" /> {else} <fieldset> <legend>Importer depuis un fichier</legend> <dl> <dt><label for="f_file">Fichier à importer</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="file" name="upload" id="f_file" required="required" /></dd> <dt><label for="f_type">Type de fichier</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> <input type="radio" name="type" id="f_type" value="garradin" {form_field name=type checked="garradin" default="garradin"} /> <label for="f_type">Fichier CSV de Garradin</label> </dd> <dd class="help"> Export de la liste des membres au format CSV provenant de Garradin. Les lignes comportant un numéro de membre mettront à jour les fiches des membres ayant ce numéro (si le numéro existe), les lignes sans numéro ou avec un numéro inexistant créeront de nouveaux membres. </dd> <dd> <input type="radio" name="type" id="f_type_csv" value="csv" {form_field name=type checked="csv"} /> <label for="f_type_csv">Fichier CSV générique</label> </dd> <dd class="help"> Vous pourrez choisir la correspondance entre colonnes du CSV et champs des fiches membres dans le prochain écran. </dd> </dl> </fieldset> {/if} <p class="submit"> {csrf_field key="membres_import"} <input type="submit" name="import" value="Importer →" /> </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/index.tpl from [346b3591a7] to [bdf20a85ce].
1 2 | {include file="admin/_head.tpl" title="Liste des membres" current="membres" js=1} | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | {include file="admin/_head.tpl" title="Liste des membres" current="membres" js=1} <ul class="actions"> <li class="current"><a href="{$admin_url}membres/">Liste des membres</a></li> <li><a href="{$admin_url}membres/recherche.php">Recherche avancée</a></li> {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)} <li><a href="{$admin_url}membres/import.php">Import & export</a></li> <li><a href="{$admin_url}membres/recherche_sql.php">Recherche par requête SQL</a></li> {/if} </ul> {if $sent} <p class="confirm">Votre message a été envoyé.</p> {/if} {if !empty($membres_cats)} <form method="get" action="{$self_url}" class="shortFormRight"> |
︙ | ︙ | |||
29 30 31 32 33 34 35 | {/foreach} </select> <noscript><input type="submit" value="Filtrer →" /></noscript> </fieldset> </form> {/if} | | | < < | | | 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 | {/foreach} </select> <noscript><input type="submit" value="Filtrer →" /></noscript> </fieldset> </form> {/if} <form method="get" action="{$admin_url}membres/recherche.php" class="shortFormLeft"> <fieldset> <legend>Rechercher un membre</legend> <input type="text" name="qt" value="" /> <input type="submit" value="Chercher →" /> </fieldset> </form> <form method="post" action="action.php" class="memberList"> {if !empty($liste)} <table class="list"> <thead class="userOrder"> <tr> {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" title="Tout cocher / décocher" /></td>{/if} {foreach from=$champs key="c" item="champ"} <td class="{if $order == $c} cur {if $desc}desc{else}asc{/if}{/if}">{if $c == "numero"}#{else}{$champ.title}{/if} <a href="?o={$c}&a&cat={$current_cat}" class="icn up">↑</a><a href="?o={$c}&d&cat={$current_cat}" class="icn dn">↓</a></td> {/foreach} |
︙ | ︙ | |||
65 66 67 68 69 70 71 | {if $c == $config.champ_identite}<a href="{$admin_url}membres/fiche.php?id={$membre.id}">{/if} {$membre->$c|raw|display_champ_membre:$cfg} {if $c == $config.champ_identite}</a>{/if} </td> {/foreach} <td class="actions"> <a class="icn" href="{$admin_url}membres/fiche.php?id={$membre.id}" title="Fiche membre">👤</a> | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | {if $c == $config.champ_identite}<a href="{$admin_url}membres/fiche.php?id={$membre.id}">{/if} {$membre->$c|raw|display_champ_membre:$cfg} {if $c == $config.champ_identite}</a>{/if} </td> {/foreach} <td class="actions"> <a class="icn" href="{$admin_url}membres/fiche.php?id={$membre.id}" title="Fiche membre">👤</a> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}<a class="icn" href="{$admin_url}membres/modifier.php?id={$membre.id}" title="Modifier la fiche membre">✎</a>{/if} </td> </tr> {/foreach} </tbody> </table> {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)} <p class="actions"> <em>Pour les membres cochés :</em> <input type="submit" name="move" value="Changer de catégorie" /> <input type="submit" name="delete" value="Supprimer" /> {csrf_field key="membres_action"} </p> {/if} {pagination url=$pagination_url page=$page bypage=$bypage total=$total} {else} <p class="alert"> Aucun membre trouvé. </p> {/if} </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/message.tpl from [6ceb73fe1d] to [3012105144].
1 2 3 4 5 6 7 8 9 10 | {include file="admin/_head.tpl" title="Contacter un membre" current="membres"} {form_errors} <form method="post" action="{$self_url}"> <fieldset class="memberMessage"> <legend>Message</legend> <dl> <dt>Expéditeur</dt> <dd>{$user.identite} <{$user.email}></dd> | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | {include file="admin/_head.tpl" title="Contacter un membre" current="membres"} {form_errors} <form method="post" action="{$self_url}"> <fieldset class="memberMessage"> <legend>Message</legend> <dl> <dt>Expéditeur</dt> <dd>{$user.identite} <{$user.email}></dd> <dt>Destinataire</dt> <dd>{$membre.identite} ({$categorie.nom})</dd> <dt><label for="f_sujet">Sujet</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="sujet" id="f_sujet" value="{form_field name=sujet}" required="required" /></dd> <dt><label for="f_message">Message</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><textarea name="message" id="f_message" cols="72" rows="25" required="required">{form_field name=message}</textarea></dd> <dd> |
︙ | ︙ |
Deleted src/templates/admin/membres/message_collectif.tpl version [c3a52f70e1].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/templates/admin/membres/recherche.tpl from [3886f956f8] to [0b60246b36].
|
| | | | | < | | | > | | < | | | | | > > > | > | > > > > > | < | > | < > > > > > | | > | < < > | | | | | | | | | | | | | > | < > > > > | | < < < < > > | > | > > | > > > > > > | > > > > > > > > | > > > > > > > > > > > > > > > | > | | > | | < < < | < | | > | | | | | | | < < | | | | | > | > | | | | | | | | | | | | | | | | | > | | | < | | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | {include file="admin/_head.tpl" title="Recherche de membre" current="membres" js=1 custom_js=['sql_query_builder.js']} {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)} <ul class="actions"> <li><a href="{$admin_url}membres/">Liste des membres</a></li> <li class="current"><a href="{$admin_url}membres/recherche.php">Recherche avancée</a></li> <li><a href="{$admin_url}membres/recherche_sql.php">Recherche par requête SQL</a></li> </ul> {/if} <form method="post" action="{$admin_url}membres/recherche.php" id="queryBuilderForm"> <fieldset> <legend>Rechercher un membre</legend> <div class="queryBuilder" id="queryBuilder"></div> <p class="actions"> <label>Trier par <select name="order"> {foreach from=$colonnes key="colonne" item="config"} <option value="{$colonne}"{form_field name="order" selected=$colonne}>{$config.label}</option> {/foreach} </select> </label> <label><input type="checkbox" name="desc" value="1" {form_field name="desc" checked=1 default=$desc} /> Tri inversé</label> <label>Limiter à <input type="number" value="{$limit}" name="limit" size="5" /> résultats</label> </p> <p class="submit"> <input type="submit" value="Chercher →" id="send" /> <input type="hidden" name="q" id="jsonQuery" /> </p> </fieldset> <p class="help">{$sql_query}</p> </form> <script type="text/javascript"> var colonnes = {$colonnes|escape:'json'}; {literal} var traductions = { "after": "après", "before": "avant", "is equal to": "est égal à", "is equal to one of": "est égal à une des ces options", "is not equal to one of": "n'est pas égal à une des ces options", "is not equal to": "n'est pas égal à", "is greater than": "est supérieur à", "is greater than or equal to": "est supérieur ou égal à", "is less than": "est inférieur à", "is less than or equal to": "est inférieur ou égal à", "is between": "est situé entre", "is not between": "n'est pas situé entre", "is null": "est nul", "is not null": "n'est pas nul", "begins with": "commence par", "doesn't begin with": "ne commence pas par", "ends with": "se termine par", "doesn't end with": "ne se termine pas par", "contains": "contient", "doesn't contain": "ne contient pas", "matches one of": "correspond à", "is true": "oui", "is false": "non", "Matches ALL of the following conditions:": "Correspond à TOUS les critères suivants :", "Matches ANY of the following conditions:": "Correspond à UN SEUL des critères suivants :", "Add a new set of conditions below this one": "-- Ajouter un groupe de critères", "Remove this set of conditions": "-- Supprimer ce groupe de critères" }; var q = new SQLQueryBuilder(colonnes); q.__ = function (str) { return traductions[str]; }; q.loadDefaultOperators(); q.buildInput = function (type, label, column) { if (label == '+') { label = '➕'; } else if (label == '-') { label = '➖'; } var i = document.createElement('input'); console.log(type); i.type = type == 'integer' ? 'number' : type; i.value = label; if (type == 'button') { i.className = 'icn action'; } return i; }; q.init(document.getElementById('queryBuilder')); $('#queryBuilderForm').onsubmit = function () { $('#jsonQuery').value = JSON.stringify(q.export()); }; {/literal} q.import({$query|escape:'json'}); </script> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)} <form method="post" action="{$admin_url}membres/action.php" class="memberList"> {/if} {if !empty($result)} <p class="help">{$result|count} membres trouvés pour cette recherche.</p> <table class="list search"> <thead> <tr> {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" value="Tout cocher / décocher" onclick="g.checkUncheck();" /></td>{/if} {foreach from=$result_header key="c" item="cfg"} <td>{$cfg.title}</td> {/foreach} <td></td> </tr> </thead> <tbody> {foreach from=$result item="row"} <tr> {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" name="selected[]" value="{$row.id}" /></td>{/if} {foreach from=$row key="key" item="value"} {if isset($result_header[$key])} <td>{$value|raw|display_champ_membre:$result_header[$key]}</td> {/if} {/foreach} <td class="actions"> <a class="icn" href="{$admin_url}membres/fiche.php?id={$row.id}" title="Fiche membre">👤</a> {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)} <a class="icn" href="{$admin_url}membres/modifier.php?id={$row.id}" title="Modifier la fiche membre">✎</a> {/if} </td> </tr> {/foreach} </tbody> </table> {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)} <p class="checkUncheck"> <input type="button" value="Tout cocher / décocher" onclick="g.checkUncheck();" /> </p> <p class="actions"> <em>Pour les membres cochés :</em> <input type="submit" name="move" value="Changer de catégorie" /> <input type="submit" name="delete" value="Supprimer" /> {csrf_field key="membres_action"} </p> {/if} {elseif $result !== null} <p class="alert"> Aucun membre trouvé. </p> </form> {/if} {if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)} </form> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/recherche_sql.tpl from [4ba2fc1f34] to [b00b9336aa].
|
| | | 1 2 3 4 5 6 7 8 | {include file="admin/_head.tpl" title="Recherche par requête SQL" current="membres" js=1} <form method="get" action="{$admin_url}membres/recherche_sql.php"> <fieldset> <legend>Schéma des tables SQL</legend> <pre class="sql_schema">{$schema.membres}</pre> <dl> <dt><label for="f_query">Requête SQL</label></dt> |
︙ | ︙ | |||
25 26 27 28 29 30 31 | <form method="post" action="{$admin_url}membres/action.php" class="memberList"> {if !empty($result)} <p class="alert">{$result|count} résultats renvoyés.</p> <table class="list search"> <thead> {if array_key_exists('id', $result[0])} | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <form method="post" action="{$admin_url}membres/action.php" class="memberList"> {if !empty($result)} <p class="alert">{$result|count} résultats renvoyés.</p> <table class="list search"> <thead> {if array_key_exists('id', $result[0])} <td class="check"><input type="checkbox" value="Tout cocher / décocher" onclick="g.checkUncheck();" /></td> {/if} {foreach from=$result[0] key="col" item="ignore"} <td>{$col}</td> {/foreach} {if array_key_exists('id', $result[0])} <td></td> {/if} |
︙ | ︙ | |||
57 58 59 60 61 62 63 | {/if} </tr> {/foreach} </tbody> </table> <p class="checkUncheck"> | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | {/if} </tr> {/foreach} </tbody> </table> <p class="checkUncheck"> <input type="button" value="Tout cocher / décocher" onclick="g.checkUncheck();" /> </p> <p class="actions"> <em>Pour les membres cochés :</em> <input type="submit" name="move" value="Changer de catégorie" /> <input type="submit" name="delete" value="Supprimer" /> {csrf_field key="membres_action"} </p> {else} <p class="alert"> Aucun membre trouvé. </p> {/if} </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/historique.tpl from [d5a6d6126a] to [7dc923ca5f].
1 2 3 | {include file="admin/_head.tpl" title="Historique : %s"|args:$page.titre current="wiki"} <ul class="actions"> | | | 1 2 3 4 5 6 7 8 9 10 11 | {include file="admin/_head.tpl" title="Historique : %s"|args:$page.titre current="wiki"} <ul class="actions"> <li><a href="{$admin_url}wiki/?{$page.uri}">Retour à la page</a></li> </ul> {if !empty($revisions)} <table class="list wikiRevisions"> {foreach from=$revisions item="rev"} <tr> <td> |
︙ | ︙ |
Modified src/templates/error.tpl from [f1a21eb4e1] to [52bccc1e68].
1 2 3 4 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | | | 1 2 3 4 5 6 7 8 9 10 11 12 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>{if empty($title)}Erreur{else}{$title}{/if}</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <style type="text/css"> {literal} * { margin: 0; padding: 0; } html { width: 100%; height: 100%; } body { |
︙ | ︙ | |||
27 28 29 30 31 32 33 | } {/literal} </style> </head> <body> | | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | } {/literal} </style> </head> <body> <h1>{if empty($title)}Erreur{else}{$title}{/if}</h1> <p class="error"> {$error|escape|nl2br} </p> <p> <a href="{$www_url}" onclick="return history.back();">← Retour</a> </p> </body> </html> |
Modified src/www/admin/_inc.php from [e0bbbc300b] to [d6f6a6d40f].
︙ | ︙ | |||
66 67 68 69 70 71 72 | $tpl->assign('is_logged', true); $user = $session->getUser(); $tpl->assign('user', $user); $tpl->assign('current', ''); | < | > | > | > > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | $tpl->assign('is_logged', true); $user = $session->getUser(); $tpl->assign('user', $user); $tpl->assign('current', ''); if ($session->get('plugins_menu') === null) { // Construction de la liste de plugins pour le menu // et stockage en session pour ne pas la recalculer à chaque page $session->set('plugins_menu', Plugin::listMenu($user)); } $tpl->assign('plugins_menu', $session->get('plugins_menu')); } |
Added src/www/admin/config/categories/index.php version [c7ce3325e0].
> > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $cats = new Membres\Categories; if (f('save')) { $form->check('new_cat', [ 'nom' => 'required', ]); if (!$form->hasErrors()) { $cats->add([ 'nom' => f('nom'), ]); Utils::redirect(ADMIN_URL . 'config/categories/'); } } $tpl->assign('liste', $cats->listCompleteWithStats()); $tpl->display('admin/config/categories/index.tpl'); |
Added src/www/admin/config/categories/modifier.php version [6a75b928b9].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $cats = new Membres\Categories; qv(['id' => 'required|numeric']); $id = (int) qg('id'); $cat = $cats->get($id); if (!$cat) { throw new UserException("Cette catégorie n'existe pas."); } if (f('save')) { $droits = implode(',', [ Membres::DROIT_AUCUN, Membres::DROIT_ACCES, Membres::DROIT_ECRITURE, Membres::DROIT_ADMIN, ]); $form->check('edit_cat_' . $id, [ 'nom' => 'required', 'droit_wiki' => 'in:' . $droits, 'droit_compta' => 'in:' . $droits, 'droit_membres' => 'in:' . $droits, 'droit_config' => sprintf('in:%s,%s', Membres::DROIT_ADMIN, Membres::DROIT_AUCUN), 'droit_connexion' => sprintf('in:%s,%s', Membres::DROIT_ACCES, Membres::DROIT_AUCUN), 'droit_inscription' => sprintf('in:%s,%s', Membres::DROIT_ACCES, Membres::DROIT_AUCUN), 'cacher' => 'boolean', 'id_cotisation_obligatoire' => 'numeric', ]); if (!$form->hasErrors()) { $data = [ 'nom' => f('nom'), 'droit_wiki' => (int) f('droit_wiki'), 'droit_compta' => (int) f('droit_compta'), 'droit_config' => (int) f('droit_config'), 'droit_membres' => (int) f('droit_membres'), 'droit_connexion' => (int) f('droit_connexion'), 'droit_inscription' => (int) f('droit_inscription'), 'cacher' => (int) f('cacher'), 'id_cotisation_obligatoire' => (int) f('id_cotisation_obligatoire'), ]; // Ne pas permettre de modifier la connexion, l'accès à la config et à la gestion des membres // pour la catégorie du membre qui édite les catégories, sinon il pourrait s'empêcher // de se connecter ou n'avoir aucune catégorie avec le droit de modifier les catégories ! if ($cat->id == $user->id_categorie) { $data['droit_connexion'] = Membres::DROIT_ACCES; $data['droit_config'] = Membres::DROIT_ADMIN; } try { $cats->edit($id, $data); if ($id == $user->id_categorie) { // Mise à jour de la session courante $session->refresh(); } Utils::redirect(ADMIN_URL . 'config/categories/'); } catch (UserException $e) { $form->addError($e->getMessage()); } } } $tpl->assign('cat', $cat); $tpl->assign('readonly', $cat->id == $user->id_categorie ? 'disabled="disabled"' : ''); $cotisations = new Cotisations; $tpl->assign('cotisations', $cotisations->listCurrent()); $tpl->assign('membres', new Membres); $tpl->display('admin/config/categories/modifier.tpl'); |
Added src/www/admin/config/categories/supprimer.php version [93c453e7a7].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $cats = new Membres\Categories; qv(['id' => 'required|numeric']); $id = (int) qg('id'); $cat = $cats->get($id); if (!$cat) { throw new UserException("Cette catégorie n'existe pas."); } if ($cat->id == $user->id_categorie) { throw new UserException("Vous ne pouvez pas supprimer votre catégorie."); } if (f('delete')) { $form->check('delete_cat_' . $id); if (!$form->hasErrors()) { try { $cats->remove($id); Utils::redirect(ADMIN_URL . 'config/categories/'); } catch (UserException $e) { $form->addError($e->getMessage()); } } } $tpl->assign('cat', $cat); $tpl->display('admin/config/categories/supprimer.tpl'); |
Deleted src/www/admin/config/donnees.php version [37588fe983].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added src/www/admin/config/donnees/automatique.php version [05a939d15b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; if (!ENABLE_AUTOMATIC_BACKUPS) { throw new UserException('Les sauvegardes automatiques sont désactivées.'); } if (f('config')) { $form->check('backup_config', [ 'frequence_sauvegardes' => 'present|numeric|min:0|max:365', 'nombre_sauvegardes' => 'present|numeric|min:1|max:90', ]); if (!$form->hasErrors()) { try { $config->set('frequence_sauvegardes', f('frequence_sauvegardes')); $config->set('nombre_sauvegardes', f('nombre_sauvegardes')); $config->save(); Utils::redirect(ADMIN_URL . 'config/donnees/automatique.php?ok=config'); } catch (UserException $e) { $form->addError($e->getMessage()); } } } $tpl->assign('ok', qg('ok')); $tpl->display('admin/config/donnees/automatique.tpl'); |
Added src/www/admin/config/donnees/import.php version [f13c6c5a62].
> > > > > > | 1 2 3 4 5 6 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $tpl->display('admin/config/donnees/import.tpl'); |
Added src/www/admin/config/donnees/index.php version [a41ebc5c56].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $s = new Sauvegarde; if (f('download')) { $form->check('backup_download'); if (!$form->hasErrors()) { header('Content-type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $config->get('nom_asso') . ' - Sauvegarde données - ' . date('Y-m-d') . '.sqlite"'); header('Content-Length: ' . $s->getDBSize(true)); $s->dump(); exit; } } elseif (f('restore_file')) { $form->check('backup_restore'); if (!$form->hasErrors()) { // Ignorer la vérification d'intégrité si autorisé et demandé $check = (ALLOW_MODIFIED_IMPORT && f('force_import')) ? false : true; try { $r = $s->restoreFromUpload($_FILES['file'], $user->id, $check); Utils::redirect(ADMIN_URL . 'config/donnees/?ok=restore&code=' . (int)$r); } catch (UserException $e) { $form->addError($e->getMessage()); $code = $e->getCode(); } } } $tpl->assign('db_size', $s->getDBSize()); $tpl->assign('files_size', $s->getDBFilesSize()); $tpl->assign('code', isset($code) ? $code : null); $tpl->assign('ok_code', qg('code')); $tpl->assign('ok', qg('ok')); $tpl->assign('now_date', date('Y-m-d')); $tpl->assign('max_file_size', Utils::getMaxUploadSize()); $tpl->display('admin/config/donnees/index.tpl'); |
Added src/www/admin/config/donnees/local.php version [26c48b632d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $s = new Sauvegarde; if (f('create')) { $form->check('backup_create'); if (!$form->hasErrors()) { try { $s->create(); Utils::redirect(ADMIN_URL . 'config/donnees/local.php?ok=create'); } catch (UserException $e) { $form->addError($e->getMessage()); } } } if (f('restore')) { $form->check('backup_manage'); if (!$form->hasErrors()) { try { $r = $s->restoreFromLocal(f('file')); Utils::redirect(ADMIN_URL . 'config/donnees/local.php?ok=restore&code=' . (int)$r); } catch (UserException $e) { $form->addError($e->getMessage()); } } } elseif (f('remove')) { $form->check('backup_manage'); if (!$form->hasErrors()) { try { $s->remove(f('file')); Utils::redirect(ADMIN_URL . 'config/donnees/local.php?ok=remove'); } catch (UserException $e) { $form->addError($e->getMessage()); } } } $tpl->assign('code', $code); $tpl->assign('ok_code', qg('code')); $tpl->assign('ok', qg('ok')); $tpl->assign('liste', $s->getList()); $tpl->display('admin/config/donnees/local.tpl'); |
Added src/www/admin/config/donnees/reset.php version [3891123042].
> > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $s = new Sauvegarde; if (f('reset_ok')) { $form->check('reset'); if (!$form->hasErrors()) { try { Install::reset($session, f('passe_verif')); Utils::redirect(ADMIN_URL . 'config/donnees/reset.php?ok'); } catch (UserException $e) { $form->addError($e->getMessage()); } } } $tpl->assign('ok', qg('ok')); $tpl->display('admin/config/donnees/reset.tpl'); |
Deleted src/www/admin/config/import.php version [0d90db7427].
|
| < < < < < < |
Modified src/www/admin/config/site.php from [6929129da8] to [dd99638235].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; | | < < < | | < | | < > | > | < > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; if (f('desactiver_site') && $form->check('config_site')) { $config->set('desactiver_site', true); $config->save(); Utils::redirect(ADMIN_URL . 'config/site.php'); } elseif (f('activer_site') && $form->check('config_site')) { $config->set('desactiver_site', false); $config->save(); Utils::redirect(ADMIN_URL . 'config/site.php'); } if (f('select') && f('reset') && $form->check('squelettes')) { try { foreach (f('select') as $source) { |
︙ | ︙ |
Modified src/www/admin/index.php from [dd9c88b1a0] to [5988e390c9].
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | } else { $tpl->assign('cotisation', false); } $tpl->assign('custom_css', ['wiki.css']); $tpl->display('admin/index.tpl'); flush(); // Si pas de cron on réalise les tâches automatisées à ce moment-là // c'est pas idéal mais mieux que rien if (!USE_CRON) { require_once ROOT . '/cron.php'; } | > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | } else { $tpl->assign('cotisation', false); } $tpl->assign('custom_css', ['wiki.css']); $tpl->assign('banniere', Plugin::fireSignal('accueil.banniere', ['user' => $user, 'session' => $session])); $tpl->display('admin/index.tpl'); flush(); // Si pas de cron on réalise les tâches automatisées à ce moment-là // c'est pas idéal mais mieux que rien if (!USE_CRON) { require_once ROOT . '/cron.php'; } |
Deleted src/www/admin/membres/categories/index.php version [a435abf714].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/categories/modifier.php version [624c7118d6].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/categories/supprimer.php version [43f9a12d7b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/www/admin/membres/cotisations.php from [32cdb67ed5] to [d156e1e5bb].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; | < < | 1 2 3 4 5 6 7 8 9 10 11 12 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; qv(['id' => 'required|numeric']); $id = (int) qg('id'); $membre = $membres->get($id); if (!$membre) |
︙ | ︙ |
Modified src/www/admin/membres/fiche.php from [173904eaef] to [890dac5864].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; | < < | 1 2 3 4 5 6 7 8 9 10 11 12 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; qv(['id' => 'required|numeric']); $id = (int) qg('id'); $membre = $membres->get($id); if (!$membre) |
︙ | ︙ |
Modified src/www/admin/membres/import.php from [414da74c86] to [87bae42958].
︙ | ︙ | |||
23 24 25 26 27 28 29 | $import->toODS(); exit; } $champs = $config->get('champs_membres')->getAll(); $champs->date_inscription = (object) ['title' => 'Date inscription', 'type' => 'date']; | > > > > > > > > > > > > > > > > > > > > > > > > > | | < | | > | | < < > > > < < | 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 | $import->toODS(); exit; } $champs = $config->get('champs_membres')->getAll(); $champs->date_inscription = (object) ['title' => 'Date inscription', 'type' => 'date']; $csv_file = false; if (f('csv_encoded')) { $form->check('membres_import', [ 'csv_encoded' => 'required|json', 'csv_translate' => 'required|array', 'skip_first_line' => 'boolean', ]); $csv_file = json_decode(f('csv_encoded'), true); if (!$form->hasErrors()) { try { $import->fromArray($csv_file, f('csv_translate'), f('skip_first_line') ? 1 : 0); Utils::redirect(ADMIN_URL . 'membres/import.php?ok'); } catch (UserException $e) { $form->addError($e->getMessage()); } } } elseif (f('import')) { $form->check('membres_import', [ 'upload' => 'file|required', 'type' => 'required|in:csv,garradin', ]); if (!$form->hasErrors()) { try { if (f('type') == 'garradin') { $import->fromGarradinCSV($_FILES['upload']['tmp_name'], $user->id); Utils::redirect(ADMIN_URL . 'membres/import.php?ok'); } elseif (f('type') == 'csv') { $csv_file = $import->getCSVAsArray($_FILES['upload']['tmp_name']); } else { throw new UserException('Import inconnu.'); } } catch (UserException $e) { $form->addError($e->getMessage()); } } } $tpl->assign('ok', null !== qg('ok') ? true : false); $tpl->assign('csv_file', $csv_file); $tpl->assign('csv_first_line', $csv_file ? reset($csv_file) : null); $tpl->assign('garradin_champs', $champs); $tpl->display('admin/membres/import.tpl'); |
Modified src/www/admin/membres/index.php from [e45d2413f7] to [33e9d88bdd].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.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 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $cats = new Membres\Categories; $champs = $config->get('champs_membres'); $membres_cats = $cats->listSimple(); $membres_cats_cachees = $cats->listHidden(); $cat_id = (int) qg('cat') ?: 0; $page = (int) qg('p') ?: 1; if ($cat_id) { if (!$session->canAccess('membres', Membres::DROIT_ECRITURE) && array_key_exists($cat_id, $membres_cats_cachees)) { $cat_id = 0; } } if (!$cat_id) { $cat_id = array_diff(array_keys((array) $membres_cats), array_keys((array) $membres_cats_cachees)); } // Par défaut le champ de tri c'est l'identité $order = $config->get('champ_identite'); $desc = false; if (qg('o')) $order = qg('o'); if (null !== qg('d')) $desc = true; $fields = $champs->getListedFields(); // Vérifier que le champ de tri existe bien dans la table if (!isset($fields->$order)) { // Sinon par défaut c'est le premier champ de la table qui fait le tri $order = $champs->getFirstListed(); } $tpl->assign('order', $order); $tpl->assign('desc', $desc); $tpl->assign('champs', $fields); $tpl->assign('liste', $membres->listByCategory($cat_id, array_keys((array) $fields), $page, $order, $desc)); $tpl->assign('total', $membres->countByCategory($cat_id)); $cat_id = is_array($cat_id) ? 0 : $cat_id; $tpl->assign('pagination_url', Utils::getSelfUrl([ 'p' => '[ID]', 'o' => $order, ($desc ? 'd' : 'a') => '', 'cat' => $cat_id, ])); $tpl->assign('membres_cats', $membres_cats); $tpl->assign('membres_cats_cachees', $membres_cats_cachees); $tpl->assign('current_cat', $cat_id); $tpl->assign('page', $page); $tpl->assign('bypage', Membres::ITEMS_PER_PAGE); $tpl->assign('sent', null !== qg('sent')); $tpl->display('admin/membres/index.tpl'); |
Deleted src/www/admin/membres/message_collectif.php version [2bd7d9d11b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/www/admin/membres/recherche.php from [f11a643a77] to [218ac5f508].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.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 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $champs = $config->get('champs_membres'); $text_query = trim(qg('qt')); $query = null; $limit = f('limit') ?: 100; $order = f('order'); $desc = (bool) f('desc'); $sql_query = null; // Recherche simple if ($text_query !== '') { $operator = 'LIKE %?%'; if (is_numeric(trim($text_query))) { $column = 'numero'; $operator = '= ?'; } elseif (strpos($text_query, '@') !== false) { $column = 'email'; } else { $column = $config->get('champ_identite'); } $query = [[ 'operator' => 'AND', 'conditions' => [ [ 'column' => $column, 'operator' => $operator, 'values' => [$text_query], ], ], ]]; } elseif (f('q') !== null) { $query = json_decode(f('q'), true); } if ($query) { $sql_query = $membres->buildSQLSearchQuery($query, $order, $desc, $limit); $result = $membres->searchSQL($sql_query); if (count($result) == 1 && $text_query !== '') { Utils::redirect(ADMIN_URL . 'membres/fiche.php?id=' . (int)$result[0]->id); } $tpl->assign('result_header', $membres->getSearchHeaderFields($result)); } else { $query = [[ 'operator' => 'AND', 'conditions' => [ [ 'column' => $config->get('champ_identite'), 'operator' => '= ?', 'values' => ['Souad Massi'], ], ], ]]; $result = null; } $tpl->assign('query', $query); $tpl->assign('sql_query', $sql_query); $tpl->assign('result', $result); $tpl->assign('order', $order); $tpl->assign('desc', $desc); $tpl->assign('limit', $limit); $colonnes = []; foreach ($champs->getList() as $champ => $config) { $colonne = [ 'label' => $config->title, 'type' => 'text', 'null' => true, ]; if ($config->type == 'checkbox') { $colonne['type'] = 'boolean'; } elseif ($config->type == 'select') { $colonne['type'] = 'enum'; $colonne['values'] = $config->options; } elseif ($config->type == 'multiple') { $colonne['type'] = 'bitwise'; $colonne['values'] = $config->options; } elseif ($config->type == 'date' || $config->type == 'datetime') { $colonne['type'] = $config->type; } elseif ($config->type == 'number' || $champ == 'numero') { $colonne['type'] = 'integer'; } $colonnes[$champ] = $colonne; } $tpl->assign('colonnes', $colonnes); $tpl->display('admin/membres/recherche.tpl'); |
Modified src/www/admin/static/admin.css from [903a1b66a2] to [78c40bcd12].
1 2 3 4 | @charset "UTF-8"; @font-face { font-family: 'gicon'; | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @charset "UTF-8"; @font-face { font-family: 'gicon'; src: url('font/garradin.eot?2018'); src: url('font/garradin.eot?2018#iefix') format('embedded-opentype'), url('font/garradin.woff?2018') format('woff'), url('font/garradin.ttf?2018') format('truetype'), url('font/garradin.svg?2018#garradin') format('svg'); font-weight: normal; font-style: normal; } body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, p, blockquote, th, td, figure, article, aside, section, header, footer { |
︙ | ︙ | |||
185 186 187 188 189 190 191 | color: #090; } span.alert, b.alert { color: #990; } | | | < | > > > > > > > > | | < < | | > > > > | > > > > > | > > > > | > > > > > > > > | 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 | color: #090; } span.alert, b.alert { color: #990; } p.alert, div.alert, p.error, div.error, p.confirm, div.confirm { border: 1px solid #ccc; padding: .5em; margin-bottom: 1em; border-radius: .3em; padding-left: 3em; position: relative; } p.error, div.error { border-color: #c00; background-color: #fcc; } p.confirm, div.confirm { border-color: #0c0; background-color: #cfc; } p.alert, div.alert { border-color: #cc0; background-color: #ffc; } p.confirm::before, div.confirm::before, p.alert::before, div.alert::before, p.error::before, div.error::before { font-family: "gicon"; left: .5em; top: .2em; position: absolute; font-size: 1.5em; text-shadow: 2px 2px 5px #666; } p.confirm::before, div.confirm::before { content: "☑"; color: green; } p.alert::before, div.alert::before { content: "⚠"; color: yellow; } p.error::before, div.error::before { content: "⚠"; color: red; } p.help { margin: 1em; color: #666; } |
︙ | ︙ | |||
274 275 276 277 278 279 280 281 282 283 284 285 286 287 | input[type=text], textarea, input[type=password], input[type=email], input[type=url], input[type=tel], select { padding: 0.2em 0.4em; font-family: Sans-serif; min-width: 20em; max-width: 100%; } select, input[size] { min-width: 0; } input.time { text-align: center; | > > > > | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | input[type=text], textarea, input[type=password], input[type=email], input[type=url], input[type=tel], select { padding: 0.2em 0.4em; font-family: Sans-serif; min-width: 20em; max-width: 100%; } input[type=password], input.clearTextPassword { font-family: monospace; } select, input[size] { min-width: 0; } input.time { text-align: center; |
︙ | ︙ | |||
300 301 302 303 304 305 306 307 308 309 310 311 312 313 | transition: opacity .5s ease; } input.resetButton { padding: .1em; margin-left: 1em; } .loader { width: 100%; min-height: 32px; display: block; position: relative; } | > > > > > > > > > > | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | transition: opacity .5s ease; } input.resetButton { padding: .1em; margin-left: 1em; } input[type=button].showPassword { margin-left: -2em; margin-right: 1em; background: none; } input[type=button].showPassword:hover { background: none; } .loader { width: 100%; min-height: 32px; display: block; position: relative; } |
︙ | ︙ | |||
405 406 407 408 409 410 411 | float: right; } ul.actions { list-style-type: none; margin: 1em 0; border-bottom: .1em solid #9c4f15; | | > > > > > > > > > | | 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 | float: right; } ul.actions { list-style-type: none; margin: 1em 0; border-bottom: .1em solid #9c4f15; border-bottom-color: rgb(var(--gMainColor)); padding: 0 1em; z-index: 100; } ul.actions.sub { margin: -1em 2em 1em 0; padding-top: 1em; border-right: .1em solid #9c4f15; border-right-color: rgb(var(--gMainColor)); border-bottom-right-radius: .5em; } ul.actions li { display: inline-block; margin: 0 0.2em; } ul.actions li a, ul.actions li label { display: inline-block; background: rgb(217, 134, 40); background: rgba(217, 134, 40, .5); background: rgba(var(--gSecondColor), .5); border-radius: .5em .5em 0 0; padding: .1em .5em; color: #000; text-decoration: none; transition: background-color .2s, color .2s; } ul.actions li input { display: none; } ul.actions li.current a, ul.actions li input:checked + label { background: #9c4f15; background: rgb(var(--gMainColor)); color: #fff; color: rgb(var(--gBgColor)); } ul.actions li a:hover, ul.actions li label:hover { color: #fff; background-color: rgb(var(--gMainColor)); text-decoration: underline; border-bottom: none; } h3.warning { margin: 1em; color: red; |
︙ | ︙ | |||
564 565 566 567 568 569 570 571 572 573 574 575 576 577 | } table.search th { background: rgb(217, 134, 40); background: rgba(217, 134, 40, 0.5); background: rgba(var(--gSecondColor), 0.5); } .userOrder .cur { background: rgb(217, 134, 40); background: rgba(var(--gSecondColor), 1.0); color: #fff; color: rgb(var(--gBgColor)); } | > > > > > > > > > > > > > | 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 | } table.search th { background: rgb(217, 134, 40); background: rgba(217, 134, 40, 0.5); background: rgba(var(--gSecondColor), 0.5); } table.list .disabled { background: #eee; color: #999; } #queryBuilder .column select { max-width: 15em; } #queryBuilder table td { vertical-align: top; } .userOrder .cur { background: rgb(217, 134, 40); background: rgba(var(--gSecondColor), 1.0); color: #fff; color: rgb(var(--gBgColor)); } |
︙ | ︙ | |||
676 677 678 679 680 681 682 683 684 685 686 687 688 689 | padding-bottom: .5em; border-bottom: 1pt solid #999; } #rapport h1 { text-align: center; } .icn, .icnl { font-family: "gicon", sans-serif; font-style: normal; font-weight: normal; speak: none; font-variant: normal; | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | padding-bottom: .5em; border-bottom: 1pt solid #999; } #rapport h1 { text-align: center; } h2.ruler { margin: .5em; text-align: center; color: #333; overflow: hidden; } h2.ruler:before, h2.ruler:after { background-color: #000; content: ""; display: inline-block; height: 1px; position: relative; vertical-align: middle; width: 50%; } h2.ruler:before { right: 0.5em; margin-left: -50%; } h2.ruler:after { left: 0.5em; margin-right: -50%; } .icn, .icnl { font-family: "gicon", sans-serif; font-style: normal; font-weight: normal; speak: none; font-variant: normal; |
︙ | ︙ |
Modified src/www/admin/static/font/garradin.css from [2361fa015f] to [d980f71e5b].
1 2 3 4 | @charset "UTF-8"; @font-face { font-family: 'garradin'; | | | > | | | | | > > > > > | > > | > > > | > > > | | | | | | > > < > | > > | > | | | | > | | 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 | @charset "UTF-8"; @font-face { font-family: 'garradin'; src: url('../font/garradin.eot?31180986'); src: url('../font/garradin.eot?31180986#iefix') format('embedded-opentype'), url('../font/garradin.woff2?31180986') format('woff2'), url('../font/garradin.woff?31180986') format('woff'), url('../font/garradin.ttf?31180986') format('truetype'), url('../font/garradin.svg?31180986#garradin') format('svg'); font-weight: normal; font-style: normal; } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ /* @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'garradin'; src: url('../font/garradin.svg?31180986#garradin') format('svg'); } } */ [class^="icn-"]:before, [class*=" icn-"]:before { font-family: "garradin"; font-style: normal; font-weight: normal; speak: none; display: inline-block; text-decoration: inherit; width: 1em; margin-right: .2em; text-align: center; /* opacity: .8; */ /* For safety - reset parent styles, that can break glyph codes*/ font-variant: normal; text-transform: none; /* fix buttons height, for twitter bootstrap */ line-height: 1em; /* Animation center compensation - margins should be symmetric */ /* remove if not needed */ margin-left: .2em; /* you can be more comfortable with increased icons size */ /* font-size: 120%; */ /* Font smoothing. That was taken from TWBS */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } .icn-up:before { content: '\2191'; } /* '↑' */ .icn-down:before { content: '\2193'; } /* '↓' */ .icn-download:before { content: '\21d3'; } /* '⇓' */ .icn-home:before { content: '\2302'; } /* '⌂' */ .icn-print:before { content: '\2399'; } /* '⎙' */ .icn-check:before { content: '\2611'; } /* '☑' */ .icn-settings:before { content: '\2638'; } /* '☸' */ .icn-alert:before { content: '\26a0'; } /* '⚠' */ .icn-mail:before { content: '\2709'; } /* '✉' */ .icn-edit:before { content: '\270e'; } /* '✎' */ .icn-delete:before { content: '\2718'; } /* '✘' */ .icn-help:before { content: '\2753'; } /* '❓' */ .icn-plus:before { content: '\2795'; } /* '➕' */ .icn-minus:before { content: '\2796'; } /* '➖' */ .icn-logout:before { content: '\291d'; } /* '⤝' */ .icn-eye-off:before { content: '\292b'; } /* '⤫' */ .icn-menu:before { content: '𝍢'; } /* '\1d362' */ .icn-eye:before { content: '👁'; } /* '\1f441' */ .icn-user:before { content: '👤'; } /* '\1f464' */ .icn-users:before { content: '👪'; } /* '\1f46a' */ .icn-attach:before { content: '📎'; } /* '\1f4ce' */ .icn-search:before { content: '🔍'; } /* '\1f50d' */ .icn-lock:before { content: '🔒'; } /* '\1f512' */ .icn-unlock:before { content: '🔓'; } /* '\1f513' */ |
Modified src/www/admin/static/font/garradin.eot from [7ef839bdc8] to [4de801b16e].
cannot compute difference between binary files
Modified src/www/admin/static/font/garradin.svg from [49157899c4] to [5bcfb6f494].
1 2 3 | <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg"> | | > | > > > > > > > > | | > | > > > > > > | | < | | > | > | > | > | > | > | > | > | > | > | > | < | | 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 | <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg"> <metadata>Copyright (C) 2018 by original authors @ fontello.com</metadata> <defs> <font id="garradin" horiz-adv-x="1000" > <font-face font-family="garradin" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" /> <missing-glyph horiz-adv-x="1000" /> <glyph glyph-name="up" unicode="↑" d="M571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" /> <glyph glyph-name="down" unicode="↓" d="M571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" /> <glyph glyph-name="download" unicode="⇓" d="M714 100q0 15-10 25t-25 11-26-11-10-25 10-25 26-11 25 11 10 25z m143 0q0 15-10 25t-26 11-25-11-10-25 10-25 25-11 26 11 10 25z m72 125v-179q0-22-16-37t-38-16h-821q-23 0-38 16t-16 37v179q0 22 16 38t38 16h259l75-76q33-32 76-32t76 32l76 76h259q22 0 38-16t16-38z m-182 318q10-23-8-40l-250-250q-10-10-25-10t-25 10l-250 250q-17 17-8 40 10 21 33 21h143v250q0 15 11 25t25 11h143q14 0 25-11t10-25v-250h143q24 0 33-21z" horiz-adv-x="928.6" /> <glyph glyph-name="home" unicode="⌂" d="M786 296v-267q0-15-11-26t-25-10h-214v214h-143v-214h-214q-15 0-25 10t-11 26v267q0 1 0 2t0 2l321 264 321-264q1-1 1-4z m124 39l-34-41q-5-5-12-6h-2q-7 0-12 3l-386 322-386-322q-7-4-13-4-7 2-12 7l-35 41q-4 5-3 13t6 12l401 334q18 15 42 15t43-15l136-114v109q0 8 5 13t13 5h107q8 0 13-5t5-13v-227l122-102q5-5 6-12t-4-13z" horiz-adv-x="928.6" /> <glyph glyph-name="print" unicode="⎙" d="M214-7h500v143h-500v-143z m0 357h500v214h-89q-22 0-38 16t-16 38v89h-357v-357z m643-36q0 15-10 25t-26 11-25-11-10-25 10-25 25-10 26 10 10 25z m72 0v-232q0-7-6-12t-12-6h-125v-89q0-22-16-38t-38-16h-536q-22 0-37 16t-16 38v89h-125q-7 0-13 6t-5 12v232q0 44 32 76t75 31h36v304q0 22 16 38t37 16h375q23 0 50-12t42-26l85-85q15-16 27-43t11-49v-143h35q45 0 76-31t32-76z" horiz-adv-x="928.6" /> <glyph glyph-name="check" unicode="☑" d="M786 331v-177q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q35 0 65-14 9-4 10-13 2-10-5-16l-27-28q-6-5-13-5-2 0-5 1-13 3-25 3h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v141q0 8 5 13l36 35q6 6 13 6 3 0 7-2 11-4 11-16z m129 273l-455-454q-13-14-31-14t-32 14l-240 240q-14 13-14 31t14 32l61 62q14 13 32 13t32-13l147-147 361 361q13 13 31 13t32-13l62-61q13-14 13-32t-13-32z" horiz-adv-x="928.6" /> <glyph glyph-name="settings" unicode="☸" d="M571 350q0 59-41 101t-101 42-101-42-42-101 42-101 101-42 101 42 41 101z m286 61v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-27 59-77 6-6 6-13t-5-13q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 21l-79-60q-6-5-14-5-8 0-14 6-70 64-92 94-4 5-4 13 0 6 5 12 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 15 20 15h124q7 0 13-4t7-12l15-103q28-9 50-21l80 60q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-13 0-6-4-12-9-12-29-38t-30-39q14-28 23-55l102-15q7-1 12-7t4-13z" horiz-adv-x="857.1" /> <glyph glyph-name="alert" unicode="⚠" d="M571 83v106q0 8-5 13t-12 5h-108q-7 0-12-5t-5-13v-106q0-8 5-13t12-6h108q7 0 12 6t5 13z m-1 208l10 257q0 6-5 10-7 6-14 6h-122q-7 0-14-6-5-4-5-12l9-255q0-5 6-9t13-3h103q8 0 13 3t6 9z m-7 522l428-786q20-35-1-70-10-17-26-26t-35-10h-858q-18 0-35 10t-26 26q-21 35-1 70l429 786q9 17 26 27t36 10 36-10 27-27z" horiz-adv-x="1000" /> <glyph glyph-name="mail" unicode="✉" d="M1000 454v-443q0-37-26-63t-63-27h-822q-36 0-63 27t-26 63v443q25-28 56-49 202-137 278-192 32-24 51-37t53-27 61-13h2q28 0 61 13t53 27 51 37q95 68 278 192 32 22 56 49z m0 164q0-44-27-84t-68-69q-210-146-262-181-5-4-23-17t-30-22-29-18-33-15-27-5h-2q-12 0-27 5t-33 15-29 18-30 22-23 17q-51 35-147 101t-114 80q-35 23-65 64t-31 77q0 43 23 72t66 29h822q36 0 62-26t27-63z" horiz-adv-x="1000" /> <glyph glyph-name="edit" unicode="✎" d="M203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" /> <glyph glyph-name="delete" unicode="✘" d="M724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" /> <glyph glyph-name="help" unicode="❓" d="M393 149v-134q0-9-7-16t-15-6h-134q-9 0-16 6t-7 16v134q0 9 7 16t16 6h134q8 0 15-6t7-16z m176 335q0-30-8-56t-20-43-31-33-32-25-34-19q-23-13-38-37t-15-37q0-10-7-18t-16-9h-134q-8 0-14 10t-6 21v26q0 46 37 87t79 60q33 15 47 32t14 42q0 23-26 41t-60 18q-36 0-60-16-20-14-60-64-7-9-17-9-7 0-14 4l-91 70q-8 6-9 14t3 16q89 148 259 148 45 0 90-17t81-46 59-72 23-88z" horiz-adv-x="571.4" /> <glyph glyph-name="plus" unicode="➕" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q22 0 38-16t16-38z" horiz-adv-x="785.7" /> <glyph glyph-name="minus" unicode="➖" d="M786 439v-107q0-22-16-38t-38-15h-678q-23 0-38 15t-16 38v107q0 23 16 38t38 16h678q22 0 38-16t16-38z" horiz-adv-x="785.7" /> <glyph glyph-name="logout" unicode="⤝" d="M857 350q0-87-34-166t-91-137-137-92-166-34-167 34-136 92-92 137-34 166q0 102 45 191t126 151q24 18 54 14t46-28q18-23 14-53t-28-47q-54-41-84-101t-30-127q0-58 22-111t62-91 91-61 111-23 110 23 92 61 61 91 22 111q0 68-30 127t-84 101q-24 18-28 47t14 53q17 24 47 28t53-14q81-61 126-151t45-191z m-357 429v-358q0-29-21-50t-50-21-51 21-21 50v358q0 29 21 50t51 21 50-21 21-50z" horiz-adv-x="857.1" /> <glyph glyph-name="eye-off" unicode="⤫" d="M0 326q6 49 64 110 79 80 176 128 129 61 260 61 29 0 59-2l74 129q10 16 23 18 4 0 8-2l51-32q17-7 2-33l-57-101-47-79-41-72-144-250-41-72-47-80-57-100q-15-25-31-15l-53 31q-15 8 0 33l49 86-8 4q-103 53-176 129-64 72-64 109z m264 0q0-74 47-133l48 84q-9 24-9 49 0 51 34 91t85 50l49 84-18 0q-98 0-167-66t-69-159z m177-295l41 71 18 0q98 0 167 65t69 159q0 74-47 133l63 109q2-2 4-3t4-1q103-52 176-128 64-73 64-110-6-49-64-109-79-80-176-129-129-61-260-61-25 0-59 4z m90 155l110 189q9-25 9-49 0-51-34-90t-85-50z" horiz-adv-x="1000" /> <glyph glyph-name="menu" unicode="𝍢" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" /> <glyph glyph-name="eye" unicode="👁" d="M0 350q6 49 64 110 79 80 176 129 129 60 260 60 137-2 260-60 103-53 176-129 64-73 64-110-6-49-64-109-79-80-176-129-129-61-260-61-137 2-260 61-103 53-176 129-64 72-64 109z m264 0q0-94 69-159t167-65 167 65 69 159-69 159-167 66-167-66-69-159z m86 1q0 60 44 102t106 42 106-42 44-102-44-102-106-43-106 43-44 102z" horiz-adv-x="1000" /> <glyph glyph-name="user" unicode="👤" d="M786 66q0-67-41-106t-108-39h-488q-67 0-108 39t-41 106q0 30 2 58t8 61 15 60 24 55 34 45 48 30 62 11q5 0 24-12t41-27 60-27 75-12 74 12 61 27 41 27 24 12q34 0 62-11t48-30 34-45 24-55 15-60 8-61 2-58z m-179 498q0-88-63-151t-151-63-152 63-62 151 62 152 152 63 151-63 63-152z" horiz-adv-x="785.7" /> <glyph glyph-name="users" unicode="👪" d="M331 350q-90-3-148-71h-75q-45 0-77 22t-31 66q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143z m598-356q0-66-41-105t-108-39h-488q-68 0-108 39t-41 105q0 30 2 58t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 23 12q35 0 63-11t47-30 35-45 24-54 15-61 8-61 2-58z m-572 713q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z m393-214q0-89-63-152t-151-62-152 62-63 152 63 151 152 63 151-63 63-151z m321-126q0-43-31-66t-77-22h-75q-57 68-147 71 45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197z m-71 340q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z" horiz-adv-x="1071.4" /> <glyph glyph-name="attach" unicode="📎" d="M783 77q0-65-44-109t-109-44q-75 0-131 55l-434 434q-63 64-63 151 0 88 62 150t150 62q88 0 152-63l338-338q5-5 5-12 0-9-17-26t-26-17q-7 0-13 5l-338 339q-44 43-101 43-59 0-100-42t-40-101q0-58 42-101l433-433q35-35 81-35 36 0 59 23t24 59q0 46-36 81l-324 324q-14 14-33 14-16 0-27-11t-11-27q0-18 14-33l229-228q6-6 6-13 0-9-18-26t-26-17q-7 0-12 5l-229 229q-35 34-35 83 0 46 32 78t77 32q49 0 83-36l325-324q55-54 55-131z" horiz-adv-x="785.7" /> <glyph glyph-name="search" unicode="🔍" d="M643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" /> <glyph glyph-name="lock" unicode="🔒" d="M179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" /> <glyph glyph-name="unlock" unicode="🔓" d="M929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" /> </font> </defs> </svg> |
Modified src/www/admin/static/font/garradin.ttf from [4452fdd794] to [2aa8a2bf32].
cannot compute difference between binary files
Modified src/www/admin/static/font/garradin.woff from [c939b61e60] to [ccddd0b63a].
cannot compute difference between binary files
Modified src/www/admin/static/scripts/global.js from [bab9903c66] to [52db09393f].
︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 112 113 114 115 116 | if (elm.onchange) elm.onchange({target: elm}); } } return true; }; var dateInputFallback = function () { /* // Firefox dit implémenter date, mais ne l'implémente pas, aucun moyen de détecter ce cas // donc on force l'utilisation du custom datepicker de Garradin… var input = document.createElement('input'); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | if (elm.onchange) elm.onchange({target: elm}); } } return true; }; g.enhancePasswordField = function (field, repeat_field = null) { var show_password = document.createElement('input'); show_password.type = 'button'; show_password.className = 'icn action showPassword'; show_password.title = 'Voir/cacher le mot de passe'; show_password.value = '👁'; show_password.onclick = function (e) { var pos = field.selectionStart; var hidden = field.type.match(/pass/i); field.type = hidden ? 'text' : 'password'; this.value = !hidden ? '👁' : '⤫'; field.classList.toggle('clearTextPassword'); if (null !== repeat_field) { repeat_field.type = field.type; repeat_field.classList.toggle('clearTextPassword'); } // Remettre le focus sur le champ mot de passe // on ne peut pas vraiment remettre le focus sur le champ // précis qui était utilisé avant de cliquer sur le bouton // car il faudrait enregistrer les actions onfocus de tous // les champs de la page field.focus(); field.selectionStart = field.selectionEnd = pos; }; field.parentNode.insertBefore(show_password, field.nextSibling); }; var dateInputFallback = function () { /* // Firefox dit implémenter date, mais ne l'implémente pas, aucun moyen de détecter ce cas // donc on force l'utilisation du custom datepicker de Garradin… var input = document.createElement('input'); |
︙ | ︙ |
Modified src/www/admin/static/scripts/password.js from [14f90c76a4] to [c16716738c].
1 2 3 4 5 6 7 8 9 | (function () { var strength_elm, match_elm, pw_elm, pw2_elm, suggest_elm; RegExp.quote = function(str) { return (str+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); }; window.initPasswordField = function(suggest, password, password2) { | < > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | (function () { var strength_elm, match_elm, pw_elm, pw2_elm, suggest_elm; RegExp.quote = function(str) { return (str+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); }; window.initPasswordField = function(suggest, password, password2) { pw_elm = (typeof password == 'string') ? document.getElementById(password) : password; pw2_elm = (typeof password2 == 'string') ? document.getElementById(password2) : password2; suggest_elm = (typeof suggest == 'string') ? document.getElementById(suggest) : suggest; g.enhancePasswordField(pw_elm, pw2_elm); suggest_elm.size = suggest_elm.value.length; suggest_elm.onclick = function () { pw_elm.value = this.value; pw2_elm.value = this.value; this.select(); |
︙ | ︙ |
Modified src/www/admin/static/scripts/wiki_editor.js from [2dad10610c] to [e1b49b3d06].
1 2 3 | (function () { var wiki_id = window.location.search.match(/id=(\d+)/)[1]; | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | (function () { var wiki_id = window.location.search.match(/id=(\d+)/)[1]; g.onload(function () { g.style('scripts/wiki_editor.css'); g.script('scripts/text_editor.min.js').onload = function () { var t = new textEditor('f_contenu'); t.parent = t.textarea.parentNode; var toolbar = document.createElement('nav'); toolbar.className = 'te'; var toggleFullscreen = function (e) { var classes = t.parent.className.split(' '); for (var i = 0; i < classes.length; i++) { if (classes[i] == 'fullscreen') { classes.splice(i, 1); t.parent.className = classes.join(' '); t.fullscreen = false; return true; } } classes.push('fullscreen'); t.parent.className = classes.join(' '); t.fullscreen = true; return true; }; var openPreview = function () { openIFrame(''); var form = document.createElement('form'); form.appendChild(t.textarea.cloneNode(true)); form.firstChild.value = t.textarea.value; form.target = 'editorFrame'; form.action = g.admin_url + 'wiki/_preview.php?id=' + wiki_id; form.style.display = 'none'; form.method = 'post'; document.body.appendChild(form); form.submit(); //document.body.removeChild(form); }; var openSyntaxHelp = function () { openIFrame(g.admin_url + 'wiki/_syntaxe.html'); }; var openFileInsert = function () { openIFrame(g.admin_url + 'wiki/_fichiers.php?page=' + wiki_id); }; window.te_insertFile = function (file) { var tag = '<<fichier|'+file+'>>'; t.insertAtPosition(t.getSelection().start, tag); closeIFrame(); }; window.te_insertImage = function (file, position, caption) { var tag = '<<image|' + file; if (position) tag += '|' + position; if (caption) tag += '|' + caption; tag += '>>'; t.insertAtPosition(t.getSelection().start, tag); closeIFrame(); }; var openIFrame = function(url) { if (t.iframe && t.iframe.src == t.base_url + url) { t.iframe.className = ''; t.parent.className += ' iframe'; return true; } else if (t.iframe) { t.parent.removeChild(t.iframe); t.iframe = null; } var w = t.textarea.offsetWidth, h = t.textarea.offsetHeight; var iframe = document.createElement('iframe'); iframe.width = w; iframe.height = h; iframe.src = url; iframe.name = 'editorFrame'; iframe.frameborder = '0'; iframe.scrolling = 'yes'; t.parent.appendChild(iframe); t.parent.className += ' iframe'; t.iframe = iframe; }; var closeIFrame = function () { t.parent.className = t.parent.className.replace(/ iframe$/, ''); t.iframe.className = 'hidden'; }; var appendButton = function (name, title, action, altTitle) { var btn = document.createElement('input'); btn.type = 'button'; btn.title = altTitle ? altTitle : title; btn.value = title; btn.className = name; btn.onclick = function () { action.call(); return false; }; toolbar.appendChild(btn); return btn; }; var wrapTags = function (left, right) { t.wrapSelection(t.getSelection(), left, right); return true; }; appendButton('title', "== Titre", function () { wrapTags("== ", ""); } ); appendButton('bold', '**gras**', function () { wrapTags('**', '**'); } ); appendButton('italic', "''italique''", function () { wrapTags("''", "''"); } ); appendButton('link', "[[lien|http://]]", function () { if (url = window.prompt('Adresse URL ?')) wrapTags("[[", "|" + url + ']]'); } ); appendButton('icnl file', "📎", openFileInsert, 'Insérer fichier / image'); appendButton('ext icnl preview', '⎙', openPreview, 'Prévisualiser'); appendButton('ext icnl help', '❓', openSyntaxHelp, 'Aide sur la syntaxe'); appendButton('ext fullscreen', 'Plein écran', toggleFullscreen, 'Plein écran'); appendButton('ext close', 'Fermer', closeIFrame); t.parent.insertBefore(toolbar, t.parent.firstChild); t.shortcuts.push({key: 'F11', callback: toggleFullscreen}); t.shortcuts.push({ctrl: true, key: 'b', callback: function () { return wrapTags('**', '**'); } }); t.shortcuts.push({ctrl: true, key: 'g', callback: function () { return wrapTags('**', '**'); } }); t.shortcuts.push({ctrl: true, key: 'i', callback: function () { return wrapTags("''", "''"); } }); if (window.location.hash.match(/fullscreen/)) { t.toggleFullscreen(); window.location.hash = ''; } }; }); }()); |
Modified src/www/admin/upgrade.php from [4dda8f7462] to [a960b884a1].
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 | <?php namespace Garradin; const UPGRADE_PROCESS = true; require_once __DIR__ . '/../../include/init.php'; $config = Config::getInstance(); $v = $config->getVersion(); if (version_compare($v, garradin_version(), '>=')) { throw new UserException("Pas de mise à jour à faire."); } Install::checkAndCreateDirectories(); if (Static_Cache::exists('upgrade')) { $path = Static_Cache::getPath('upgrade'); throw new UserException('Une mise à jour est déjà en cours.' . PHP_EOL . 'Si celle-ci a échouée et que vous voulez ré-essayer, supprimez le fichier suivant:' . PHP_EOL . $path); } Static_Cache::store('upgrade', 'Mise à jour en cours.'); $db = DB::getInstance(); $redirect = true; // Créer une sauvegarde automatique | > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; use Garradin\Membres\Session; const UPGRADE_PROCESS = true; require_once __DIR__ . '/../../include/init.php'; $config = Config::getInstance(); $v = $config->getVersion(); if (version_compare($v, garradin_version(), '>=')) { throw new UserException("Pas de mise à jour à faire."); } // versions pré-0.7.0: démerdez-vous ! if (!$v || version_compare($v, '0.7.0', '<')) { throw new UserException("Votre version de Garradin est trop ancienne pour être mise à jour. Mettez à jour vers Garradin 0.8.5 avant de faire la mise à jour vers cette version."); } Install::checkAndCreateDirectories(); if (Static_Cache::exists('upgrade')) { $path = Static_Cache::getPath('upgrade'); throw new UserException('Une mise à jour est déjà en cours.' . PHP_EOL . 'Si celle-ci a échouée et que vous voulez ré-essayer, supprimez le fichier suivant:' . PHP_EOL . $path); } // Voir si l'utilisateur est loggé, on le fait ici pour le cas où // il y aurait déjà eu des entêtes envoyés au navigateur plus bas $session = new Session; $user_is_logged = $session->isLogged(true); Static_Cache::store('upgrade', 'Mise à jour en cours.'); $db = DB::getInstance(); $redirect = true; // Créer une sauvegarde automatique |
︙ | ︙ | |||
50 51 52 53 54 55 56 | <div id="loader" class="loader" style="margin: 2em 0; height: 50px;"></div> <script> animatedLoader(document.getElementById("loader"), 5); </script>'; flush(); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | <div id="loader" class="loader" style="margin: 2em 0; height: 50px;"></div> <script> animatedLoader(document.getElementById("loader"), 5); </script>'; flush(); if (version_compare($v, '0.7.0', '<')) { $db->exec('PRAGMA foreign_keys = OFF; BEGIN;'); // Mise à jour base de données $db->exec(file_get_contents(ROOT . '/include/data/0.7.0.sql')); |
︙ | ︙ | |||
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | { $db->begin(); $db->import(ROOT . '/include/data/0.8.4.sql'); $db->commit(); } Utils::clearCaches(); $config->setVersion(garradin_version()); Static_Cache::remove('upgrade'); echo '<h2>Mise à jour terminée.</h2> <p><a href="'.ADMIN_URL.'">Retour</a></p>'; if ($redirect) { echo ' | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | { $db->begin(); $db->import(ROOT . '/include/data/0.8.4.sql'); $db->commit(); } if (version_compare($v, '0.9.0', '<')) { $db->exec('PRAGMA foreign_keys = OFF;'); $db->begin(); $db->import(ROOT . '/include/data/0.9.0.sql'); // Correction des ID parents des comptes qui ont été mal renseignés // exemple : compte 512A avec "5" comme parent (c'était permis, // par erreur, par le formulaire d'ajout de compte dans le plan) // Serait probablement possible en 3-4 lignes de SQL avec // WITH RECURSIVE mais c'est au delà de mes compétences $comptes = $db->iterate('SELECT id FROM compta_comptes WHERE parent != length(id) - 1;'); foreach ($comptes as $compte) { $parent = false; $id = $compte->id; while (!$parent && strlen($id)) { // On enlève un caractère à la fin jusqu'à trouver un compte parent correspondant $id = substr($id, 0, -1); $parent = $db->firstColumn('SELECT id FROM compta_comptes WHERE id = ?;', $id); } if (!$parent) { // Situation normalement impossible ! throw new \LogicException(sprintf('Le compte %s est invalide et n\'a pas de compte parent possible !', $compte->id)); } $db->update('compta_comptes', ['parent' => $parent], 'id = :id', ['id' => $compte->id]); } $db->commit(); $config->set('desactiver_site', false); $config->save(); } Utils::clearCaches(); $config->setVersion(garradin_version()); Static_Cache::remove('upgrade'); // Réinstaller les plugins système si nécessaire Plugin::checkAndInstallSystemPlugins(); // Mettre à jour les plugins si nécessaire foreach (Plugin::listInstalled() as $id=>$infos) { // Ne pas tenir compte des plugins dont le code n'est pas dispo if ($infos->disabled) { continue; } $plugin = new Plugin($id); if ($plugin->needUpgrade()) { $plugin->upgrade(); } unset($plugin); } // Forcer à rafraîchir les données de la session si elle existe if ($user_is_logged) { $session->refresh(); } echo '<h2>Mise à jour terminée.</h2> <p><a href="'.ADMIN_URL.'">Retour</a></p>'; if ($redirect) { echo ' |
︙ | ︙ |
Modified src/www/index.php from [36cb4b20f1] to [f59003a96f].
1 2 3 4 5 6 7 8 | <?php namespace Garradin; require __DIR__ . '/_inc.php'; $squelette = new Squelette; $squelette->dispatchURI(); | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; require __DIR__ . '/_inc.php'; if (Config::getInstance()->get('desactiver_site')) { Utils::redirect(ADMIN_URL); } $squelette = new Squelette; $squelette->dispatchURI(); |