Changes In Branch dev Through [a5c1d5d229] Excluding Merge-Ins

This is equivalent to a diff from a0c15d9d73 to a5c1d5d229

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-03
14:56
Redécoupage de la partie "Sauvegarde et restauration" de la configuration, ajout d'une constante permettant de désactiver les sauvegardes automatiques check-in: 1365430651 user: bohwaz tags: dev
14:03
Corrections diverses sous menu configuration check-in: a5c1d5d229 user: bohwaz tags: dev
2018-08-02
23:53
Correctif : utiliser la fonction JS checkUncheck globale, pas une copie locale check-in: 9d4ada3a11 user: bohwaz tags: dev
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/VERSION from [d1cc680d2c] to [37225f3c32].

1
0.8.5
|
1
0.9.0

Modified src/cron.php from [d4a8acbd51] to [12f97b4850].

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22


23
24
25

if ($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();







<







>
>



8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26

if ($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();
}

(new Email)->runQueue();

// Nettoyage du cache statique
Static_Cache::clean();

Added src/include/data/0.9.0.sql version [3ad6108e5f].

































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
-- 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;

Modified src/include/data/schema.sql from [80be656e5d] to [3637608e49].

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 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,
    description TEXT 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,







<







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
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,

    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)
);

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)







>

















|







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
401
402
403
404
405
406
407
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 emails_attente (
-- Emails en attente d'expédition (queue d'envoi)
    id INTEGER NOT NULL PRIMARY KEY,
    adresse TEXT NOT NULL,
    id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE,
    sujet TEXT NOT NULL,
    contenu TEXT NOT NULL,
    date_envoi TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_envoi) IS NOT NULL AND datetime(date_envoi) = date_envoi),
    statut INTEGER NOT NULL DEFAULT 0 -- 0 = en attente, 1 = en cours d'envoi
);

CREATE TABLE IF NOT EXISTS emails_rejets (
-- Adresses email qui ne peuvent recevoir de message
    adresse TEXT NOT NULL PRIMARY KEY,
    date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
    message TEXT NOT NULL,
    statut INTEGER NOT NULL DEFAULT 0 -- -1 = désinscription à l'initiative de l'utilisateur, -2 = boîte mail inexistante, >= 1 = nombre de rejets temporaire
);

Added src/include/lib/Garradin/Email.php version [14773bb5c2].





















































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
<?php

namespace Garradin;

use KD2\Security;
use KD2\SMTP;

class Email
{
	const STATUT_ATTENTE_ENVOI = 0;
	const STATUT_EN_COURS_ENVOI = 1;

	/**
	 * Valeur de blocage pour les emails qui ont demandé à ne plus recevoir de message
	 */
	const REJET_OPTOUT = -1;

	/**
	 * Valeur de blocage pour les emails qui sont revenus avec une erreur permanente
	 */
	const REJET_DEFINITIF = -2;

	/**
	 * Seuil à partir duquel on n'essaye plus d'envoyer de message à cette adresse
	 */
	const REJET_ABANDON = 3;

	/**
	 * Renvoie la liste des emails en attente d'envoi dans la queue,
	 * sauf ceux qui correspondent à des adresses bloquées
	 * @return array
	 */
	public function listQueue()
	{
		// Nettoyage de la queue déjà
		$this->purgeQueueFromRejected();
		return DB::getInstance()->get('SELECT * FROM emails_attente	WHERE statut = ?;', self::STATUT_ATTENTE_ENVOI);
	}

	/**
	 * Ajoute un message à la queue d'envoi
	 * @param  string $to        Destinataire
	 * @param  string $subject   Sujet du message
	 * @param  string $content   Contenu
	 * @param  integer $id_membre ID membre (facultatif)
	 * @param  string $pgp_key   Clé PGP, si renseigné le message sera chiffré à l'aide de cette clé
	 * @return boolean
	 */
	public function appendToQueue($to, $subject, $content, $id_membre = null, $pgp_key = null)
	{
		// Ne pas envoyer de mail à des adresses invalides
		if (!SMTP::checkEmailIsValid($to, false))
		{
			throw new UserException('Adresse email invalide: ' . $to);
		}

		if ($pgp_key)
		{
			$content = Security::encryptWithPublicKey($pgp_key, $content);
		}

		$content = wordwrap($content);
		$content = trim($content);

		return DB::getInstance()->insert('emails_attente', [
			'adresse'   => $to,
			'id_membre' => (int) $id_membre ?: null,
			'sujet'     => $subject,
			'contenu'   => $content,
		]);
	}

	/**
	 * Lance la queue d'envoi
	 * @return void
	 */
	public function runQueue()
	{
		$res = DB::getInstance()->iterate('SELECT * FROM emails_attente	WHERE statut = ?;', self::STATUT_ATTENTE_ENVOI);

		foreach ($res as $row)
		{
			$this->mail($row->adresse, $row->sujet, $row->message);
		}
	}

	/**
	 * Supprime de la queue les messages liés à des adresses invalides
	 * ou qui ne souhaitent plus recevoir de message
	 * @return boolean
	 */
	public function purgeQueueFromRejected()
	{
		return DB::getInstance()->delete('emails_attente',
			'adresse IN (SELECT adresse FROM emails_rejets WHERE r.statut < 0 OR r.statut > ?)',
			self::REJET_ABANDON);
	}

