Add first valid expression ruler. Still not linked to scheduleds.

This commit is contained in:
osaajani 2019-11-27 06:25:33 +01:00
parent f59f7bd757
commit f4bbfa0152
16 changed files with 1049 additions and 18 deletions

View File

@ -3,6 +3,7 @@
"ingenerator/tokenista": "^1.1",
"ajani/flash-message": "^2.0",
"giggsey/libphonenumber-for-php": "^8.10",
"twig/twig": "^3.0"
"twig/twig": "^3.0",
"symfony/expression-language": "^5.0"
}
}

450
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "645ff432da0c81453a7f3f1df765195d",
"content-hash": "5c471b1b5ba3135917d74c53558a6259",
"packages": [
{
"name": "ajani/flash-message",
@ -212,6 +212,336 @@
],
"time": "2018-02-26T14:16:22+00:00"
},
{
"name": "psr/cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"time": "2016-08-06T20:24:11+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"time": "2017-02-14T16:28:37+00:00"
},
{
"name": "psr/log",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2019-11-01T11:05:21+00:00"
},
{
"name": "symfony/cache",
"version": "v5.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "32bd1f9be1684bba768a6834037706cf0950843c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/32bd1f9be1684bba768a6834037706cf0950843c",
"reference": "32bd1f9be1684bba768a6834037706cf0950843c",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"psr/cache": "~1.0",
"psr/log": "~1.0",
"symfony/cache-contracts": "^1.1.7|^2",
"symfony/service-contracts": "^1.1|^2",
"symfony/var-exporter": "^4.4|^5.0"
},
"conflict": {
"doctrine/dbal": "<2.5",
"symfony/dependency-injection": "<4.4",
"symfony/http-kernel": "<4.4",
"symfony/var-dumper": "<4.4"
},
"provide": {
"psr/cache-implementation": "1.0",
"psr/simple-cache-implementation": "1.0",
"symfony/cache-implementation": "1.0"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/cache": "~1.6",
"doctrine/dbal": "~2.5",
"predis/predis": "~1.1",
"psr/simple-cache": "^1.0",
"symfony/config": "^4.4|^5.0",
"symfony/dependency-injection": "^4.4|^5.0",
"symfony/var-dumper": "^4.4|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Cache\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Cache component with PSR-6, PSR-16, and tags",
"homepage": "https://symfony.com",
"keywords": [
"caching",
"psr6"
],
"time": "2019-11-18T17:27:11+00:00"
},
{
"name": "symfony/cache-contracts",
"version": "v2.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache-contracts.git",
"reference": "a91281de82119a7a07481b892f709d88da592cd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/a91281de82119a7a07481b892f709d88da592cd3",
"reference": "a91281de82119a7a07481b892f709d88da592cd3",
"shasum": ""
},
"require": {
"php": "^7.2.9",
"psr/cache": "^1.0"
},
"suggest": {
"symfony/cache-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Cache\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to caching",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"time": "2019-11-09T09:18:34+00:00"
},
{
"name": "symfony/expression-language",
"version": "v5.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/expression-language.git",
"reference": "121ece2d8c52777db0809525526ba9875f5a483a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/expression-language/zipball/121ece2d8c52777db0809525526ba9875f5a483a",
"reference": "121ece2d8c52777db0809525526ba9875f5a483a",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"symfony/cache": "^4.4|^5.0",
"symfony/service-contracts": "^1.1|^2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\ExpressionLanguage\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony ExpressionLanguage Component",
"homepage": "https://symfony.com",
"time": "2019-11-18T17:27:11+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.12.0",
@ -329,6 +659,124 @@
],
"time": "2019-08-06T08:03:45+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "9d99e1556417bf227a62e14856d630672bf10eaf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/9d99e1556417bf227a62e14856d630672bf10eaf",
"reference": "9d99e1556417bf227a62e14856d630672bf10eaf",
"shasum": ""
},
"require": {
"php": "^7.2.9",
"psr/container": "^1.0"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"time": "2019-11-09T09:18:34+00:00"
},
{
"name": "symfony/var-exporter",
"version": "v5.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "e2f1eeb12edacf744c4b359a859204578fdf8549"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/e2f1eeb12edacf744c4b359a859204578fdf8549",
"reference": "e2f1eeb12edacf744c4b359a859204578fdf8549",
"shasum": ""
},
"require": {
"php": "^7.2.5"
},
"require-dev": {
"symfony/var-dumper": "^4.4|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\VarExporter\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code",
"homepage": "https://symfony.com",
"keywords": [
"clone",
"construct",
"export",
"hydrate",
"instantiate",
"serialize"
],
"time": "2019-11-18T17:27:11+00:00"
},
{
"name": "twig/twig",
"version": "v3.0.0",

View File

@ -41,7 +41,9 @@ namespace controllers\internals;
'condition' => $condition,
];
if (!$this->validate_condition($condition))
$internal_ruler = new Ruler();
$valid_condition = $internal_ruler->validate_condition($condition, ['contact' => (object) ['datas' => (object) null]]);
if (!$valid_condition)
{
return false;
}
@ -73,8 +75,10 @@ namespace controllers\internals;
'name' => $name,
'condition' => $condition,
];
if (!$this->validate_condition($condition))
$internal_ruler = new Ruler();
$valid_condition = $internal_ruler->validate_condition($condition, ['contact' => (object) ['datas' => (object) null]]);
if (!$valid_condition)
{
return false;
}
@ -102,11 +106,39 @@ namespace controllers\internals;
/**
* Verify if a condition string is valid (i.e we can parse it without error)
* Gets the user's contacts that respects a condition
* @param int $id_user : User id
* @param string $condition : Condition string to verify
* @return bool
*/
public function validate_condition (string $condition) : bool
public function get_contacts_for_condition_and_user (int $id_user, string $condition) : bool
{
$internal_contacts = new Contacts($this->bdd);
$contacts = $internal_contacts->gets_for_user($id_user);
$ruler = new Ruler();
foreach ($contacts as $key => $contact)
{
if ($contact['datas'] != null)
{
$contact['datas'] = json_decode($contact['datas']);
}
else
{
$contact['datas'] = new \stdClass();
}
$contact = (object) $contact;
$datas = ['contact' => $contact];
$is_valid = $ruler->evaluate_condition($condition, $datas);
if (!$is_valid)
{
unset($contacts[$key]);
}
}
return $contacts;
}
}

