Overview
SHA1:94082a8d1fa9a497c35f9e9c17fedb4c6ebcfcf0
Date: 2014-03-26 17:29:17
User: bohwaz
Comment:Ajout configuration d'exemple + ajout gestion tâche automatisées
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2014-03-26
17:47
[6e539273e0] Vague de "required" dans les formulaires (user: bohwaz, tags: trunk)
17:29
[94082a8d1f] Ajout configuration d'exemple + ajout gestion tâche automatisées (user: bohwaz, tags: trunk)
17:06
[da117a9e3e] Possibilité de faire un rappel le jour de l'expiration (user: bohwaz, tags: trunk)
Changes

Added src/config.dist.php version [1f97e4c178].











































































































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

/**
 * Ce fichier représente un exemple des constantes de configuration
 * disponibles pour Garradin.
 */

// Nécessaire pour situer les constantes dans le bon namespace
namespace Garradin;

// Connexion automatique à l'administration avec l'adresse e-mail donnée
#const LOCAL_LOGIN = 'president@association.net';

// Connexion automatique avec le numéro de membre indiqué
// Défaut : false (connexion automatique désactivée)
const LOCAL_LOGIN = 1;

// Répertoire où est le code source de Garradin
const ROOT = '/usr/share/garradin';

// Répertoire où sont situées les données de Garradin
// (incluant la base de données SQLite, le cache et les fichiers locaux)
// Défaut : le même répertoire que le source
const DATA_ROOT = '/var/www/garradin';

// Emplacement de la base de données
const DB_FILE = '/var/lib/sqlite/garradin.sqlite';

// Adresse URI de la racine du site Garradin
// (doit se terminer par un slash)
// Défaut : découverte automatique à partir de SCRIPT_NAME
const WWW_URI = '/garradin/';

// Adresse URL HTTP(S) de Garradin
// Défaut : découverte à partir de HTTP_HOST ou SERVER_NAME + WWW_URI
const WWW_URL = 'http://garradin.net' . WWW_URI;

// Emplacement de stockage des plugins
const PLUGINS_ROOT = DATA_ROOT . '/plugins';

// Affichage des erreurs
// Si "true" alors un message expliquant l'erreur et comment rapporter le bug s'affiche
// en cas d'erreur. Sinon rien ne sera affiché.
// Défaut : true
const SHOW_ERRORS = true;

// Utilisation de cron pour les tâches automatiques
// Si "true" on s'attend à ce qu'une tâche automatisée appelle
// le script cron.php à la racine toutes les 24 heures. Sinon Garradin
// effectuera les actions automatiques quand quelqu'un se connecte à 
// l'administration ou visite le site.
// Défaut : false
const USE_CRON = false;

Added src/cron.php version [4f820133c2].



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace Garradin;

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

// Exécution des tâches automatiques

if ($config->get('frequence_sauvegardes') && $config->get('nombre_sauvegardes'))
{
	$s = new Sauvegarde;
	$s->auto();
}

Modified src/include/class.plugin.php from [3d3b394c0f] to [fc78aaa227].

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500

	/**
	 * Renvoie le chemin absolu vers l'archive du plugin
	 * @return string Chemin PHAR vers l'archive
	 */
	public function path()
	{
		return 'phar://' . PLUGINS_PATH . '/' . $this->id . '.phar';
	}

	/**
	 * Renvoie une entrée de la configuration ou la configuration complète
	 * @param  string $key Clé à rechercher, ou NULL si on désire toutes les entrées de la
	 * @return mixed       L'entrée demandée (mixed), ou l'intégralité de la config (array),
	 * ou NULL si l'entrée demandée n'existe pas.
................................................................................
	public function uninstall()
	{
		if (file_exists($this->path() . '/uninstall.php'))
		{
			include $this->path() . '/uninstall.php';
		}
		
		unlink(PLUGINS_PATH . '/' . $this->id . '.phar');

		$db = DB::getInstance();
		return $db->simpleExec('DELETE FROM plugins WHERE id = ?;', $this->id);
	}

	/**
	 * Renvoie TRUE si le plugin a besoin d'être mis à jour
................................................................................
	 * @return array Liste des plugins téléchargés
	 */
	static public function listDownloaded()
	{
		$installed = self::listInstalled();

		$list = [];
		$dir = dir(PLUGINS_PATH);

		while ($file = $dir->read())
		{
			if (substr($file, 0, 1) == '.')
				continue;

			if (!preg_match('!^([a-z0-9_-]+)\.phar$!', $file, $match))
				continue;
			
			if (array_key_exists($match[1], $installed))
				continue;

			$list[$match[1]] = parse_ini_file('phar://' . PLUGINS_PATH . '/' . $match[1] . '.phar/garradin_plugin.ini', false);
		}

		$dir->close();

		return $list;
	}

