Overview
Comment:Ajout configuration d'exemple + ajout gestion tâche automatisées
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 94082a8d1fa9a497c35f9e9c17fedb4c6ebcfcf0
User & Date: bohwaz on 2014-03-26 17:29:17
Other Links: manifest | tags
Context
2014-03-26
17:47
Vague de "required" dans les formulaires check-in: 6e539273e0 user: bohwaz tags: trunk
17:29
Ajout configuration d'exemple + ajout gestion tâche automatisées check-in: 94082a8d1f user: bohwaz tags: trunk
17:06
Possibilité de faire un rappel le jour de l'expiration check-in: da117a9e3e 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

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







|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

	/**
	 * 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.
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
	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







|







198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
	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
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
	 * @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;
	}








|












|







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
	 * @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;
	}

344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
	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







|







344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
	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
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
		$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 = [







|







377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
		$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 = [
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
				'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'],
			'description'=>	$infos['description'],
			'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é







|








|
















|




|




|











|








|





|





|















|

|







399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
				'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'],
			'description'=>	$infos['description'],
			'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
{
    $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







|

|







>
>
>
>
>
>







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
{
    $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
207
208
209
210
211
212
213




214
215
216
217
218
219
220
        <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');







>
>
>
>







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
        <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';
}

?>