View File

@ -68,7 +68,7 @@ namespace controllers\internals;
* @param string $datas : Contact datas
* @return mixed bool|int : False if cannot create contact, id of the new contact else
*/
public function create($id_user, $number, $name, $datas)
public function create($id_user, $number, $name, ?string $datas = null)
{
$contact = [
'id_user' => $id_user,

View File

@ -0,0 +1,21 @@
<?php
namespace controllers\internals;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
class ExpressionProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions()
{
return [
ExpressionFunction::fromPhp('is_null', 'exists'),
ExpressionFunction::fromPhp('mb_strtolower', 'lower'),
ExpressionFunction::fromPhp('mb_strtoupper', 'upper'),
ExpressionFunction::fromPhp('mb_substr', 'substr'),
ExpressionFunction::fromPhp('abs', 'abs'),
ExpressionFunction::fromPhp('strtotime', 'date'),
];
}
}

75
controllers/internals/Ruler.php Executable file
View File

@ -0,0 +1,75 @@
<?php
/*
* This file is part of RaspiSMS.
*
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
*
* This source file is subject to the GPL-3.0 license that is bundled
* with this source code in the file LICENSE.
*/
namespace controllers\internals;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
/**
* Class to analyse rules used by conditional groups
*/
class Ruler extends \descartes\InternalController
{
private $expression_language;
/**
* Constructor
*/
public function __construct ()
{
$this->expression_language = new ExpressionLanguage();
//Add custom functions
$this->expression_language->registerProvider(new ExpressionProvider());
}
/**
* Verify if a condition is valid. i.e we can evaluate it without error.
* @param string $condition : The condition to evaluate.
* @param array $datas : The datas to made available to condition
* @return bool : false if invalid, true else
*/
public function validate_condition (string $condition, array $datas = []) : bool
{
try
{
$this->expression_language->evaluate($condition, $datas);
return true;
}
catch (\Exception $e)
{
echo "Error : ";
echo $e->getMessage();
return false;
}
}
/**
* Evaluate a condition
* @param string $condition : The condition to evaluate.
* @param array $datas : The datas to made available to condition
* @return ?bool : false if invalid, true else, null only on error
*/
public function evaluate_condition (string $condition, array $datas = []) : ?bool
{
try
{
$result = $this->expression_language->evaluate($condition, $datas);
return (bool) $result;
}
catch (\Exception $e)
{
return null;
}
}
}

View File

@ -0,0 +1,181 @@
<?php
/*
* This file is part of RaspiSMS.
*
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
*
* This source file is subject to the GPL-3.0 license that is bundled
* with this source code in the file LICENSE.
*/
namespace controllers\publics;
/**
* Page des groups.
*/
class ConditionalGroup extends \descartes\Controller
{
private $internal_conditional_group;
private $internal_contact;
private $internal_ruler;
private $internal_event;
/**
* Cette fonction est appelée avant toute les autres :
* Elle vérifie que l'utilisateur est bien connecté.
*
* @return void;
*/
public function __construct()
{
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
$this->internal_conditional_group = new \controllers\internals\ConditionalGroup($bdd);
$this->internal_contact = new \controllers\internals\Contact($bdd);
$this->internal_event = new \controllers\internals\Event($bdd);
$this->internal_ruler = new \controllers\internals\Ruler($bdd);
\controllers\internals\Tool::verifyconnect();
}
/**
* Return all conditionnals groups for administration
*
* @param mixed $page
*/
public function list($page = 0)
{
$page = (int) $page;
$groups = $this->internal_conditional_group->list_for_user($_SESSION['user']['id'], 25, $page);
$this->render('conditional_group/list', ['groups' => $groups]);
}
/**
* Cette fonction va supprimer une liste de groups.
*
* @param array int $_GET['ids'] : Les id des groups à supprimer
* @param mixed $csrf
*
* @return boolean;
*/
public function delete($csrf)
{
if (!$this->verify_csrf($csrf))
{
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
}
$ids = $_GET['ids'] ?? [];
foreach ($ids as $id)
{
$this->internal_conditional_group->delete_for_user($_SESSION['user']['id'], $id);
}
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
}
/**
* Cette fonction retourne la page d'ajout d'un group.
*/
public function add()
{
$this->render('conditional_group/add');
}
/**
* Cette fonction retourne la page d'édition des groups.
*
* @param int... $ids : Les id des groups à supprimer
*/
public function edit()
{
$ids = $_GET['ids'] ?? [];
$groups = $this->internal_conditional_group->gets_in_for_user($_SESSION['user']['id'], $ids);
$this->render('conditional_group/edit', [
'groups' => $groups,
]);
}
/**
* Cette fonction insert un nouveau group.
*
* @param $csrf : Le jeton CSRF
* @param string $_POST['name'] : Le nom du group
* @param array $_POST['condition'] : The condition to used
*/
public function create($csrf)
{
if (!$this->verify_csrf($csrf))
{
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'add'));
}
$name = $_POST['name'] ?? false;
$condition = $_POST['condition'] ?? false;
if (!$name || !$condition)
{
\FlashMessage\FlashMessage::push('danger', 'Des champs sont manquants !');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'add'));
}
$id_group = $this->internal_conditional_group->create($_SESSION['user']['id'], $name, $condition);
if (!$id_group)
{
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer ce groupe.');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'add'));
}
\FlashMessage\FlashMessage::push('success', 'Le groupe a bien été créé.');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
}
/**
* Cette fonction met à jour une group.
*
* @param $csrf : Le jeton CSRF
* @param array $_POST['groups'] : Un tableau des groups avec leur nouvelle valeurs & une entrée 'contacts_id' avec les ids des contacts pour chaque group
*
* @return boolean;
*/
public function update($csrf)
{
if (!$this->verify_csrf($csrf))
{
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
}
$groups = $_POST['groups'] ?? [];
$nb_groups_update = 0;
foreach ($groups as $id => $group)
{
$nb_groups_update += (int) $this->internal_conditional_group->update_for_user($_SESSION['user']['id'], $id, $group['name'], $group['condition']);
}
if ($nb_groups_update !== \count($groups))
{
\FlashMessage\FlashMessage::push('danger', 'Certains groupes n\'ont pas pu êtres mis à jour.');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
}
\FlashMessage\FlashMessage::push('success', 'Tous les groupes ont été modifiés avec succès.');
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
}
}