	/**
	 * Change le statut d'un message dans la queue d'envoi
	 * @param integer $id
	 * @param integer $status
	 * @return boolean
	 */
	public function setMessageStatusInQueue($id, $status)
	{
		if (!in_array($status, [self::STATUT_ATTENTE_ENVOI, self::STATUT_EN_COURS_ENVOI]))
		{
			throw new \UnexpectedValueException('Statut inconnu: ' . $status);
		}

		return DB::getInstance()->update('emails_attente', ['statut' => $status], 'id = ' . (int)$id);
	}

	/**
	 * Supprime un message de la queue d'envoi
	 * @param  integer $id
	 * @return boolean
	 */
	public function deleteFromQueue($id)
	{
		return DB::getInstance()->delete('emails_attente', 'id = ?', (int)$id);
	}

	/**
	 * Tente de trouver le statut de rejet (définitif ou temporaire) d'un message à partir du message d'erreur reçu
	 * @param  string $error_message
	 * @return integer|null
	 */
	public function guessRejectionStatus($error_message)
	{
		if (preg_match('/unavailable|doesn\'t\s*have|quota|does\s*not\s*exist|invalid|Unrouteable|unknown|illegal/i', $error_message))
		{
			return self::REJET_DEFINITIF;
		}
		elseif (preg_match('/rejete|rejected|spam\s*detected|Service\s*refus|greylist/i', $error_message))
		{
			return 1;
		}

		return null;
	}

	/**
	 * Met à jour le statut de rejet d'une adresse
	 * @param string $address
	 * @param integer $status
	 * @param string $message
	 * @return boolean
	 */
	public function setRejectedStatus($address, $status, $message)
	{
		$address = strtolower(trim($address));

		if (!SMTP::checkEmailIsValid($address, false))
		{
			return false;
		}

		if ($status < 0 && !in_array($status, [self::REJET_DEFINITIF, self::REJET_OPTOUT]))
		{
			throw new \UnexpectedValueException('Statut inconnu: ' . $status);
		}

		if ($status == 0)
		{
			throw new \UnexpectedValueException('Statut invalide');
		}

		return DB::getInstance()->preparedQuery('INSERT OR IGNORE INTO emails_rejets (adresse, message, statut) VALUES (?, ?, ?);',
			[$address, $message, $status]);
	}

	/**
	 * Vérifie qu'une adresse est valide
	 * @param  string $address
	 * @return integer FALSE si l'adresse est invalide (syntaxe) ou un entier si l'adresse a été rejetée
	 */
	static public function checkAddress($address)
	{
		$address = strtolower(trim($address));

		// Ce domaine n'existe pas (MX inexistant), erreur de saisie courante
		if (substr($address, -9) == '@gmail.fr')
		{
			return false;
		}

		if ($statut = DB::getInstance()->firstColumn('SELECT statut FROM emails_rejets WHERE adresse = ?;', $address))
		{
			return $statut;
		}

		if (!SMTP::checkEmailIsValid($address, true))
		{
			return false;
		}

		return true;
	}

	protected function mail($to, $subject, $content, array $headers = [])
	{
		// Création du contenu du message
		$config = Config::getInstance();

		$subject = sprintf('[%s] %s', $config->get('nom_asso'), $subject);

		$unsubscribe_url = sprintf('%semail.php?optout=%s', ADMIN_URL, rawurlencode($to));

		$content .= sprintf("\n\n-- \n%s\n%s\n\n", $config->get('nom_asso'), $config('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 cliquez ici :\n" . $unsubscribe_url;

		$content = preg_replace("#(?<!\r)\n#si", "\r\n", $content);

		$headers['List-Unsubscribe'] = sprintf('<%s>', $unsubscribe_url);

		if (FORCE_EMAIL_FROM)
		{
			$headers['From'] = sprintf('"%s" <%s>', sprintf('=?UTF-8?B?%s?=', base64_encode($config->get('nom_asso'))), FORCE_EMAIL_FROM);
			$headers['Return-Path'] = FORCE_EMAIL_FROM;
			$headers['Reply-To'] = $config->get('email_asso');
		}
		else
		{
			$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/include/lib/Garradin/Membres.php from [79cc6c1e41] to [d2c0429520].

454
455
456
457
458
459
460









461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
    }

    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));
    }

    /**
     * @deprecated remplacer par envoyer message à tableau de membres
     */
    public function sendMessageToCategory($dest, $sujet, $message, $subscribed_only = false)
    {
        $config = Config::getInstance();

        $message .= "\n\n--\n".$config->get('nom_asso')."\n".$config->get('site_asso');

        if ($dest == 0)
            $where = 'id_categorie NOT IN (SELECT id FROM membres_categories WHERE cacher = 1)';
        else
            $where = 'id_categorie = '.(int)$dest;

        // FIXME: filtrage plus intelligent, car le champ lettre_infos peut ne pas exister
        if ($subscribed_only)
        {
            $champs = Config::getInstance()->get('champs_membres');

            if ($champs->get('lettre_infos'))
            {
                $where .= ' AND lettre_infos = 1';
            }
        }

        $db = DB::getInstance();
        $res = $db->query('SELECT email FROM membres WHERE LENGTH(email) > 0 AND '.$where.' ORDER BY id;');

        $sujet = '['.$config->get('nom_asso').'] '.$sujet;

        while ($row = $res->fetchArray(SQLITE3_ASSOC))
        {
            Utils::mail($row['email'], $sujet, $message);
        }

        return true;
    }