................................................................................
	static public function checkHash($id)
	{
		$list = self::fetchOfficialList();

		if (!array_key_exists($id, $list))
			return null;

		$hash = sha1_file(PLUGINS_PATH . '/' . $id . '.phar');

		return ($hash === $list[$id]['hash']);
	}

	/**
	 * Est-ce que le plugin est officiel ?
	 * @param  string  $id Identifiant du plugin
................................................................................
		$list = self::fetchOfficialList();

		if (!array_key_exists($id, $list))
		{
			throw new \LogicException($id . ' n\'est pas un plugin officiel (absent de la liste)');
		}

		if (file_exists(PLUGINS_PATH . '/' . $id . '.phar'))
		{
			throw new UserException('Le plugin '.$id.' existe déjà.');
		}

		$url = parse_url(PLUGINS_URL);

		$context_options = [
................................................................................
				'disable_compression'	=>	true,
			]
		];

		$context = stream_context_create($context_options);

		try {
			copy($list[$id]['phar'], PLUGINS_PATH . '/' . $id . '.phar', $context);
		}
		catch (\Exception $e)
		{
			throw new UserException('Le téléchargement du plugin '.$id.' a échoué : ' . $e->getMessage());
		}

		if (!self::checkHash($id))
		{
			unlink(PLUGINS_PATH . '/' . $id . '.phar');
			throw new \RuntimeException('L\'archive du plugin '.$id.' est corrompue (le hash SHA1 ne correspond pas).');
		}

		self::install($id, true);

		return true;
	}
................................................................................
	 * Installer un plugin
	 * @param  string  $id       Identifiant du plugin
	 * @param  boolean $official TRUE si le plugin est officiel
	 * @return boolean           TRUE si tout a fonctionné
	 */
	static public function install($id, $official = false)
	{
		if (!file_exists('phar://' . PLUGINS_PATH . '/' . $id . '.phar'))
		{
			throw new \RuntimeException('Le plugin ' . $id . ' ne semble pas exister et ne peut donc être installé.');
		}

		if (!file_exists('phar://' . PLUGINS_PATH . '/' . $id . '.phar/garradin_plugin.ini'))
		{
			throw new UserException('L\'archive '.$id.'.phar n\'est pas une extension Garradin : fichier garradin_plugin.ini manquant.');
		}

		$infos = parse_ini_file('phar://' . PLUGINS_PATH . '/' . $id . '.phar/garradin_plugin.ini', false);

		$required = ['nom', 'description', 'auteur', 'url', 'version', 'menu', 'config'];

		foreach ($required as $key)
		{
			if (!array_key_exists($key, $infos))
			{
				throw new \RuntimeException('Le fichier garradin_plugin.ini ne contient pas d\'entrée "'.$key.'".');
			}
		}

		if (!empty($infos['menu']) && !file_exists('phar://' . PLUGINS_PATH . '/' . $id . '.phar/www/admin/index.php'))
		{
			throw new \RuntimeException('Le plugin '.$id.' ne comporte pas de fichier www/admin/index.php alors qu\'il demande à figurer au menu.');
		}

		$config = '';

		if ((bool)$infos['config'])
		{
			if (!file_exists('phar://' . PLUGINS_PATH . '/' . $id . '.phar/config.json'))
			{
				throw new \RuntimeException('L\'archive '.$id.'.phar ne comporte pas de fichier config.json 
					alors que le plugin nécessite le stockage d\'une configuration.');
			}

			if (!file_exists('phar://' . PLUGINS_PATH . '/' . $id . '.phar/www/admin/config.php'))
			{
				throw new \RuntimeException('L\'archive '.$id.'.phar ne comporte pas de fichier www/admin/config.php 
					alors que le plugin nécessite le stockage d\'une configuration.');
			}

			$config = json_encode(file_get_contents('phar://' . PLUGINS_PATH . '/' . $id . '.phar/config.json'));
		}

		$db = DB::getInstance();
		$db->simpleInsert('plugins', [
			'id' 		=> 	$id,
			'officiel' 	=> 	(int)(bool)$official,
			'nom'		=>	$infos['nom'],
................................................................................
			'auteur'	=>	$infos['auteur'],
			'url'		=>	$infos['url'],
			'version'	=>	$infos['version'],
			'menu'		=>	(int)(bool)$infos['menu'],
			'config'	=>	$config,
		]);

		if (file_exists('phar://' . PLUGINS_PATH . '/' . $id . '.phar/install.php'))
		{
			include 'phar://' . PLUGINS_PATH . '/' . $id . '.phar/install.php';
		}

		return true;
	}

	/**
	 * Renvoie la version installée d'un plugin ou FALSE s'il n'est pas installé







|







 







|







 







|












|







 







|







 







|







 







|








|







 







|




|




|











|








|





|





|







 







|

|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500

	/**
	 * Renvoie le chemin absolu vers l'archive du plugin
	 * @return string Chemin PHAR vers l'archive
	 */
	public function path()
	{
		return 'phar://' . PLUGINS_ROOT . '/' . $this->id . '.phar';
	}

	/**
	 * Renvoie une entrée de la configuration ou la configuration complète
	 * @param  string $key Clé à rechercher, ou NULL si on désire toutes les entrées de la
	 * @return mixed       L'entrée demandée (mixed), ou l'intégralité de la config (array),
	 * ou NULL si l'entrée demandée n'existe pas.
................................................................................
	public function uninstall()
	{
		if (file_exists($this->path() . '/uninstall.php'))
		{
			include $this->path() . '/uninstall.php';
		}
		
		unlink(PLUGINS_ROOT . '/' . $this->id . '.phar');

		$db = DB::getInstance();
		return $db->simpleExec('DELETE FROM plugins WHERE id = ?;', $this->id);
	}

	/**
	 * Renvoie TRUE si le plugin a besoin d'être mis à jour
................................................................................
	 * @return array Liste des plugins téléchargés
	 */
	static public function listDownloaded()
	{
		$installed = self::listInstalled();

		$list = [];
		$dir = dir(PLUGINS_ROOT);

		while ($file = $dir->read())
		{
			if (substr($file, 0, 1) == '.')
				continue;

			if (!preg_match('!^([a-z0-9_-]+)\.phar$!', $file, $match))
				continue;
			
			if (array_key_exists($match[1], $installed))
				continue;

			$list[$match[1]] = parse_ini_file('phar://' . PLUGINS_ROOT . '/' . $match[1] . '.phar/garradin_plugin.ini', false);
		}

		$dir->close();

		return $list;
	}