View File

@ -131,7 +131,7 @@ namespace controllers\publics;
$name = $_POST['name'] ?? false;
$number = $_POST['number'] ?? false;
$id_user = $_SESSION['user']['id'];
$datas = empty($_POST['datas']) ? null : $_POST['datas'];
$datas = $_POST['datas'] ?? [];
if (!$name || !$number)
{
@ -162,7 +162,11 @@ namespace controllers\publics;
$key = mb_ereg_replace('[\W]', '', $key);
$clean_datas[$key] = (string) $value;
}
}
$clean_datas = $clean_datas ?: null;
if ($clean_datas)
{
$clean_datas = json_encode($clean_datas);
}
@ -206,7 +210,7 @@ namespace controllers\publics;
$name = $contact['name'] ?? false;
$number = $contact['number'] ?? false;
$id_user = $_SESSION['user']['id'];
$datas = empty($contact['datas']) ? null : $contact['datas'];
$datas = $contact['datas'] ?? null;
if (!$name || !$number)
{
@ -218,7 +222,7 @@ namespace controllers\publics;
{
continue;
}
$clean_datas = null;
if ($datas)
{
@ -233,9 +237,14 @@ namespace controllers\publics;
$key = mb_ereg_replace('[\W]', '', $key);
$clean_datas[$key] = (string) $value;
}
}
$clean_datas = $clean_datas ?: null;
if ($clean_datas)
{
$clean_datas = json_encode($clean_datas);
}
$nb_contacts_update += (int) $this->internal_contact->update_for_user($id_user, $id_contact, $number, $name, $clean_datas);
}

