mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'master' into CRUD-init
This commit is contained in:
commit
547439d9ef
28
CHANGELOG.md
28
CHANGELOG.md
@ -65,10 +65,34 @@ Version 1.5.10
|
||||
|
||||
- allow to group export in UI
|
||||
|
||||
Branch CRUD-Init
|
||||
================
|
||||
Version 1.5.11
|
||||
==============
|
||||
|
||||
- improve return path functions and filters ;
|
||||
|
||||
Version 1.5.12
|
||||
==============
|
||||
|
||||
- make the redirection to admin temporarily: some admin experienced cache problems (403 error) when they switched from one admin account to a non-admin one ;
|
||||
|
||||
Version 1.5.13
|
||||
==============
|
||||
|
||||
- allow to customize logo on login screen and main layout ;
|
||||
- remove desert background image on page, handle it from cache in login screen;
|
||||
|
||||
Version 1.5.14
|
||||
==============
|
||||
|
||||
- fix errors in pagination
|
||||
- fix search: usage of parenthesis
|
||||
- add DQL function REPLACE for replacing in strings: "REPLACE(string, 'from', 'to')"
|
||||
- add function to format phonenumber
|
||||
- improve `chill_print_or_message` to support date time;
|
||||
- add a module `show_hide` for javascript;
|
||||
- load assets using functions ;
|
||||
- load a `runtime.js` assets for objects shared by webpack ;
|
||||
|
||||
Branch CRUD-Init
|
||||
================
|
||||
|
||||
|
@ -10,7 +10,7 @@ class DefaultController extends Controller
|
||||
{
|
||||
if ($this->isGranted('ROLE_ADMIN')) {
|
||||
|
||||
return $this->redirectToRoute('chill_main_admin_central');
|
||||
return $this->redirectToRoute('chill_main_admin_central', [], 302);
|
||||
}
|
||||
|
||||
return $this->render('ChillMainBundle::layout.html.twig');
|
||||
|
@ -34,6 +34,7 @@ use Chill\MainBundle\Doctrine\DQL\Similarity;
|
||||
use Chill\MainBundle\Doctrine\DQL\OverlapsI;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Chill\MainBundle\Doctrine\DQL\Replace;
|
||||
|
||||
/**
|
||||
* This class load config for chillMainExtension.
|
||||
@ -164,7 +165,8 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
'string_functions' => array(
|
||||
'unaccent' => Unaccent::class,
|
||||
'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class,
|
||||
'AGGREGATE' => JsonAggregate::class
|
||||
'AGGREGATE' => JsonAggregate::class,
|
||||
'REPLACE' => Replace::class,
|
||||
),
|
||||
'numeric_functions' => [
|
||||
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
|
||||
|
64
Doctrine/DQL/Replace.php
Normal file
64
Doctrine/DQL/Replace.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
* Copyright (C) 2019 Champs-Libres Coopérative <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\MainBundle\Doctrine\DQL;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class Replace extends FunctionNode
|
||||
{
|
||||
protected $string;
|
||||
|
||||
protected $from;
|
||||
|
||||
protected $to;
|
||||
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker): string
|
||||
{
|
||||
return 'REPLACE('.
|
||||
$this->string->dispatch($sqlWalker).
|
||||
', '.
|
||||
$this->from->dispatch($sqlWalker).
|
||||
', '.
|
||||
$this->to->dispatch($sqlWalker).
|
||||
')';
|
||||
}
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser): void
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->string = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->from = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->to = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
@ -63,6 +63,13 @@ class Page implements PageInterface
|
||||
* @var int
|
||||
*/
|
||||
protected $itemPerPage;
|
||||
|
||||
/**
|
||||
* The number of items in the whole iteration
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $totalItems;
|
||||
|
||||
|
||||
public function __construct(
|
||||
@ -70,13 +77,15 @@ class Page implements PageInterface
|
||||
$itemPerPage,
|
||||
UrlGeneratorInterface $urlGenerator,
|
||||
$route,
|
||||
array $routeParameters
|
||||
array $routeParameters,
|
||||
$totalItems
|
||||
) {
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->number = $number;
|
||||
$this->itemPerPage = $itemPerPage;
|
||||
$this->route = $route;
|
||||
$this->routeParameters = $routeParameters;
|
||||
$this->totalItems = $totalItems;
|
||||
}
|
||||
|
||||
public function generateUrl()
|
||||
@ -91,7 +100,9 @@ class Page implements PageInterface
|
||||
|
||||
public function getLastItemNumber()
|
||||
{
|
||||
return $this->number * $this->itemPerPage - 1;
|
||||
$last = $this->number * $this->itemPerPage - 1;
|
||||
|
||||
return $last < $this->totalItems ? $last : $this->totalItems;
|
||||
}
|
||||
|
||||
public function getNumber()
|
||||
|
@ -232,7 +232,8 @@ class Paginator implements PaginatorInterface
|
||||
array_merge($this->routeParameters, array(
|
||||
$this->pageKey => $number,
|
||||
$this->itemPerPageKey => $this->itemPerPage
|
||||
))
|
||||
)),
|
||||
$this->totalItems
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ class PhonenumberHelper
|
||||
protected $cachePool;
|
||||
|
||||
const LOOKUP_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s';
|
||||
const FORMAT_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s';
|
||||
|
||||
|
||||
public function __construct(
|
||||
@ -121,6 +122,64 @@ class PhonenumberHelper
|
||||
return \in_array($validation, [ 'landline', 'voip' ]);
|
||||
}
|
||||
|
||||
public function format($phonenumber)
|
||||
{
|
||||
return $this->performTwilioFormat($phonenumber);
|
||||
}
|
||||
|
||||
protected function performTwilioFormat($phonenumber)
|
||||
{
|
||||
if (FALSE === $this->isPhonenumberValidationConfigured()) {
|
||||
return $phonenumber;
|
||||
}
|
||||
|
||||
// filter only number
|
||||
$filtered = \preg_replace("/[^0-9]/", "", $phonenumber);
|
||||
|
||||
$item = $this->cachePool->getItem('pnum_format_nat_'.$filtered);
|
||||
|
||||
if ($item->isHit()) {
|
||||
return $item->get();
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->twilioClient->get(sprintf(self::FORMAT_URI, '+'.$filtered), [
|
||||
'http_errors' => true,
|
||||
]);
|
||||
|
||||
} catch (ClientException $e) {
|
||||
$this->logger->error("[phonenumber helper] Could not format number "
|
||||
. "due to client error", [
|
||||
"message" => $e->getResponseBodySummary($e->getResponse()),
|
||||
"status_code" => $e->getResponse()->getStatusCode(),
|
||||
"phonenumber" => $phonenumber
|
||||
]);
|
||||
|
||||
return $phonenumber;
|
||||
} catch (ServerException $e) {
|
||||
$this->logger->error("[phonenumber helper] Could not format number "
|
||||
. "due to server error", [
|
||||
"message" => $e->getResponseBodySummary($e->getResponse()),
|
||||
"status_code" => $e->getResponse()->getStatusCode(),
|
||||
"phonenumber" => $phonenumber
|
||||
]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$format = \json_decode($response->getBody())->national_format;
|
||||
|
||||
$item
|
||||
->set($format)
|
||||
// expires after 3d
|
||||
->expiresAfter(3600 * 24 * 3)
|
||||
;
|
||||
|
||||
$this->cachePool->save($item);
|
||||
|
||||
return $format;
|
||||
}
|
||||
|
||||
protected function performTwilioLookup($phonenumber)
|
||||
{
|
||||
if (FALSE === $this->isPhonenumberValidationConfigured()) {
|
||||
|
52
Phonenumber/Templating.php
Normal file
52
Phonenumber/Templating.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2019 Champs Libres Cooperative <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\MainBundle\Phonenumber;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
use Chill\MainBundle\Phonenumber\PhonenumberHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class Templating extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var PhonenumberHelper
|
||||
*/
|
||||
protected $phonenumberHelper;
|
||||
|
||||
public function __construct(PhonenumberHelper $phonenumberHelper)
|
||||
{
|
||||
$this->phonenumberHelper = $phonenumberHelper;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('chill_format_phonenumber', [$this, 'formatPhonenumber'])
|
||||
];
|
||||
}
|
||||
|
||||
public function formatPhonenumber($phonenumber)
|
||||
{
|
||||
return $this->phonenumberHelper->format($phonenumber);
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ root:
|
||||
defaults:
|
||||
_controller: FrameworkBundle:Redirect:urlRedirect
|
||||
path: /homepage
|
||||
permanent: true
|
||||
permanent: false
|
||||
|
||||
chill_main_homepage_without_locale:
|
||||
path: /homepage
|
||||
|
@ -4,6 +4,12 @@ services:
|
||||
$logger: '@Psr\Log\LoggerInterface'
|
||||
$config: '%chill_main.phone_helper%'
|
||||
$cachePool: '@cache.user_data'
|
||||
|
||||
Chill\MainBundle\Phonenumber\Templating:
|
||||
arguments:
|
||||
$phonenumberHelper: '@Chill\MainBundle\Phonenumber\PhonenumberHelper'
|
||||
tags:
|
||||
- { name: twig.extension }
|
||||
|
||||
Chill\MainBundle\Validation\Validator\ValidPhonenumber:
|
||||
arguments:
|
||||
|
@ -27,8 +27,6 @@ require('./modules/download-report/index.js');
|
||||
require('select2/dist/css/select2.css');
|
||||
require('./modules/select_interactive_loading/index.js');
|
||||
require('./modules/export-list/export-list.scss');
|
||||
//import {ChillShowHide} from './modules/show_hide/index.js';
|
||||
//global.ChillShowHide = ChillShowHide;
|
||||
|
||||
// img
|
||||
require('./img/favicon.ico');
|
||||
|
BIN
Resources/public/modules/login_page/desert.jpg
Normal file
BIN
Resources/public/modules/login_page/desert.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 MiB |
@ -28,7 +28,7 @@ body {
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
background-image: url('./../../img/background/desert.jpg');
|
||||
background-image: url('./desert.jpg');
|
||||
background-attachment: fixed;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
|
1
Resources/views/Layout/_header-logo.html.twig
Normal file
1
Resources/views/Layout/_header-logo.html.twig
Normal file
@ -0,0 +1 @@
|
||||
<img class="logo" src="{{ asset('build/images/logo-chill-sans-slogan_white.png') }}">
|
1
Resources/views/Login/_login-logo.html.twig
Normal file
1
Resources/views/Login/_login-logo.html.twig
Normal file
@ -0,0 +1 @@
|
||||
<img class="logo" src="{{ asset('build/images/logo-chill-outil-accompagnement_white.png') }}">
|
@ -27,8 +27,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<img class="logo" src="{{ asset('build/images/logo-chill-outil-accompagnement_white.png') }}">
|
||||
|
||||
{{ include('@ChillMain/Login/_login-logo.html.twig') }}
|
||||
|
||||
{% if error is not null %}
|
||||
<p>{{ error.message|trans }}</p>
|
||||
{% endif %}
|
||||
|
@ -37,7 +37,7 @@
|
||||
<div class="grid-4 hide-tablet hide-mobile parent">
|
||||
<div class="grid-10 push-2 grid-tablet-12 grid-mobile-12 push-tablet-0 grid-mobile-0 logo-container">
|
||||
<a href="{{ path('chill_main_homepage') }}">
|
||||
<img class="logo" src="{{ asset('build/images/logo-chill-sans-slogan_white.png') }}">
|
||||
{{ include('@ChillMain/Layout/_header-logo.html.twig') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -76,7 +76,14 @@ abstract class AbstractSearch implements SearchInterface
|
||||
foreach ($supportedTerms as $term) {
|
||||
if (array_key_exists($term, $terms) && $term !== '_default') {
|
||||
$recomposed .= ' '.$term.':';
|
||||
$containsSpace = \strpos($terms[$term], " ") !== false;
|
||||
if ($containsSpace) {
|
||||
$recomposed .= "(";
|
||||
}
|
||||
$recomposed .= (mb_stristr(' ', $terms[$term]) === FALSE) ? $terms[$term] : '('.$terms[$term].')';
|
||||
if ($containsSpace) {
|
||||
$recomposed .= ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ namespace Chill\MainBundle\Templating;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
use Twig\TwigFilter;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Bridge\Twig\Extension\RoutingExtension;
|
||||
|
||||
@ -42,7 +43,15 @@ class ChillTwigRoutingHelper extends AbstractExtension
|
||||
return [
|
||||
new TwigFunction('chill_return_path_or', [$this, 'getReturnPathOr'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']] ),
|
||||
new TwigFunction('chill_path_add_return_path', [$this, 'getPathAddReturnPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']] ),
|
||||
new TwigFunction('chill_path_forward_return_path', [$this, 'getPathForwardReturnPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']] )
|
||||
new TwigFunction('chill_path_forward_return_path', [$this, 'getPathForwardReturnPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']] ),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('chill_return_path_label', [$this, 'getLabelReturnPath']),
|
||||
];
|
||||
}
|
||||
|
||||
@ -51,6 +60,13 @@ class ChillTwigRoutingHelper extends AbstractExtension
|
||||
return $this->originalExtension->isUrlGenerationSafe($argsNode);
|
||||
}
|
||||
|
||||
public function getLabelReturnPath($default)
|
||||
{
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
|
||||
return $request->query->get('returnPathLabel', null) ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the return path if it exists, or generate the path if not.
|
||||
*
|
||||
@ -78,12 +94,16 @@ class ChillTwigRoutingHelper extends AbstractExtension
|
||||
* @param bool $relative
|
||||
* @return string
|
||||
*/
|
||||
public function getPathAddReturnPath($name, $parameters = [], $relative = false)
|
||||
public function getPathAddReturnPath($name, $parameters = [], $relative = false, $label = null)
|
||||
{
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
|
||||
$parameters['returnPath'] = $request->getRequestUri();
|
||||
|
||||
if ($label) {
|
||||
$parameters['returnPathLabel'] = $label;
|
||||
}
|
||||
|
||||
return $this->originalExtension->getPath($name, $parameters, $relative);
|
||||
}
|
||||
|
||||
|
@ -5,4 +5,4 @@ module.exports = function(encore, entries) {
|
||||
encore.addAliases({
|
||||
ShowHide: __dirname + '/Resources/public/modules/show_hide/'
|
||||
});
|
||||
};
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user