Overview
Comment:Refactor saved searches
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA3-256: 973cc37152f4dbf0277c917c735737372a7b6a08f63ec8a8a7dc3b2c74da7c2a
User & Date: bohwaz on 2022-04-03 17:54:07
Other Links: branch diff | manifest | tags
Context
2022-04-03
18:30
Try to migrate saved searches to new schema check-in: 8465743e92 user: bohwaz tags: dev
17:54
Refactor saved searches check-in: 973cc37152 user: bohwaz tags: dev
17:26
Only show selected columns in results check-in: 198c92fdef user: bohwaz tags: dev
Changes

Modified src/include/lib/Garradin/Entities/Search.php from [741d5e34fa] to [04e9a49497].

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
	const TARGET_ACCOUNTING = 'accounting';

	const TARGETS = [
		self::TARGET_USERS => 'Membres',
		self::TARGET_ACCOUNTING => 'Comptabilité',
	];

	protected int $id;
	protected ?int $id_user = null;
	protected string $label;
	protected \DateTime $created;
	protected string $target;
	protected string $type;
	protected string $content;








|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
	const TARGET_ACCOUNTING = 'accounting';

	const TARGETS = [
		self::TARGET_USERS => 'Membres',
		self::TARGET_ACCOUNTING => 'Comptabilité',
	];

	protected ?int $id;
	protected ?int $id_user = null;
	protected string $label;
	protected \DateTime $created;
	protected string $target;
	protected string $type;
	protected string $content;

Modified src/include/lib/Garradin/Search.php from [a51d6dad77] to [237cb6df6a].

1
2
3
4
5


6
7
8
9
10
11
12
<?php

namespace Garradin;

use Garradin\Entities\Search as SE;