View File

@ -32,7 +32,6 @@ CREATE TABLE IF NOT EXISTS scheduled
origin VARCHAR(25) DEFAULT NULL,
at DATETIME NOT NULL,
text VARCHAR(1000) NOT NULL,
condition VARCHAR(1000) DEFAULT NULL,
flash BOOLEAN NOT NULL DEFAULT 0,
FOREIGN KEY (id_user) REFERENCES user (id) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (id)
@ -89,7 +88,7 @@ CREATE TABLE IF NOT EXISTS `conditional_group`
id INT NOT NULL AUTO_INCREMENT,
id_user INT NOT NULL,
name VARCHAR(100) NOT NULL,
condition TEXT NOT NULL,
`condition` TEXT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id_user) REFERENCES user (id) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE (id_user, name)

View File

@ -11,7 +11,7 @@
namespace models;
class CondiditionalGroup extends StandardModel
class ConditionalGroup extends StandardModel
{
/**
* Return table name

View File

@ -77,6 +77,18 @@
'update' => '/group/update/{csrf}/',
'json_list' => '/groups.json/',
],
'ConditionalGroup' => [
'list' => [
'/conditional_group/',
'/conditional_group/p/{page}/',
],
'add' => '/conditional_group/add/',
'create' => '/conditional_group/create/{csrf}/',
'delete' => '/conditional_group/delete/{csrf}/',
'edit' => '/conditional_group/edit/',
'update' => '/conditional_group/update/{csrf}/',
],
'Received' => [
'list' => [

View File

@ -0,0 +1,66 @@
<?php
//Template dashboard
$this->render('incs/head', ['title' => 'Groupes Conditionnels - Add'])
?>
<div id="wrapper">
<?php
$this->render('incs/nav', ['page' => 'conditional_groupes'])
?>
<div id="page-wrapper">
<div class="container-fluid">
<!-- Page Heading -->
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
Nouveau groupe conditionnel
</h1>
<ol class="breadcrumb">
<li>
<i class="fa fa-dashboard"></i> <a href="<?php echo \descartes\Router::url('Dashboard', 'show'); ?>">Dashboard</a>
</li>
<li>
<i class="fa fa-random"></i> <a href="<?php echo \descartes\Router::url('ConditionalGroup', 'list'); ?>">Groupes Conditionnels</a>
</li>
<li class="active">
<i class="fa fa-plus"></i> Nouveau
</li>
</ol>
</div>
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-random fa-fw"></i> Ajout d'un groupe conditionnel</h3>
</div>
<div class="panel-body">
<form action="<?php echo \descartes\Router::url('ConditionalGroup', 'create', ['csrf' => $_SESSION['csrf']]);?>" method="POST">
<div class="form-group">
<label>Nom du groupe conditionnel</label>
<div class="form-group input-group">
<span class="input-group-addon"><span class="fa fa-users"></span></span>
<input name="name" class="form-control" type="text" placeholder="Nom groupe" autofocus required>
</div>
</div>
<div class="form-group">
<label>Condition</label>
<p class="italic small help">
Les conditions vous permettent de définir dynamiquement les contacts qui appartiennent au groupe en utilisant leurs données additionnelles. Pour plus d'informations consultez la documentation relative à <a href="#">l'utilisation des groupes conditionnels.</a>
</p>
<input class="form-control" name="condition" placeholder="Ex : contact.datas.gender == 'male'"/>
</div>
<a class="btn btn-danger" href="<?php echo \descartes\Router::url('ConditionalGroup', 'list'); ?>">Annuler</a>
<input type="submit" class="btn btn-success" value="Enregistrer le groupe" />
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php
$this->render('incs/footer');

View File

@ -0,0 +1,83 @@
<?php
//Template dashboard
$this->render('incs/head', ['title' => 'Groupes Conditionnels - Edit'])
?>
<div id="wrapper">
<?php
$this->render('incs/nav', ['page' => 'conditional_groupes'])
?>
<div id="page-wrapper">
<div class="container-fluid">
<!-- Page Heading -->
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
Modification groupes conditionnels
</h1>
<ol class="breadcrumb">
<li>
<i class="fa fa-dashboard"></i> <a href="<?php echo \descartes\Router::url('Dashboard', 'show'); ?>">Dashboard</a>
</li>
<li>
<i class="fa fa-random"></i> <a href="<?php echo \descartes\Router::url('ConditionalGroup', 'list'); ?>">Groupes Conditionnels</a>
</li>
<li class="active">
<i class="fa fa-edit"></i> Modifier
</li>
</ol>
</div>
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-edit fa-fw"></i> Modification des groupes conditionnels</h3>
</div>
<div class="panel-body">
<form action="<?php echo \descartes\Router::url('ConditionalGroup', 'update', ['csrf' => $_SESSION['csrf']]);?>" method="POST">
<?php foreach ($groups as $group) { ?>
<input name="groups[<?php $this->s($group['id']); ?>][group][id]" type="hidden" value="<?php $this->s($group['id']); ?>">
<div class="form-group">
<label>Nom du groupe conditionnel</label>
<div class="form-group input-group">
<span class="input-group-addon"><span class="fa fa-user"></span></span>
<input name="groups[<?php $this->s($group['id']); ?>][name]" class="form-control" type="text" placeholder="Nom groupe" autofocus required value="<?php $this->s($group['name']); ?>">
</div>
</div>
<div class="form-group">
<label>Condition</label>
<p class="italic small help">
Les conditions vous permettent de définir dynamiquement les contacts qui appartiennent au groupe en utilisant leurs données additionnelles. Pour plus d'informations consultez la documentation relative à <a href="#">l'utilisation des groupes conditionnels.</a>
</p>
<input class="form-control" name="groups[<?php $this->s($group['id']); ?>][condition]" value="<?php $this->s($group['condition']); ?>"/>
</div>
<hr/>
<?php } ?>
<a class="btn btn-danger" href="<?php echo \descartes\Router::url('ConditionalGroup', 'list'); ?>">Annuler</a>
<input type="submit" class="btn btn-success" value="Enregistrer le groupe" />
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
jQuery(document).ready(function()
{
jQuery('.add-contacts').each(function()
{
jQuery(this).magicSuggest({
data: '<?php echo \descartes\Router::url('Contact', 'json_list'); ?>',
valueField: 'id',
displayField: 'name',
});
});
});
</script>
<?php
$this->render('incs/footer');

View File

@ -0,0 +1,101 @@
<?php
//Template dashboard
$this->render('incs/head', ['title' => 'ConditionalGroupes Conditionnels - Show All'])
?>
<div id="wrapper">
<?php
$this->render('incs/nav', ['page' => 'conditional_groupes'])
?>
<div id="page-wrapper">
<div class="container-fluid">
<!-- Page Heading -->
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
Dashboard <small>Groupes Conditionnels</small>
</h1>
<ol class="breadcrumb">
<li>
<i class="fa fa-dashboard"></i> <a href="<?php echo \descartes\Router::url('Dashboard', 'show'); ?>">Dashboard</a>
</li>
<li class="active">
<i class="fa fa-random"></i> Groupes Conditionnels
</li>
</ol>
</div>
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-random fa-fw"></i> Liste des groupes conditionnels</h3>
</div>
<div class="panel-body">
<form method="GET">
<?php if (!$groups) { ?>
<p>Aucun groupe n'a été formé pour le moment.</p>
<?php } else { ?>
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped" id="table-groupes">
<thead>
<tr>
<th>#</th>
<th>Nom</th>
<th>Condition</th>
<th style="width:5%;">Sélectionner</th>
</tr>
</thead>
<tbody>
<?php foreach ($groups as $group) { ?>
<tr>
<td><?php $this->s($group['id']); ?></td>
<td><?php $this->s($group['name']); ?></td>
<td><?php $this->s($group['condition']); ?></td>
<td><input type="checkbox" name="ids[]" value="<?php $this->s($group['id']); ?>"></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
<?php } ?>
<div>
<div class="col-xs-6 no-padding">
<a class="btn btn-success" href="<?php echo \descartes\Router::url('ConditionalGroup', 'add'); ?>"><span class="fa fa-plus"></span> Ajouter un groupe conditionnel</a>
</div>
<?php if ($groups) { ?>
<div class="text-right col-xs-6 no-padding">
<strong>Action pour la séléction :</strong>
<button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('ConditionalGroup', 'edit'); ?>"><span class="fa fa-edit"></span> Modifier</button>
<button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('ConditionalGroup', 'delete', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-trash-o"></span> Supprimer</button>
</div>
<?php } ?>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
jQuery(document).ready(function ()
{
jQuery('.action-dropdown a').on('click', function (e)
{
e.preventDefault();
var destination = jQuery(this).parents('.action-dropdown').attr('destination');
var url = jQuery(this).attr('href');
jQuery(destination).find('input:checked').each(function ()
{
url += '/' + jQuery(this).val();
});
window.location = url;
});
});
</script>
<?php
$this->render('incs/footer');

View File

@ -19,7 +19,7 @@
</script>
<?php } ?>
<?php if (!$_SESSION['user']['settings']['display_help']) { ?>
<?php if (!$_SESSION['user']['settings']['display_help'] ?? false) { ?>
<style>.help {display: none;}</style>
<?php } ?>

View File

@ -55,13 +55,16 @@
</li>
<li>
<a href="javascript:;" data-toggle="collapse" data-target="#repertoire"><i class="fa fa-fw fa-book"></i> Répertoire <i class="fa fa-fw fa-caret-down"></i></a>
<ul id="repertoire" class="collapse <?php echo in_array($page, array('contacts', 'groupes')) ? 'in' : ''; ?>">
<ul id="repertoire" class="collapse <?php echo in_array($page, array('contacts', 'groupes', 'conditional_groupes')) ? 'in' : ''; ?>">
<li <?php echo $page == 'contacts' ? 'class="active"' : ''; ?>>
<a href="<?php echo \descartes\Router::url('Contact', 'list'); ?>"><i class="fa fa-fw fa-user"></i> Contacts</a>
</li>
<li <?php echo $page == 'groupes' ? 'class="active"' : ''; ?>>
<a href="<?php echo \descartes\Router::url('Group', 'list'); ?>"><i class="fa fa-fw fa-group"></i> Groupes</a>
</li>
<li <?php echo $page == 'conditional_groupes' ? 'class="active"' : ''; ?>>
<a href="<?php echo \descartes\Router::url('ConditionalGroup', 'list'); ?>"><i class="fa fa-fw fa-random"></i> Groupes Conditionnels</a>
</li>
</ul>
</li>
<li>