................................................................................
	static public function checkHash($id)
	{
		$list = self::fetchOfficialList();

		if (!array_key_exists($id, $list))
			return null;

		$hash = sha1_file(PLUGINS_ROOT . '/' . $id . '.phar');

		return ($hash === $list[$id]['hash']);
	}

	/**
	 * Est-ce que le plugin est officiel ?
	 * @param  string  $id Identifiant du plugin
................................................................................
		$list = self::fetchOfficialList();

		if (!array_key_exists($id, $list))
		{
			throw new \LogicException($id . ' n\'est pas un plugin officiel (absent de la liste)');
		}

		if (file_exists(PLUGINS_ROOT . '/' . $id . '.phar'))
		{
			throw new UserException('Le plugin '.$id.' existe déjà.');
		}

		$url = parse_url(PLUGINS_URL);

		$context_options = [
................................................................................
				'disable_compression'	=>	true,
			]
		];

		$context = stream_context_create($context_options);

		try {
			copy($list[$id]['phar'], PLUGINS_ROOT . '/' . $id . '.phar', $context);
		}
		catch (\Exception $e)
		{
			throw new UserException('Le téléchargement du plugin '.$id.' a échoué : ' . $e->getMessage());
		}

		if (!self::checkHash($id))
		{
			unlink(PLUGINS_ROOT . '/' . $id . '.phar');
			throw new \RuntimeException('L\'archive du plugin '.$id.' est corrompue (le hash SHA1 ne correspond pas).');
		}

		self::install($id, true);

		return true;
	}
................................................................................
	 * Installer un plugin
	 * @param  string  $id       Identifiant du plugin
	 * @param  boolean $official TRUE si le plugin est officiel
	 * @return boolean           TRUE si tout a fonctionné
	 */
	static public function install($id, $official = false)
	{
		if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.phar'))
		{
			throw new \RuntimeException('Le plugin ' . $id . ' ne semble pas exister et ne peut donc être installé.');
		}

		if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.phar/garradin_plugin.ini'))
		{
			throw new UserException('L\'archive '.$id.'.phar n\'est pas une extension Garradin : fichier garradin_plugin.ini manquant.');
		}

		$infos = parse_ini_file('phar://' . PLUGINS_ROOT . '/' . $id . '.phar/garradin_plugin.ini', false);

		$required = ['nom', 'description', 'auteur', 'url', 'version', 'menu', 'config'];

		foreach ($required as $key)
		{
			if (!array_key_exists($key, $infos))
			{
				throw new \RuntimeException('Le fichier garradin_plugin.ini ne contient pas d\'entrée "'.$key.'".');
			}
		}

		if (!empty($infos['menu']) && !file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.phar/www/admin/index.php'))
		{
			throw new \RuntimeException('Le plugin '.$id.' ne comporte pas de fichier www/admin/index.php alors qu\'il demande à figurer au menu.');
		}

		$config = '';

		if ((bool)$infos['config'])
		{
			if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.phar/config.json'))
			{
				throw new \RuntimeException('L\'archive '.$id.'.phar ne comporte pas de fichier config.json 
					alors que le plugin nécessite le stockage d\'une configuration.');
			}

			if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.phar/www/admin/config.php'))
			{
				throw new \RuntimeException('L\'archive '.$id.'.phar ne comporte pas de fichier www/admin/config.php 
					alors que le plugin nécessite le stockage d\'une configuration.');
			}

			$config = json_encode(file_get_contents('phar://' . PLUGINS_ROOT . '/' . $id . '.phar/config.json'));
		}

		$db = DB::getInstance();
		$db->simpleInsert('plugins', [
			'id' 		=> 	$id,
			'officiel' 	=> 	(int)(bool)$official,
			'nom'		=>	$infos['nom'],
................................................................................
			'auteur'	=>	$infos['auteur'],
			'url'		=>	$infos['url'],
			'version'	=>	$infos['version'],
			'menu'		=>	(int)(bool)$infos['menu'],
			'config'	=>	$config,
		]);

		if (file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.phar/install.php'))
		{
			include 'phar://' . PLUGINS_ROOT . '/' . $id . '.phar/install.php';
		}

		return true;
	}

	/**
	 * Renvoie la version installée d'un plugin ou FALSE s'il n'est pas installé

Modified src/include/init.php from [5b49b14001] to [9f7a1dec4b].

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102






103
104
105
106
107
108
109
...
207
208
209
210
211
212
213




214
215
216
217
218
219
220
{
    $host = isset($_SERVER['HTTP_HOST']) 
        ? $_SERVER['HTTP_HOST'] 
        : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
    define('Garradin\WWW_URL', 'http' . (!empty($_SERVER['HTTPS']) ? 's' : '') . '://' . $host . WWW_URI);
}

if (!defined('Garradin\PLUGINS_PATH'))
{
    define('Garradin\PLUGINS_PATH', DATA_ROOT . '/plugins');
}

// Affichage des erreurs par défaut
if (!defined('Garradin\SHOW_ERRORS'))
{
    define('Garradin\SHOW_ERRORS', true);
}







define('Garradin\WEBSITE', 'http://garradin.eu/');
define('Garradin\PLUGINS_URL', 'https://garradin.eu/plugins/list.json');

// PHP devrait être assez intelligent pour chopper la TZ système mais nan
// il sait pas faire (sauf sur Debian qui a le bon patch pour ça), donc pour 
// éviter le message d'erreur à la con on définit une timezone par défaut
................................................................................
        <pre> \__/<br /> (xx)<br />//||\\\\</pre>
        <h1>Erreur d\'exécution</h1>
        <p>Une erreur s\'est produite à l\'exécution de Garradin. Pour rapporter ce bug
        merci d\'inclure le message suivant :</p>
        <textarea cols="70" rows="'.substr_count($error, "\n").'">'.htmlspecialchars($error, ENT_QUOTES, 'UTF-8').'</textarea>
        <hr />
        <p><a href="http://dev.kd2.org/garradin/Rapporter%20un%20bug">Comment rapporter un bug</a></p>';




    }

    exit;
}

set_error_handler('Garradin\exception_error_handler');
set_exception_handler('Garradin\exception_handler');







|

|







>
>
>
>
>
>







 







>
>
>
>







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
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
{
    $host = isset($_SERVER['HTTP_HOST']) 
        ? $_SERVER['HTTP_HOST'] 
        : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
    define('Garradin\WWW_URL', 'http' . (!empty($_SERVER['HTTPS']) ? 's' : '') . '://' . $host . WWW_URI);
}

if (!defined('Garradin\PLUGINS_ROOT'))
{
    define('Garradin\PLUGINS_ROOT', DATA_ROOT . '/plugins');
}

// Affichage des erreurs par défaut
if (!defined('Garradin\SHOW_ERRORS'))
{
    define('Garradin\SHOW_ERRORS', true);
}

// Utilisation de cron pour les tâches automatiques
if (!defined('Garradin\USE_CRON'))
{
    define('Garradin\USE_CRON', false);
}

define('Garradin\WEBSITE', 'http://garradin.eu/');
define('Garradin\PLUGINS_URL', 'https://garradin.eu/plugins/list.json');

// PHP devrait être assez intelligent pour chopper la TZ système mais nan
// il sait pas faire (sauf sur Debian qui a le bon patch pour ça), donc pour 
// éviter le message d'erreur à la con on définit une timezone par défaut
................................................................................
        <pre> \__/<br /> (xx)<br />//||\\\\</pre>
        <h1>Erreur d\'exécution</h1>
        <p>Une erreur s\'est produite à l\'exécution de Garradin. Pour rapporter ce bug
        merci d\'inclure le message suivant :</p>
        <textarea cols="70" rows="'.substr_count($error, "\n").'">'.htmlspecialchars($error, ENT_QUOTES, 'UTF-8').'</textarea>
        <hr />
        <p><a href="http://dev.kd2.org/garradin/Rapporter%20un%20bug">Comment rapporter un bug</a></p>';
    }
    else
    {

    }

    exit;
}

set_error_handler('Garradin\exception_error_handler');
set_exception_handler('Garradin\exception_handler');

Modified src/www/admin/index.php from [76b02bcb9c] to [1c24b867dc].

24
25
26
27
28
29
30

31
32
33

34

35
36
37
38
39
40
}
else
{
	$tpl->assign('cotisation', false);
}

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


// On réalise la sauvegarde auto à cet endroit, c'est un peu inefficace mais bon


if ($config->get('frequence_sauvegardes') && $config->get('nombre_sauvegardes'))

{
	$s = new Sauvegarde;
	$s->auto();
}

?>







>

<
<
>
|
>

<
|



24
25
26
27
28
29
30
31
32


33
34
35
36

37
38
39
40
}
else
{
	$tpl->assign('cotisation', false);
}

$tpl->display('admin/index.tpl');
flush();



// Si pas de cron on réalise les tâches automatisées à ce moment-là
// c'est pas idéal mais mieux que rien
if (!USE_CRON)
{

	require_once ROOT . '/cron.php';
}

?>