    public function searchSQL($query)
    {







>
>
>
>
>
>
>
>
>

















<
<

















|

|

|

|







454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486


487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
    }

    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));
    }

    /**
     * @deprecated remplacer par envoyer message à tableau de membres
     */
    public function sendMessageToCategory($dest, $sujet, $message, $subscribed_only = false)
    {
        $config = Config::getInstance();



        if ($dest == 0)
            $where = 'id_categorie NOT IN (SELECT id FROM membres_categories WHERE cacher = 1)';
        else
            $where = 'id_categorie = '.(int)$dest;

        // FIXME: filtrage plus intelligent, car le champ lettre_infos peut ne pas exister
        if ($subscribed_only)
        {
            $champs = Config::getInstance()->get('champs_membres');

            if ($champs->get('lettre_infos'))
            {
                $where .= ' AND lettre_infos = 1';
            }
        }

        $db = DB::getInstance();
        $res = $db->iterate('SELECT email FROM membres WHERE LENGTH(email) > 0 AND '.$where.' ORDER BY id;');

        $email = new Email;

        foreach ($res as $row)
        {
            $email->appendToQueue($row->email, $sujet, $message);
        }

        return true;
    }

    public function searchSQL($query)
    {

Modified src/include/lib/Garradin/Membres/Categories.php from [af4fccf952] to [5b61a5fe1b].

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        }
    }

    public function add($data)
    {
        $this->_checkData($data);

        if (!isset($data['description']))
        {
            $data['description'] = '';
        }

        foreach ($this->droits as $key=>$value)
        {
            if (!isset($data['droit_'.$key]))
                $data['droit_'.$key] = $value;
            else
                $data['droit_'.$key] = (int)$data['droit_'.$key];
        }







<
<
<
<
<







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/Session.php from [b9cd12a177] to [3934882d0a].

1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18
19
20
21
<?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 const Garradin\FORCE_EMAIL_FROM;

use KD2\Security;
use KD2\Security_OTP;
use KD2\QRCode;

class Session extends \KD2\UserSession
{









>




<







1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
<?php

namespace Garradin\Membres;

use Garradin\Config;
use Garradin\DB;
use Garradin\Utils;
use Garradin\Membres;
use Garradin\UserException;
use Garradin\Email;

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
{
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
		$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é.";

		Utils::mail($membre->email, '['.$config->get('nom_asso').'] Mot de passe perdu ?', $message, [], $membre->clef_pgp);
		return true;
	}

	static public function recoverPasswordConfirm($code)
	{
		if (substr_count($code, '.') !== 2)
		{
			return false;







|
<







189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
		$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 (new Email)->appendToQueue($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
248
249
250
251
252
253
254
255
		$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::mail($membre->email, '['.$config->get('nom_asso').'] Nouveau mot de passe', $message, [], $membre->clef_pgp);
	}

	public function editUser($data)
	{
		(new Membres)->edit($this->user->id, $data, false);
		$this->refresh();








|







240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
		$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 (new Email)->appendToQueue($membre->email, 'Nouveau mot de passe', $message, [], $membre->clef_pgp);
	}

	public function editUser($data)
	{
		(new Membres)->edit($this->user->id, $data, false);
		$this->refresh();

286
287
288
289
290
291
292
293
294

295


296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

		return $out;
	}

	public function sendMessage($dest, $sujet, $message, $copie = false)
	{
		$user = $this->getUser();
		$config = Config::getInstance();


		$from = sprintf('"%s" <%s>', sprintf('=?UTF-8?B?%s?=', base64_encode($user->identite)), FORCE_EMAIL_FROM ?: $config->get('email_asso'));



		$message .= "\n\n--\nCe message a été envoyé par un membre de ".$config->get('nom_asso');
		$message .= ", merci de contacter ".$config->get('email_asso')." en cas d'abus.";

		if ($copie)
		{
			Utils::mail($from, $sujet, $message);
		}

		return Utils::mail($dest, $sujet, $message, ['From' => $from, 'Reply-To' => $user->email]);
	}

	public function editSecurity(Array $data = [])
	{
		$allowed_fields = ['passe', 'clef_pgp', 'secret_otp'];

		foreach ($data as $key=>$value)







<

>
|
>
>

<
|



|


|







285
286
287
288
289
290
291

292
293
294
295
296
297

298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

		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;


		$email = new Email;

		if ($copie)
		{
			$email->appendToQueue($user->email, $sujet, $content);
		}

		return $email->appendToQueue($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 [d7415e1122].

375
376
377
378
379
380
381
382
383
384
385































386
387
388
389
390
391
392
		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()
	{
		$db = DB::getInstance();
		return $db->getAssoc('SELECT id, nom FROM plugins WHERE menu = 1 ORDER BY nom;');































	}

	/**
	 * Liste les plugins téléchargés mais non installés
	 * @return array Liste des plugins téléchargés
	 */
	static public function listDownloaded()







|


|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
		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 (!$row->menu_condition)
			{
				$row = $row->nom;
				continue;
			}

			$query = 'SELECT 1 WHERE ' . preg_replace_callback('/\{\$user\.(\w+)\}/', function ($m) use ($user) { return $user->{$m[1]}; }, $row->menu_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()

Modified src/include/lib/Garradin/Rappels_Envoyes.php from [4ab2f9f384] to [9c988c2ebc].

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::mail($data->email, $subject, $text);

		// Enregistrement en DB
		$this->add([
			'id_cotisation' => $data->id_cotisation,
			'id_membre'     => $data->id,
			'id_rappel'     => $data->id_rappel,
			'media'         => Rappels_Envoyes::MEDIA_EMAIL,







|







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
		(new Email)->appendToQueue($data->email, $subject, $text);

		// 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/Template.php from [8050b58d78] to [f111533e27].

49
50
51
52
53
54
55

56
57
58
59
60
61
62
		$this->register_function('html_champ_membre', [$this, 'formChampMembre']);

		$this->register_function('custom_colors', [$this, 'customColors']);
		$this->register_function('plugin_url', ['Garradin\Utils', 'plugin_url']);
		$this->register_function('diff', [$this, 'diff']);
		$this->register_function('pagination', [$this, 'pagination']);
		$this->register_function('format_droits', [$this, 'formatDroits']);


		$this->register_function('csrf_field', function ($params) {
			return Form::tokenHTML($params['key']);
		});

		$this->register_modifier('strlen', 'strlen');
		$this->register_modifier('get_country_name', ['Garradin\Utils', 'getCountryName']);







>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
		$this->register_function('html_champ_membre', [$this, 'formChampMembre']);

		$this->register_function('custom_colors', [$this, 'customColors']);
		$this->register_function('plugin_url', ['Garradin\Utils', 'plugin_url']);
		$this->register_function('diff', [$this, 'diff']);
		$this->register_function('pagination', [$this, 'pagination']);
		$this->register_function('format_droits', [$this, 'formatDroits']);
		$this->register_function('email_link', [$this, 'emailLink']);

		$this->register_function('csrf_field', function ($params) {
			return Form::tokenHTML($params['key']);
		});

		$this->register_modifier('strlen', 'strlen');
		$this->register_modifier('get_country_name', ['Garradin\Utils', 'getCountryName']);
110
111
112
113
114
115
116
















































117
118
119
120
121
122
123
		$this->register_modifier('liens_wiki', function ($str, $prefix) {
			return preg_replace_callback('!<a href="([^/.:@]+)">!i', function ($matches) use ($prefix) {
				return '<a href="' . $prefix . Wiki::transformTitleToURI($matches[1]) . '">';
			}, $str);
		});

	}

















































	protected function formErrors($params)
	{
		$form = $this->getTemplateVars('form');

		if (!$form->hasErrors())
		{







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
		$this->register_modifier('liens_wiki', function ($str, $prefix) {
			return preg_replace_callback('!<a href="([^/.:@]+)">!i', function ($matches) use ($prefix) {
				return '<a href="' . $prefix . Wiki::transformTitleToURI($matches[1]) . '">';
			}, $str);
		});

	}

	protected function emailLink($params)
	{
		if (empty($params['address']))
		{
			throw new \BadFunctionCallException('Missing argument: address');
		}

		$status = Email::checkAddress($params['address']);

		if ($status === true)
		{
			$out = '<a href="mailto:' . $this->escape($params['address'], 'url') . '">' . $this->escape($params['address']) . '</a>';

			if (!empty($params['id_membre']))
			{
				$out .= sprintf(' | <a href="%smembres/message.php?id=%s"><b class="icn action">✉</b> Envoyer un message</a>', ADMIN_URL, (int)$params['id_membre']);
			}

			return $out;
		}

		$out = '<span class="error invalidEmail">' . $this->escape($params['address']) . '</span> <em>(envois désactivés)</em>';

		if (!empty($params['show_error']))
		{
			$out .= '<br />';

			if ($status === Email::REJET_OPTOUT)
			{
				$out .= 'Ce destinataire ne souhaite plus recevoir de message de votre part.';
			}
			elseif ($status === Email::REJET_DEFINITIF)
			{
				$out .= 'Cette adresse n\'existe pas.';
			}
			elseif ($status >= EMAIL::REJET_ABANDON)
			{
				$out .= 'Cette adresse a renvoyé trop d\'erreurs.';
			}
			else
			{
				$out .= 'Cette adresse est invalide.';
			}
		}

		return $out;
	}

	protected function formErrors($params)
	{
		$form = $this->getTemplateVars('form');

		if (!$form->hasErrors())
		{

Modified src/include/lib/Garradin/Utils.php from [4680da7c34] to [c92830dc0e].

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
        $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 mail($to, $subject, $content, array $headers = [], $pgp_key = null)
    {
        // Création du contenu du message
        $content = wordwrap($content);
        $content = trim($content);

        $content = preg_replace("#(?<!\r)\n#si", "\r\n", $content);
        $config = Config::getInstance();

        $headers['Return-Path'] = FORCE_EMAIL_FROM ?: $config->get('email_asso');

        if (empty($headers['From']))
        {
            if (FORCE_EMAIL_FROM)
            {
                $headers['Reply-To'] = !empty($headers['From']) ? $headers['From'] : $config->get('email_asso');
                $headers['From'] = sprintf('"%s" <%s>', sprintf('=?UTF-8?B?%s?=', base64_encode($config->get('nom_asso'))), FORCE_EMAIL_FROM);
                $headers['Return-Path'] = FORCE_EMAIL_FROM;
            }
            else
            {
                $headers['From'] = sprintf('"%s" <%s>', sprintf('=?UTF-8?B?%s?=', base64_encode($config->get('nom_asso'))), $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 ($pgp_key)
        {
            $content = Security::encryptWithPublicKey($pgp_key, $content);
        }

        if (!is_array($to))
        {
            $to = [$to];
        }

        foreach ($to as $recipient)
        {
            // Ne pas envoyer de mail à des adresses invalides
            if (!SMTP::checkEmailIsValid($recipient, false))
            {
                continue;
            }

            if (!self::_sendMail($recipient, $subject, $content, $headers))
            {
                throw new \RuntimeException('Impossible d\'envoyer l\'email');
            }
        }

        return true;
    }

    static protected function _sendMail($to, $subject, $content, array $headers)
    {
        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);
        }
    }

    static public function clearCaches($path = false)
    {
        if (!$path)
        {
            self::clearCaches('compiled');
            self::clearCaches('static');
            return true;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







371
372
373
374
375
376
377


























































































378
379
380
381
382
383
384
        $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;

Modified src/templates/admin/_head.tpl from [aa97d73757] to [5bdcfb933c].

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
        {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>
                {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)}
                <li class="member admin config{if $current == 'membres/categories'} current{/if}"><a href="{$admin_url}membres/categories/">Catégories</a></li>
                <li class="members admin mail{if $current == 'membres/message_collectif'} current{/if}"><a href="{$admin_url}membres/message_collectif.php">Message collectif</a></li>
                {/if}
            </ul>
            {/if}
            </li>
        {/if}
        {if $session->canAccess('compta', Garradin\Membres::DROIT_ACCES)}







<







66
67
68
69
70
71
72

73
74
75
76
77
78
79
        {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>
                {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)}

                <li class="members admin mail{if $current == 'membres/message_collectif'} current{/if}"><a href="{$admin_url}membres/message_collectif.php">Message collectif</a></li>
                {/if}
            </ul>
            {/if}
            </li>
        {/if}
        {if $session->canAccess('compta', Garradin\Membres::DROIT_ACCES)}

Modified src/templates/admin/config/_menu.tpl from [b62a4fdea8] to [f5431a24f4].

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 == '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.php">Données&nbsp;: sauvegarde et restauration</a></li>
    <li{if $current == 'import'} class="current"{/if}><a href="{$admin_url}config/import.php">Import &amp; export</a></li>
    <li{if $current == 'plugins'} class="current"{/if}><a href="{$admin_url}config/plugins.php">Extensions</a></li>
</ul>


>
|

|



1
2
3
4
5
6
7
8
9
<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.php">sauvegarde et restauration</a></li>
    <li{if $current == 'import'} class="current"{/if}><a href="{$admin_url}config/import.php">Import &amp; export</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 &rarr;" />
    </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 &amp; é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 &amp; é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 &amp; é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">&#x2611;</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">&#x2611;</b> Oui</label>
            </dd>
        </dl>
    </fieldset>

    <p class="submit">
        {csrf_field key="edit_cat_"|cat:$cat.id}
        <input type="submit" name="save" value="Enregistrer &rarr;" />
    </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 «&nbsp;{$cat.nom}&nbsp;» ?
        </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 &rarr;" />
    </p>

</form>

{include file="admin/_foot.tpl"}

Modified src/templates/admin/config/donnees.tpl from [396a0ea87b] to [bbe16924a5].

1
2
3
4
5
6
7
8
{include file="admin/_head.tpl" title="Données — Sauvegarde et restauration" current="config"}

{include file="admin/config/_menu.tpl" current="donnees"}

{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 «&nbsp;Ignorer les erreurs&nbsp;».
|







1
2
3
4
5
6
7
8
{include file="admin/_head.tpl" title="Sauvegarde et restauration" current="config"}

{include file="admin/config/_menu.tpl" current="donnees"}

{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 «&nbsp;Ignorer les erreurs&nbsp;».

Modified src/templates/admin/config/membres.tpl from [79611cc039] to [fcc1959f81].

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="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">


|







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">

Deleted src/templates/admin/membres/categories/index.tpl version [9c762d5e02].

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
{include file="admin/_head.tpl" title="Catégories de membres" current="membres/categories"}

<table class="list">
    <thead>
        <th>Nom</th>
        <td>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/categories/modifier.php?id={$cat.id}" title="Modifier">✎</a>
                    {if $cat.id != $user.id_categorie}
                    <a class="icn" href="{$admin_url}membres/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 &rarr;" />
    </p>

</form>


{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































Deleted src/templates/admin/membres/categories/modifier.tpl version [206fa39a37].

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
{include file="admin/_head.tpl" title="Modifier une catégorie" current="membres/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><label for="f_description">Description</label></dt>
            <dd><textarea name="description" id="f_description" rows="5" cols="50">{form_field data=$cat name=description}</textarea></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>
            {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_membres" value="{$membres::DROIT_AUCUN}" id="f_droit_membres_aucun" {if $cat.droit_membres == $membres::DROIT_AUCUN}checked="checked"{/if} {$readonly} />
                <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} {$readonly} />
                <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} {$readonly} />
                <label for="f_droit_membres_ecriture"><b class="ecriture">M</b> Lecture &amp; é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} {$readonly} />
                <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 &amp; é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 &amp; é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">&#x2611;</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">&#x2611;</b> Oui</label>
            </dd>
        </dl>
    </fieldset>

    <p class="submit">
        {csrf_field key="edit_cat_"|cat:$cat.id}
        <input type="submit" name="save" value="Enregistrer &rarr;" />
    </p>

</form>

{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































Deleted src/templates/admin/membres/categories/supprimer.tpl version [145753eeb5].

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
{include file="admin/_head.tpl" title="Supprimer une catégorie" current="membres/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 «&nbsp;{$cat.nom}&nbsp;» ?
        </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 &rarr;" />
    </p>

</form>

{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































Modified src/templates/admin/membres/cotisations.tpl from [90b6408dfe] to [c69a2595d3].

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>
    <li><a href="{$admin_url}membres/modifier.php?id={$membre.id}">Modifier</a></li>
    {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">




|







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 [ee27111687].

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>
    <li><a href="{$admin_url}membres/modifier.php?id={$membre.id}">Modifier</a></li>
    {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">




|







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

49
50
51
52
53
54
55

56
57
58
59
60
61
62
        {else}
            Aucune cotisation enregistrée
        {/if} 
    </dt>
    <dd>
        <a href="{$admin_url}membres/cotisations.php?id={$membre.id}">Voir l'historique</a>
    </dd>

    <dd><form method="get" action="{$admin_url}membres/cotisations/ajout.php"><input type="submit" value="Enregistrer une cotisation &rarr;" /><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}

</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>







>
|
|
|
|
|
|
|
>







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 &rarr;" /><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
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
				{/if}
		{/if}
		</dd>
	</dl>
</aside>

<dl class="describe">
    {foreach from=$champs key="c" item="config"}
    <dt>{$config.title}</dt>
    <dd>
        {if $config.type == 'checkbox'}
            {if $membre->$c}Oui{else}Non{/if}
        {elseif empty($membre->$c)}
            <em>(Non renseigné)</em>
        {elseif $c == 'nom'}
            <strong>{$membre->$c}</strong>
        {elseif $c == 'email'}
            <a href="mailto:{$membre->$c}">{$membre->$c}</a>
            | <a href="{$admin_url}membres/message.php?id={$membre.id}"><b class="icn action">✉</b> Envoyer un message</a>
        {elseif $config.type == 'email'}
            <a href="mailto:{$membre->$c}">{$membre->$c}</a>
        {elseif $config.type == 'tel'}
            <a href="tel:{$membre->$c}">{$membre->$c|format_tel}</a>
        {elseif $config.type == 'country'}
            {$membre->$c|get_country_name}
        {elseif $config.type == 'date' || $config.type == 'datetime'}
            {$membre->$c|format_sqlite_date_to_french}
        {elseif $config.type == 'password'}
            *******
        {elseif $config.type == 'multiple'}
            <ul>
            {foreach from=$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"}







|
|

|



|


|
<
|
|
|

|

|

|

|

|













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
				{/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 == 'email'}
            {email_link address=$membre->$c show_error=true id_membre=$membre->id}

        {elseif $c_config.type == 'email'}
            {email_link address=$membre->$c show_error=true}
        {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/index.tpl from [346b3591a7] to [12e18bee98].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{include file="admin/_head.tpl" title="Liste des membres" current="membres" js=1}

{if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}
<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 &amp; export</a></li>
        <li><a href="{$admin_url}membres/recherche_sql.php">Recherche par requête SQL</a></li>
    {/if}
</ul>
{/if}

{if $sent}
    <p class="confirm">Votre message a été envoyé.</p>
{/if}

{if !empty($membres_cats)}
<form method="get" action="{$self_url}" class="shortFormRight">


<








<







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 &amp; 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        {/foreach}
        </select>
        <noscript><input type="submit" value="Filtrer &rarr;" /></noscript>
    </fieldset>
</form>
{/if}

<form method="get" action="{$admin_url}membres/{if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}recherche.php{/if}" class="shortFormLeft">
    <fieldset>
        <legend>Rechercher un membre</legend>
        <input type="text" name="r" value="" />
        <input type="submit" value="Chercher &rarr;" />
    </fieldset>
</form>

{if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}

    <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}&amp;a&amp;cat={$current_cat}" class="icn up">&uarr;</a><a href="?o={$c}&amp;d&amp;cat={$current_cat}" class="icn dn">&darr;</a></td>
                {/foreach}







|







<
<
|

|







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 &rarr;" /></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="r" value="" />
        <input type="submit" value="Chercher &rarr;" />
    </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}&amp;a&amp;cat={$current_cat}" class="icn up">&uarr;</a><a href="?o={$c}&amp;d&amp;cat={$current_cat}" class="icn dn">&darr;</a></td>
                {/foreach}
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
                            {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>
                        <a class="icn" href="{$admin_url}membres/modifier.php?id={$membre.id}" title="Modifier la fiche membre">✎</a>
                    </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>
{else}
    {if !empty($liste)}
    <table class="list">
        <thead>
            <th>Membre</th>
            <td></td>
        </thead>
        <tbody>
            {foreach from=$liste item="membre"}
                <tr>
                    <th>{$membre.identite}</th>
                    <td class="actions">
                        {if !empty($membre.email)}<a href="{$admin_url}membres/message.php?id={$membre.id}">Envoyer un message</a>{/if}
                    </td>
                </tr>
            {/foreach}
        </tbody>
    </table>

    {if !empty($pagination_url)}
        {pagination url=$pagination_url page=$page bypage=$bypage total=$total}
    {/if}

    {else}
    <p class="alert">
        Aucun membre trouvé.
    </p>
    {/if}
{/if}

{include file="admin/_foot.tpl"}







|
















|



|

|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<

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/recherche.tpl from [3886f956f8] to [8cd775429b].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{include file="admin/_head.tpl" title="Recherche de membre" current="membres"}

{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="get" action="{$admin_url}membres/recherche.php" class="shortFormLeft">
    <fieldset>
        <legend>Rechercher un membre</legend>
        <dl>
            <dt><label for="f_champ">Champ</label></dt>
            <dd>
|








<







1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
{include file="admin/_head.tpl" title="Recherche de membre" current="membres" js=1}

{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="get" action="{$admin_url}membres/recherche.php" class="shortFormLeft">
    <fieldset>
        <legend>Rechercher un membre</legend>
        <dl>
            <dt><label for="f_champ">Champ</label></dt>
            <dd>
53
54
55
56
57
58
59
60
61

62
63
64
65
66
67
68
69
70
71
72
73
        <p class="submit">
            <input type="submit" value="Chercher &rarr;" />
        </p>
    </fieldset>
</form>

{if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}

    <form method="post" action="{$admin_url}membres/action.php" class="memberList">


    {if !empty($liste)}
    <table class="list search">
        <thead>
            {if $session->canAccess('membres', Garradin\Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" value="Tout cocher / décocher" onclick="checkUncheck();" /></td>{/if}
            {foreach from=$champs_entete key="c" item="cfg"}
                {if $champ == $c}
                    <th><strong>{$cfg.title}</strong></th>
                {else}
                    <td>{$cfg.title}</td>
                {/if}
            {/foreach}







<

>

|


|







52
53
54
55
56
57
58

59
60
61
62
63
64
65
66
67
68
69
70
71
72
        <p class="submit">
            <input type="submit" value="Chercher &rarr;" />
        </p>
    </fieldset>
</form>

{if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}

    <form method="post" action="{$admin_url}membres/action.php" class="memberList">
{/if}

{if !empty($liste)}
    <table class="list search">
        <thead>
            {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=$champs_entete key="c" item="cfg"}
                {if $champ == $c}
                    <th><strong>{$cfg.title}</strong></th>
                {else}
                    <td>{$cfg.title}</td>
                {/if}
            {/foreach}
82
83
84
85
86
87
88

89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
                            <th><strong>{$membre->$c|raw|display_champ_membre:$cfg}</strong></th>
                        {else}
                            <td>{$membre->$c|raw|display_champ_membre:$cfg}</td>
                        {/if}
                    {/foreach}
                    <td class="actions">
                    	<a class="icn" href="{$admin_url}membres/fiche.php?id={$membre.id}" title="Fiche membre">👤</a>

                        <a class="icn" href="{$admin_url}membres/modifier.php?id={$membre.id}" title="Modifier la fiche membre">✎</a>

                    </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="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 $recherche != ''}

    <p class="alert">
        Aucun membre trouvé.
    </p>
    {/if}

    </form>

    <script type="text/javascript">
    {literal}
    (function() {
        var checked = false;

        window.checkUncheck = function()
        {
            var elements = document.getElementsByTagName('input');
            var el_length = elements.length;

            for (i = 0; i < el_length; i++)
            {
                var elm = elements[i];

                if (elm.type == 'checkbox')
                {
                    if (checked)
                        elm.checked = false;
                    else
                        elm.checked = true;
                }
            }

            checked = checked ? false : true;
            return true;
        }
    }())
    {/literal}
    </script>
{else}
    {if !empty($liste)}
    <table class="list">
        <thead>
            <th>Membre</th>
            <td></td>
        </thead>
        <tbody>
            {foreach from=$liste item="membre"}
                <tr>
                    <th>{$membre.identite}</th>
                    <td class="actions">
                        {if !empty($membre.email)}<a href="{$admin_url}membres/message.php?id={$membre.id}">Envoyer un message</a>{/if}
                    </td>
                </tr>
            {/foreach}
        </tbody>
    </table>
    {else}
    <p class="info">
        Aucun membre trouvé.
    </p>
    {/if}
{/if}

<script type="text/javascript">
{literal}
(function() {
    var current = false;








>

>








|









|
>



<

<
|
<
<
<
<

<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<







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
                            <th><strong>{$membre->$c|raw|display_champ_membre:$cfg}</strong></th>
                        {else}
                            <td>{$membre->$c|raw|display_champ_membre:$cfg}</td>
                        {/if}
                    {/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="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 $recherche != ''}

    <p class="alert">
        Aucun membre trouvé.
    </p>



{/if}









{if $session->canAccess('membres', Garradin\Membres::DROIT_ECRITURE)}


































    </form>







{/if}

<script type="text/javascript">
{literal}
(function() {
    var current = false;

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"}

<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>
|







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
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="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}







|







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
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
                {/if}
            </tr>
        {/foreach}
    </tbody>
</table>

<p class="checkUncheck">
    <input type="button" value="Tout cocher / décocher" onclick="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>

<script type="text/javascript">
{literal}
(function() {
    var checked = false;

    window.checkUncheck = function()
    {
        var elements = document.getElementsByTagName('input');
        var el_length = elements.length;

        for (i = 0; i < el_length; i++)
        {
            var elm = elements[i];

            if (elm.type == 'checkbox')
            {
                if (checked)
                    elm.checked = false;
                else
                    elm.checked = true;
            }
        }

        checked = checked ? false : true;
        return true;
    }
}())
{/literal}
</script>

{include file="admin/_foot.tpl"}







|
















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

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/error.tpl from [f1a21eb4e1] to [52bccc1e68].

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>Erreur</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 {




|







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
34
35
36
37
38
39
40
41
42
43
44
45
    }
    {/literal}
    </style>
</head>

<body>

<h1>Erreur</h1>

<p class="error">
    {$error|escape|nl2br}
</p>

<p>
    <a href="{$www_url}" onclick="history.back(); return false;">&larr; Retour</a>
</p>

</body>
</html>







|






|




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();">&larr; Retour</a>
</p>

</body>
</html>

Modified src/www/admin/_inc.php from [e0bbbc300b] to [d2b4f407f4].

66
67
68
69
70
71
72








73
74
75
76
77
78
79

    $tpl->assign('is_logged', true);

    $user = $session->getUser();
    $tpl->assign('user', $user);

    $tpl->assign('current', '');








    $tpl->assign('plugins_menu', Plugin::listMenu());

    if ($session->canAccess('membres', Membres::DROIT_ACCES))
    {
        $tpl->assign('nb_membres', (new Membres)->countAllButHidden());
    }
}







>
>
>
>
>
>
>
>
|






66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

    $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'));

    if ($session->canAccess('membres', Membres::DROIT_ACCES))
    {
        $tpl->assign('nb_membres', (new Membres)->countAllButHidden());
    }
}

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');

Added src/www/admin/email.php version [0a473d143d].





































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace Garradin;

require_once __DIR__ . '/../../include/init.php';

$tpl = Template::getInstance();

if (!empty($_GET['optout']))
{
    $email = new Email;
    $email->setRejectedStatus($_GET['optout'], $email::REJET_OPTOUT, 'Demande de désinscription');
    
    $tpl->assign('title', 'Confirmation');
    $tpl->assign('error', 'Votre adresse a bien été désinscrite, vous ne recevrez plus de messages de notre part.');
}

$tpl->display('error.tpl');

Deleted src/www/admin/membres/categories/index.php version [a435abf714].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
namespace Garradin;

require_once __DIR__ . '/../_inc.php';

$session->requireAccess('membres', Membres::DROIT_ADMIN);

$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 . 'membres/categories/');
    }
}

$tpl->assign('liste', $cats->listCompleteWithStats());

$tpl->display('admin/membres/categories/index.tpl');
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































Deleted src/www/admin/membres/categories/modifier.php version [624c7118d6].

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
<?php
namespace Garradin;

require_once __DIR__ . '/../_inc.php';

$session->requireAccess('membres', Membres::DROIT_ADMIN);

$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'),
            'description'   =>  f('description'),
            '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;
            $data['droit_membres'] = 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 . 'membres/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', $membres);

$tpl->display('admin/membres/categories/modifier.tpl');
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































Deleted src/www/admin/membres/categories/supprimer.php version [43f9a12d7b].

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
<?php
namespace Garradin;

require_once __DIR__ . '/../_inc.php';

$session->requireAccess('membres', Membres::DROIT_ADMIN);

$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 . 'membres/categories/');
        }
        catch (UserException $e)
        {
            $form->addError($e->getMessage());
        }
    }
}

$tpl->assign('cat', $cat);

$tpl->display('admin/membres/categories/supprimer.tpl');
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































Modified src/www/admin/membres/cotisations.php from [32cdb67ed5] to [d156e1e5bb].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

$session->requireAccess('membres', Membres::DROIT_ECRITURE);

qv(['id' => 'required|numeric']);

$id = (int) qg('id');

$membre = $membres->get($id);

if (!$membre)





<
<







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
6
7
8
9
10
11
12
13
14
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

$session->requireAccess('membres', Membres::DROIT_ECRITURE);

qv(['id' => 'required|numeric']);

$id = (int) qg('id');

$membre = $membres->get($id);

if (!$membre)





<
<







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/index.php from [e45d2413f7] to [33e9d88bdd].

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
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

// Recherche de membre (pour ceux qui n'ont qu'un accès à la liste des membres)
if (qg('r'))
{
	$recherche = trim(qg('r'));

	$result = $membres->search($config->get('champ_identite'), $recherche);
    $tpl->assign('liste', $result);
	$tpl->assign('recherche', $recherche);
}
else
{
	$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');





<
<
<
<
<
<
<
<
<
<
<
|
|

|
|

|
|

|
|
|
|
|
|
|

|
|
|
|

|
|
|

|
|

|
|

|

|
|
|
|
|
|

|
|

|

|
|

|

|
|
|
|
|
|

|
|
|

|
|
<
<




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');

Modified src/www/admin/membres/recherche.php from [f11a643a77] to [53c0358ecc].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

$session->requireAccess('membres', Membres::DROIT_ECRITURE);

$recherche = trim(qg('r'));
$champ = trim(qg('c'));

$champs = $config->get('champs_membres');

$auto = false;






<
<







1
2
3
4
5


6
7
8
9
10
11
12
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';



$recherche = trim(qg('r'));
$champ = trim(qg('c'));

$champs = $config->get('champs_membres');

$auto = false;

Modified src/www/admin/static/admin.css from [903a1b66a2] to [ac3a89353d].

184
185
186
187
188
189
190




191
192
193
194
195
196
197
span.confirm, b.confirm {
    color: #090;
}

span.alert, b.alert {
    color: #990;
}





p.error, div.error {
    border: 1px solid #c00;
    background: #fcc;
    padding: 0.5em;
    margin-bottom: 1em;
}







>
>
>
>







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
span.confirm, b.confirm {
    color: #090;
}

span.alert, b.alert {
    color: #990;
}

.error.invalidEmail {
    text-decoration: line-through;
}

p.error, div.error {
    border: 1px solid #c00;
    background: #fcc;
    padding: 0.5em;
    margin-bottom: 1em;
}

Modified src/www/admin/upgrade.php from [4dda8f7462] to [23f1d1d153].

322
323
324
325
326
327
328










329
330
331
332
333
334
335

if (version_compare($v, '0.8.4', '<'))
{
    $db->begin();

    $db->import(ROOT . '/include/data/0.8.4.sql');











    $db->commit();
}

Utils::clearCaches();

$config->setVersion(garradin_version());








>
>
>
>
>
>
>
>
>
>







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345

if (version_compare($v, '0.8.4', '<'))
{
    $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');

    $db->commit();
}

Utils::clearCaches();

$config->setVersion(garradin_version());