Index: VERSION
==================================================================
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
-0.4.5
+0.5.0
Index: include/class.champs_membres.php
==================================================================
--- include/class.champs_membres.php
+++ include/class.champs_membres.php
@@ -12,10 +12,11 @@
'checkbox' => 'Case à cocher',
'multiple' => 'Combinaison de cases à cocher',
'date' => 'Date',
'datetime' => 'Date et heure',
'file' => 'Fichier',
+ 'password' => 'Mot de passe',
'number' => 'Numéro',
'tel' => 'Numéro de téléphone',
'select' => 'Sélecteur de choix',
'country' => 'Sélecteur de pays',
'text' => 'Texte',
@@ -27,40 +28,37 @@
'title',
'help',
'editable',
'mandatory',
'private',
- 'values'
+ 'options'
);
static protected $presets = null;
public function __toString()
{
- return json_encode($this->champs);
- }
-
- static public function import()
- {
- $json = file_get_contents(GARRADIN_ROOT . '/include/data/champs_membres.json');
- $json = preg_replace('!/[*].*?[*]/!s', '', $json);
- return new Champs_Membres($json);
+ return utils::write_ini_string($this->champs);
+ }
+
+ public function toString()
+ {
+ return utils::write_ini_string($this->champs);
+ }
+
+ static public function importInstall()
+ {
+ $champs = parse_ini_file(GARRADIN_ROOT . '/include/data/champs_membres.ini', true);
+ $champs = array_filter($champs, function ($row) { return !empty($row['install']); });
+ return new Champs_Membres($champs);
}
static public function importPresets()
{
if (is_null(self::$presets))
{
- $json = file_get_contents(GARRADIN_ROOT . '/include/data/champs_membres.json');
- $json = preg_replace('!/[*].*?[*]/!s', '', $json);
- $champs = json_decode($json, true);
-
- $json = file_get_contents(GARRADIN_ROOT . '/include/data/champs_membres_supplementaires.json');
- $json = preg_replace('!/[*].*?[*]/!s', '', $json);
- $champs_supplementaires = json_decode($json, true);
-
- self::$presets = array_merge($champs, $champs_supplementaires);
+ self::$presets = parse_ini_file(GARRADIN_ROOT . '/include/data/champs_membres.ini', true);
}
return self::$presets;
}
@@ -73,24 +71,51 @@
{
if ($champs instanceOf Champs_Membres)
{
$this->champs = $champs->getAll();
}
+ elseif (is_array($champs))
+ {
+ foreach ($champs as $key=>&$config)
+ {
+ $this->_checkField($key, $config);
+ }
+
+ $this->champs = $champs;
+ }
else
{
- $this->champs = json_decode((string)$champs, true);
+ $champs = parse_ini_string((string)$champs, true);
+
+ foreach ($champs as $key=>&$config)
+ {
+ $this->_checkField($key, $config);
+ }
+
+ $this->champs = $champs;
}
}
public function getTypes()
{
return $this->types;
}
- public function get($key)
+ public function get($champ, $key = null)
{
- return $this->champs[$key];
+ if (!array_key_exists($champ, $this->champs))
+ return null;
+
+ if ($key !== null)
+ {
+ if (array_key_exists($key, $this->champs[$champ]))
+ return $this->champs[$champ][$key];
+ else
+ return null;
+ }
+
+ return $this->champs[$champ];
}
public function getAll()
{
return $this->champs;
@@ -107,12 +132,19 @@
if (!preg_match('!^\w+(_\w+)*$!', $name))
{
throw new UserException('Le nom du champ est invalide.');
}
- foreach ($config as $key=>&$value)
+ foreach ($config as $key=>&$value)
{
+ // Champ install non pris en compte
+ if ($key == 'install')
+ {
+ unset($config[$key]);
+ continue;
+ }
+
if (!in_array($key, $this->config_fields))
{
throw new \BadMethodCallException('Champ '.$key.' non valide.');
}
@@ -122,26 +154,50 @@
}
elseif ($key == 'help' || $key == 'title')
{
$value = trim((string) $value);
}
+ elseif ($key == 'options')
+ {
+ $value = (array) $value;
+ }
}
if (empty($config['title']))
{
- throw new UserException('Le titre est obligatoire.');
+ throw new UserException('Champ "'.$name.'" : Le titre est obligatoire.');
}
if (empty($config['type']) || !array_key_exists($config['type'], $this->types))
{
- throw new UserException('Le type est vide ou non valide.');
+ throw new UserException('Champ "'.$name.'" : Le type est vide ou non valide.');
}
if ($name == 'email' && $config['type'] != 'email')
{
throw new UserException('Le champ email ne peut être d\'un type différent de email.');
}
+
+ if ($name == 'passe' && $config['type'] != 'password')
+ {
+ throw new UserException('Le champ mot de passe ne peut être d\'un type différent de email.');
+ }
+
+ if (!array_key_exists('editable', $config))
+ {
+ $config['editable'] = false;
+ }
+
+ if (!array_key_exists('mandatory', $config))
+ {
+ $config['mandatory'] = false;
+ }
+
+ if (!array_key_exists('private', $config))
+ {
+ $config['private'] = false;
+ }
return true;
}
/**
@@ -166,11 +222,21 @@
* @param mixed $value Valeur à affecter
* @return boolean true
*/
public function set($champ, $key, $value)
{
- $this->champs[$champs][$key] = $value;
+ if (!isset($this->champs[$champ]))
+ {
+ throw new \LogicException('Champ "'.$champ.'" inconnu.');
+ }
+
+ // Vérification
+ $config = $this->champs[$champ];
+ $config[$key] = $value;
+ $this->_checkField($champ, $config);
+
+ $this->champs[$champ] = $config;
return true;
}
/**
* Modifie les champs en interne en vérifiant que tout va bien
@@ -182,11 +248,16 @@
if (!array_key_exists('email', $champs))
{
throw new UserException('Le champ E-Mail ne peut être supprimé des fiches membres.');
}
- foreach ($champs as $name=>$config)
+ if (!array_key_exists('passe', $champs))
+ {
+ throw new UserException('Le champ Mot de passe ne peut être supprimé des fiches membres.');
+ }
+
+ foreach ($champs as $name=>&$config)
{
$this->_checkField($name, $config);
}
$this->champs = $champs;
@@ -212,23 +283,22 @@
// Champs à créer
$create = array(
'id INTEGER PRIMARY KEY, -- Numéro attribué automatiquement',
'id_categorie INTEGER NOT NULL, -- Numéro de catégorie',
- 'passe TEXT NULL, -- Mot de passe',
'date_connexion TEXT NULL, -- Date de dernière connexion',
);
// Champs à recopier
$copy = array(
'id',
'id_categorie',
- 'passe',
'date_connexion'
);
- $anciens_champs = $config->get('champs_membres')->getAll();
+ $anciens_champs = $config->get('champs_membres');
+ $anciens_champs = is_null($anciens_champs) ? $this->champs : $anciens_champs->getAll();
foreach ($this->champs as $key=>$cfg)
{
if ($cfg['type'] == 'number')
$type = 'FLOAT';
Index: include/class.config.php
==================================================================
--- include/class.config.php
+++ include/class.config.php
@@ -19,10 +19,11 @@
{
}
protected function __construct()
{
+ // Définition des types de données stockées
$string = '';
$int = 0;
$float = 0.0;
$array = array();
$bool = false;
@@ -121,15 +122,20 @@
return true;
}
public function get($key)
{
- if (!array_key_exists($key, $this->config))
+ if (!array_key_exists($key, $this->fields_types))
{
throw new \OutOfBoundsException('Ce champ est inconnu.');
}
+ if (!array_key_exists($key, $this->config))
+ {
+ return null;
+ }
+
return $this->config[$key];
}
public function getVersion()
{
Index: include/class.membres.php
==================================================================
--- include/class.membres.php
+++ include/class.membres.php
@@ -519,11 +519,11 @@
$date_verif = time();
if (!$date_membre)
return false;
- $echeance = new \DateTime('@'.$date_membre);
+ $echeance = new \DateTime($date_membre);
$echeance->setTime(0, 0);
$echeance->modify('+'.$duree_cotisation.' months');
if ($echeance->getTimestamp() < $date_verif)
return round(($date_verif - $echeance->getTimestamp()) / 3600 / 24);
Index: include/class.wiki.php
==================================================================
--- include/class.wiki.php
+++ include/class.wiki.php
@@ -226,11 +226,11 @@
{
return true;
}
// Il faut obligatoirement fournir un ID d'auteur
- if (empty($data['id_auteur']))
+ if (empty($data['id_auteur']) && $data['id_auteur'] !== null)
{
throw new \BadMethodCallException('Aucun ID auteur de fourni.');
}
$contenu = $db->simpleQuerySingle('SELECT contenu FROM wiki_revisions WHERE revision = ? AND id_page = ?;', false, (int)$revision, (int)$id);
ADDED include/data/champs_membres.ini
Index: include/data/champs_membres.ini
==================================================================
--- include/data/champs_membres.ini
+++ include/data/champs_membres.ini
@@ -0,0 +1,124 @@
+; Ce fichier contient la configuration par défaut des champs des fiches membres.
+; La configuration est ensuite enregistrée au format INI dans la table
+; config de la base de données.
+;
+; Syntaxe :
+;
+; [nom_du_champ] ; Nom unique du champ, ne peut contenir que des lettres et des tirets bas
+; type = text
+; title = "Super champ trop cool"
+; mandatory = true
+; editable = false
+;
+; Description des options possibles pour chaque champ :
+;
+; type: (défaut: text) OBLIGATOIRE
+; tous les types gérés par input type de HTML5 plus :
+; + country = sélecteur de pays
+; + checkbox = case à cocher
+; + multiple = multiples cases à cocher (jusqu'à 32, binaire)
+; + select = un choix parmis plusieurs
+; title: OBLIGATOIRE
+; Titre du champ
+; help:
+; Texte d'aide sur les fiches membres
+; options[]:
+; pour définir les options d'un champ de type select ou multiple
+; editable:
+; true = modifiable par le membre
+; false = modifiable uniquement par un admin (défaut)
+; mandatory:
+; true = obligatoire, la fiche membre ne pourra être enregistrée si ce champ est vide
+; false = facultatif (défaut)
+; private:
+; true = non visible par le membre lui-même
+; false = visible par le membre (défaut)
+; install:
+; true = sera ajouté aux fiches membres à l'installation
+; false = sera seulement présent dans les champs supplémentaires possibles (défaut)
+
+[nom]
+type = text
+title = "Nom & prénom"
+mandatory = true
+install = true
+editable = true
+
+[email]
+type = email
+title = "Adresse E-Mail"
+mandatory = true
+install = true
+editable = true
+
+[passe]
+type = password
+title = "Mot de passe"
+mandatory = true
+install = true
+editable = true
+
+[adresse]
+type = textarea
+title = "Adresse postale"
+help = "Indiquer ici le numéro, le type de voie, etc."
+install = true
+editable = true
+
+[code_postal]
+type = text
+title = "Code postal"
+install = true
+editable = true
+
+[ville]
+type = text
+title = "Ville"
+install = true
+editable = true
+
+[pays]
+type = country
+title = "Pays"
+install = true
+editable = true
+
+[telephone]
+type = tel
+title = "Numéro de téléphone"
+install = true
+editable = true
+
+[lettre_infos]
+type = checkbox
+title = "Inscription à la lettre d'information"
+install = true
+editable = true
+
+[groupe_travail]
+type = multiple
+title = "Groupes de travail"
+editable = false
+options[] = "Télécoms"
+options[] = "Trésorerie"
+options[] = "Relations publiques"
+options[] = "Communication presse"
+options[] = "Organisation d'événements"
+
+[date_naissance]
+type = date
+title = "Date de naissance"
+editable = true
+
+[notes]
+type = textarea
+title = "Notes"
+editable = false
+private = true
+
+[date_inscription]
+type = date
+title = "Date d'inscription"
+editable = false
+mandatory = true
+private = true
DELETED include/data/champs_membres.json
Index: include/data/champs_membres.json
==================================================================
--- include/data/champs_membres.json
+++ include/data/champs_membres.json
@@ -1,84 +0,0 @@
-/*
- Descriptif :
- --
-
- type: (défaut: text)
- tous les types gérés par input type de HTML5
- + country = sélecteur de pays
- + checkbox = case à cocher
- + multiple = multiples cases à cocher (jusqu'à 32, binaire)
- + select = un choix parmis plusieurs
- value: (défaut: vide)
- valeur du champ par défaut, ou plusieurs valeurs pour select/multiple
- editable: (défaut: true)
- true = modifiable par le membre
- false = modifiable uniquement par un admin
- mandatory: (défaut: false)
- true = obligatoire
- false = facultatif
- title: (obligatoire)
- Titre du champ
- help: (facultatif)
- Texte d'aide sur les fiches membres
- private: (défaut: false)
- true = non visible par le membre lui-même
- false = visible par le membre
- */
-{
- "nom":
- {
- "type": "text",
- "title": "Nom & prénom",
- "editable": true,
- "mandatory": true
- },
- "email":
- {
- "type": "email",
- "title": "Adresse E-Mail",
- "editable": true,
- "mandatory": true
- },
- "adresse":
- {
- "type": "textarea",
- "title": "Adresse postale (rue, numéro, immeuble, etc.)",
- "editable": true,
- "mandatory": false
- },
- "code_postal":
- {
- "type": "text",
- "title": "Code postal",
- "editable": true,
- "mandatory": false
- },
- "ville":
- {
- "type": "text",
- "title": "Ville",
- "editable": true,
- "mandatory": false
- },
- "pays":
- {
- "type": "country",
- "title": "Pays",
- "editable": true,
- "mandatory": true
- },
- "telephone":
- {
- "type": "tel",
- "title": "Numéro de téléphone",
- "editable": true,
- "mandatory": false
- },
- "lettre_infos":
- {
- "type": "checkbox",
- "title": "Inscription à la lettre d'informations",
- "editable": true,
- "mandatory": false
- }
-}
DELETED include/data/champs_membres_supplementaires.json
Index: include/data/champs_membres_supplementaires.json
==================================================================
--- include/data/champs_membres_supplementaires.json
+++ include/data/champs_membres_supplementaires.json
@@ -1,38 +0,0 @@
-{
- "groupe_travail":
- {
- "type": "multiple",
- "title": "Groupe de travail",
- "editable": false,
- "mandatory": false,
- "values": [
- "Télécom",
- "Trésorerie",
- "Relations publiques",
- "Organisation d'événements"
- ]
- },
- "date_naissance":
- {
- "type": "date",
- "title": "Date de naissance",
- "editable": true,
- "mandatory": false
- },
- "notes":
- {
- "type": "textarea",
- "title": "Notes",
- "editable": false,
- "mandatory": false,
- "private": true
- },
- "date_inscription":
- {
- "type": "date",
- "title": "Date d'inscription",
- "editable": false,
- "mandatory": true,
- "private": true
- }
-}
Index: include/init.php
==================================================================
--- include/init.php
+++ include/init.php
@@ -169,10 +169,11 @@
static protected $libs = array(
'utils',
'squelette_filtres',
'static_cache',
+ 'template'
);
/**
* Loads a class from the $name
* @param stringg $classname
ADDED include/lib.template.php
Index: include/lib.template.php
==================================================================
--- include/lib.template.php
+++ include/lib.template.php
@@ -0,0 +1,489 @@
+cache = false;
+
+ $this->compile_dir = GARRADIN_ROOT . '/cache/compiled';
+ $this->template_dir = GARRADIN_ROOT . '/templates';
+
+ $this->compile_check = true;
+
+ $this->reserved_template_varname = 'tpl';
+
+ $this->assign('www_url', WWW_URL);
+ $this->assign('self_url', utils::getSelfUrl());
+
+ $this->assign('is_logged', false);
+ }
+}
+
+$tpl = Template::getInstance();
+
+$tpl->assign('config', Config::getInstance()->getConfig());
+
+function tpl_csrf_field($params)
+{
+ $name = utils::CSRF_field_name($params['key']);
+ $value = utils::CSRF_create($params['key']);
+
+ return '';
+}
+
+function tpl_form_field($params)
+{
+ $name = $params['name'];
+
+ if (isset($_POST[$name]))
+ $value = $_POST[$name];
+ elseif (isset($params['data']) && isset($params['data'][$name]))
+ $value = $params['data'][$name];
+ elseif (isset($params['default']))
+ $value = $params['default'];
+ else
+ $value = '';
+
+ if (isset($params['checked']))
+ {
+ if ($value == $params['checked'])
+ return ' checked="checked" ';
+
+ return '';
+ }
+
+ return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
+}
+
+function tpl_format_tel($n)
+{
+ $n = preg_replace('![^\d\+]!', '', $n);
+ $n = preg_replace('!(\+?\d{2})!', '\\1 ', $n);
+ return $n;
+}
+
+function tpl_strftime_fr($ts, $format)
+{
+ return utils::strftime_fr($format, $ts);
+}
+
+function tpl_date_fr($ts, $format)
+{
+ return utils::date_fr($format, $ts);
+}
+
+function tpl_format_droits($params)
+{
+ $droits = $params['droits'];
+
+ $out = array('connexion' => '', 'inscription' => '', 'membres' => '', 'compta' => '',
+ 'wiki' => '', 'config' => '');
+ $classes = array(
+ Membres::DROIT_AUCUN => 'aucun',
+ Membres::DROIT_ACCES => 'acces',
+ Membres::DROIT_ECRITURE=> 'ecriture',
+ Membres::DROIT_ADMIN => 'admin',
+ );
+
+ foreach ($droits as $cle=>$droit)
+ {
+ $cle = str_replace('droit_', '', $cle);
+
+ if (array_key_exists($cle, $out))
+ {
+
+ $class = $classes[$droit];
+ $desc = false;
+ $s = false;
+
+ if ($cle == 'connexion')
+ {
+ if ($droit == Membres::DROIT_AUCUN)
+ $desc = 'N\'a pas le droit de se connecter';
+ else
+ $desc = 'A le droit de se connecter';
+ }
+ elseif ($cle == 'inscription')
+ {
+ if ($droit == Membres::DROIT_AUCUN)
+ $desc = 'N\'a pas le droit de s\'inscrire seul';
+ else
+ $desc = 'A le droit de s\'inscrire seul';
+ }
+ elseif ($cle == 'config')
+ {
+ $s = '☑';
+
+ if ($droit == Membres::DROIT_AUCUN)
+ $desc = 'Ne peut modifier la configuration';
+ else
+ $desc = 'Peut modifier la configuration';
+ }
+ elseif ($cle == 'compta')
+ {
+ $s = '€';
+ }
+
+ if (!$s)
+ $s = strtoupper($cle[0]);
+
+ if (!$desc)
+ {
+ $desc = ucfirst($cle). ' : ';
+
+ if ($droit == Membres::DROIT_AUCUN)
+ $desc .= 'Pas accès';
+ elseif ($droit == Membres::DROIT_ACCES)
+ $desc .= 'Lecture uniquement';
+ elseif ($droit == Membres::DROIT_ECRITURE)
+ $desc .= 'Lecture & écriture';
+ else
+ $desc .= 'Administration';
+ }
+
+ $out[$cle] = ''.$s.'';
+ }
+ }
+
+ return implode(' ', $out);
+}
+
+function tpl_format_wiki($str)
+{
+ $str = utils::htmlLinksOnUrls($str);
+ $str = utils::htmlSpip($str);
+ $str = utils::htmlGarbage2xhtml($str);
+ return $str;
+}
+
+function tpl_liens_wiki($str, $prefix)
+{
+ return preg_replace_callback('!!i', function ($matches) use ($prefix) {
+ return '';
+ }, $str);
+}
+
+function tpl_pagination($params)
+{
+ if (!isset($params['url']) || !isset($params['page']) || !isset($params['bypage']) || !isset($params['total']))
+ throw new \BadFunctionCallException("Paramètre manquant pour pagination");
+
+ if ($params['total'] == -1)
+ return '';
+
+ $pagination = utils::getGenericPagination($params['page'], $params['total'], $params['bypage']);
+
+ if (empty($pagination))
+ return '';
+
+ $out = '';
+
+ foreach ($pagination as &$page)
+ {
+ $attributes = '';
+
+ if (!empty($page['class']))
+ $attributes .= ' class="' . htmlspecialchars($page['class']) . '" ';
+
+ $out .= '
';
+
+ return $out;
+}
+
+function tpl_diff($params)
+{
+ if (!isset($params['old']) || !isset($params['new']))
+ {
+ throw new Template_Exception('Paramètres old et new requis.');
+ }
+
+ $old = $params['old'];
+ $new = $params['new'];
+
+ require_once GARRADIN_ROOT . '/include/libs/diff/class.simplediff.php';
+ $diff = simpleDiff::diff_to_array(false, $old, $new, 3);
+
+ $out = '
'.($i+1).' | '; + $out .= ''.$t1.' | '; + $out .= ''.$old.' | '; + $out .= ''.$t2.' | '; + $out .= ''.$new.' | '; + $out .= '