class Search
{
	static public function list(int $id_user, string $target): array
	{
		return EM::getInstance(SE::class)->all('SELECT * FROM @TABLE
			WHERE (id_user IS NULL OR id_user = ?) AND target = ?





>
>







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

namespace Garradin;

use Garradin\Entities\Search as SE;

use KD2\DB\EntityManager as EM;

class Search
{
	static public function list(int $id_user, string $target): array
	{
		return EM::getInstance(SE::class)->all('SELECT * FROM @TABLE
			WHERE (id_user IS NULL OR id_user = ?) AND target = ?

Modified src/templates/common/search/saved_searches.tpl from [c5426cd9d9] to [48379cfbf5].

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
{include file="admin/_head.tpl" title="Recherches enregistrées" current=$target}

{if $target == 'membres'}
	{include file="admin/membres/_nav.tpl" current="recherches"}
{else}
	<nav class="tabs">
		<ul>
			<li><a href="search.php">Recherche</a></li>
			<li class="current"><a href="saved_searches.php">Recherches enregistrées</a></li>
		</ul>
	</nav>
{/if}

{if $mode == 'edit'}
	{form_errors}

	<form method="post" action="{$self_url}">
		<fieldset>
			<legend>Modifier une recherche enregistrée</legend>
			<dl>
				{input type="text" name="intitule" label="Intitulé" required=1 source=$recherche}
				<dt>Statut</dt>
				<?php $checked = (int)(bool)$recherche->id_membre; ?>
				{input type="radio" name="prive" value="1" default=$checked label="Recherche privée" help="Visible seulement par moi-même"}
				{input type="radio" name="prive" value="0" default=$checked label="Recherche publique" help="Visible et exécutable par tous les membres ayant accès à la gestion %s"|args:$target}
				<dt>Type</dt>
				<dd>
					{if $recherche.type == Recherche::TYPE_JSON}
						Avancée
					{elseif $recherche.type == Recherche::TYPE_SQL_UNPROTECTED}
						SQL non protégée
					{else}
						SQL
					{/if}</dd>
				<dt>Cible</dt>
				<dd>{$recherche.cible}</dd>
			</dl>
		</fieldset>

		<p class="submit">
			{csrf_field key="edit_recherche_%s"|args:$recherche.id}
			{button type="submit" name="save" label="Enregistrer" shape="right" class="main"}
		</p>
	</form>
{elseif $mode == 'delete'}

	{include file="common/delete_form.tpl"
		legend="Supprimer cette recherche enregistrée ?"
		warning="Êtes-vous sûr de vouloir supprimer la recherche enregistrée « %s » ?"|args:$recherche.intitule
		csrf_key="del_recherche_%s"|args:$recherche.id
	}

{elseif count($liste) == 0}
	<p class="block alert">Aucune recherche enregistrée. <a href="{$search_url}">Faire une nouvelle recherche</a></p>
{else}
	<table class="list">
		<thead>
			<tr>
				<th>Recherche</th>
				<th>Type</th>
				<th>Statut</th>
				<th></th>
			</tr>
		</thead>
		<tbody>
			{foreach from=$liste item="recherche"}
			<tr>
				<th><a href="{$search_url}?id={$recherche.id}">{$recherche.intitule}</a></th>
				<td>{if $recherche.type == Recherche::TYPE_JSON}Avancée{else}SQL{/if}</td>
				<td>{if !$recherche.id_membre}Publique{else}Privée{/if}</td>
				<td class="actions">
					{linkbutton href="%s?id=%d"|args:$search_url,$recherche.id shape="search" label="Rechercher"}
					{if $recherche.id_membre || $session->canAccess($access_section, $session::ACCESS_ADMIN)}
						{linkbutton href="?edit=%d"|args:$recherche.id shape="edit" label="Modifier"}
						{linkbutton href="?delete=%d"|args:$recherche.id shape="delete" label="Supprimer"}
					{/if}
				</td>
			</tr>
			{/foreach}
		</tbody>
	</table>
{/if}

{include file="admin/_foot.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
74
75
76
77
78
79
80
81
82
83
{include file="admin/_head.tpl" title="Recherches enregistrées" current=$target}

{if $target == 'users'}
	{include file="users/_nav.tpl" current="searches"}
{else}
	<nav class="tabs">
		<ul>
			<li><a href="search.php">Recherche</a></li>
			<li class="current"><a href="saved_searches.php">Recherches enregistrées</a></li>
		</ul>
	</nav>
{/if}

{if $mode == 'edit'}
	{form_errors}

	<form method="post" action="{$self_url}">
		<fieldset>
			<legend>Modifier une recherche enregistrée</legend>
			<dl>
				{input type="text" name="label" label="Intitulé" required=1 source=$search}
				<dt>Statut</dt>
				<?php $checked = (int)(bool)$search->id_membre; ?>
				{input type="radio" name="prive" value="1" default=$checked label="Recherche privée" help="Visible seulement par moi-même"}
				{input type="radio" name="prive" value="0" default=$checked label="Recherche publique" help="Visible et exécutable par tous les membres ayant accès à la gestion %s"|args:$target}
				<dt>Type</dt>
				<dd>
					{if $search.type == $search::TYPE_JSON}
						Avancée
					{elseif $search.type == $search::TYPE_SQL_UNPROTECTED}
						SQL non protégée
					{else}
						SQL
					{/if}
				</dd>

			</dl>
		</fieldset>

		<p class="submit">
			{csrf_field key=$csrf_key}
			{button type="submit" name="save" label="Enregistrer" shape="right" class="main"}
		</p>
	</form>
{elseif $mode == 'delete'}

	{include file="common/delete_form.tpl"
		legend="Supprimer cette recherche enregistrée ?"
		warning="Êtes-vous sûr de vouloir supprimer la recherche enregistrée « %s » ?"|args:$search.label
		csrf_key=$csrf_key
	}

{elseif count($list) == 0}
	<p class="block alert">Aucune recherche enregistrée. <a href="{$search_url}">Faire une nouvelle recherche</a></p>
{else}
	<table class="list">
		<thead>
			<tr>
				<th>Recherche</th>
				<th>Type</th>
				<th>Statut</th>
				<th></th>
			</tr>
		</thead>
		<tbody>
			{foreach from=$list item="search"}
			<tr>
				<th><a href="{$search_url}?id={$search.id}">{$search.label}</a></th>
				<td>{if $search.type == $search::TYPE_JSON}Avancée{else}SQL{/if}</td>
				<td>{if !$search.id_user}Publique{else}Privée{/if}</td>
				<td class="actions">
					{linkbutton href="%s?id=%d"|args:$search_url,$search.id shape="search" label="Rechercher"}
					{if $search.id_membre || $session->canAccess($access_section, $session::ACCESS_ADMIN)}
						{linkbutton href="?edit=%d"|args:$search.id shape="edit" label="Modifier"}
						{linkbutton href="?delete=%d"|args:$search.id shape="delete" label="Supprimer"}
					{/if}
				</td>
			</tr>
			{/foreach}
		</tbody>
	</table>
{/if}

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

Modified src/templates/users/search.tpl from [40ac8077dd] to [f5d1da42a6].

1
2
3
4
5
6
7
8
{include file="admin/_head.tpl" title="Recherche de membre" current="membres" custom_js=['lib/query_builder.min.js']}

{include file="users/_nav.tpl" current="search"}

{include file="common/search/advanced.tpl" action_url=$self_url}

{if $session->canAccess($session::SECTION_USERS, $session::ACCESS_WRITE)}
	<form method="post" action="{$admin_url}membres/action.php" class="memberList">
|







1
2
3
4
5
6
7
8
{include file="admin/_head.tpl" title="Recherche de membre" current="users" custom_js=['lib/query_builder.min.js']}

{include file="users/_nav.tpl" current="search"}

{include file="common/search/advanced.tpl" action_url=$self_url}

{if $session->canAccess($session::SECTION_USERS, $session::ACCESS_WRITE)}
	<form method="post" action="{$admin_url}membres/action.php" class="memberList">

Modified src/www/admin/acc/saved_searches.php from [76dcbfceee] to [ff2bd7e578].

1
2
3
4
5
6
7
8
9
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

$target = 'compta';
$search_url = ADMIN_URL . 'acc/search.php';

require __DIR__ . '/../common/saved_searches.php';





|



1
2
3
4
5
6
7
8
9
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

const CURRENT_SEARCH_TARGET = 'accounting';
$search_url = ADMIN_URL . 'acc/search.php';

require __DIR__ . '/../common/saved_searches.php';

Modified src/www/admin/common/saved_searches.php from [b986545306] to [e5a3c04fd9].

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





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

if (empty($target) || !in_array($target, Recherche::TARGETS)) {
    throw new UserException('Cible inconnue');
}

if (empty($search_url)) {
	throw new \LogicException('Missing $search_url');
}

$access_section = $target == 'compta' ? $session::SECTION_ACCOUNTING : $session::SECTION_USERS;

$recherche = new Recherche;
$mode = null;

if (qg('edit') || qg('delete'))
{
	$r = $recherche->get(qg('edit') ?: qg('delete'));

	if (!$r)
	{
		throw new UserException('Recherche non trouvée');
	}

	if ($r->id_membre !== null && $r->id_membre != $user->id)
	{
		throw new UserException('Recherche privée appartenant à un autre membre.');
	}

	$tpl->assign('recherche', $r);

	$mode = qg('edit') ? 'edit' : 'delete';
}

if ($mode == 'edit' && f('save') && $form->check('edit_recherche_' . $r->id))
{
	try {
		$recherche->edit($r->id, [
			'intitule'  => f('intitule'),
			'id_membre' => f('prive') ? $user->id : null,
		]);

		Utils::redirect(Utils::getSelfURI(false));
	}
	catch (UserException $e) {
		$form->addError($e->getMessage());


	}


}
elseif ($mode == 'delete' && f('delete') && $form->check('del_recherche_' . $r->id))
{
	$recherche->remove($r->id);
	Utils::redirect(Utils::getSelfURI(false));
}


if (!$mode)
{
	$tpl->assign('liste', $recherche->getList($user->id, $target));
}


$tpl->assign(compact('mode', 'target', 'search_url', 'access_section'));

$tpl->display('common/search/saved_searches.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
<?php
namespace Garradin;

use Garradin\Entities\Search as SE;
use Garradin\Search;
use Garradin\Users\Session;

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

if (!defined('Garradin\CURRENT_SEARCH_TARGET') || !array_key_exists(CURRENT_SEARCH_TARGET, SE::TARGETS)) {
	throw new UserException('Cible inconnue');
}

if (empty($search_url)) {
	throw new \LogicException('Missing $search_url');
}

$access_section = CURRENT_SEARCH_TARGET == 'accounting' ? $session::SECTION_ACCOUNTING : $session::SECTION_USERS;


$mode = null;

if (qg('edit') || qg('delete'))
{
	$s = Search::get(qg('edit') ?: qg('delete'));

	if (!$s) {

		throw new UserException('Recherche non trouvée');
	}

	if ($s->id_user !== null && $r->id_user != Session::getInstance()->getUser()->id) {

		throw new UserException('Recherche privée appartenant à un autre membre.');
	}


	$csrf_key = 'search_' . $s->id;


	$form->runIf('save', function () use ($s) {






		$s->importForm();
		$s->save();
	}, $csrf_key, Utils::getSelfURI(false));


	$form->runIf('delete', function () use ($s) {
		$s->delete();
	}, $csrf_key, Utils::getSelfURI(false));

	$tpl->assign('search', $s);
	$tpl->assign('csrf_key', $csrf_key);

	$mode = qg('edit') ? 'edit' : 'delete';



}
else {
	$tpl->assign('list', Search::list(Session::getInstance()->getUser()->id, CURRENT_SEARCH_TARGET));
	$mode = 'list';


}

$target = CURRENT_SEARCH_TARGET;
$tpl->assign(compact('mode', 'target', 'search_url', 'access_section'));

$tpl->display('common/search/saved_searches.tpl');

Modified src/www/admin/common/search.php from [5cb21d400e] to [047afdeb57].

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

use Garradin\Accounting\Years;
use Garradin\Entities\Search as SE;
use Garradin\Search;
use Garradin\Users\Session;

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

if (!defined('Garradin\CURRENT_SEARCH_TARGET') || !array_key_exists(CURRENT_SEARCH_TARGET, SE::TARGETS)) {



<







1
2
3

4
5
6
7
8
9
10
<?php
namespace Garradin;


use Garradin\Entities\Search as SE;
use Garradin\Search;
use Garradin\Users\Session;

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

if (!defined('Garradin\CURRENT_SEARCH_TARGET') || !array_key_exists(CURRENT_SEARCH_TARGET, SE::TARGETS)) {

Added src/www/admin/users/saved_searches.php version [efd71f4473].



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

const CURRENT_SEARCH_TARGET = 'users';
$search_url = ADMIN_URL . 'users/search.php';

require __DIR__ . '/../common/saved_searches.php';