Compare commits

...

18 Commits

Author SHA1 Message Date
7aa63a25a7 Add signature messenger request serialization and processing
This update introduces a new serializer class for request messages (from messenger component). New features-includes encoding and decoding of request messages and handling unexpected value exceptions. A new test class for the serializer and it also adds functionality to process signature requests in the controller.
2024-06-26 10:05:38 +02:00
610239930b Add serialization groups to PDFPage and PDFSignatureZone properties
The Symfony Serializer groups annotation has been added to all properties of the PDFPage and PDFSignatureZone classes. This change allows the serialization and deserialization process to be group-specific, ensuring only relevant data is processed during these operations.
2024-06-25 13:43:48 +02:00
b65e2c62c4 Merge branch 'signature-app/parse-pdf' into 'signature-app-master'
Add PDF signature zone parsing functionality

See merge request Chill-Projet/chill-bundles!703
2024-06-25 11:27:34 +00:00
89f5231649 Refactor PDFSignatureZoneParser to use float values
This update changes how we handle values in PDFSignatureZoneParser class. Specifically, we've modified the 'MediaBox' and 'PDFSignatureZone' variables to use float values. The helps ensure greater precision, minimize errors, and maintain data consistency across the application.
2024-06-25 13:25:49 +02:00
99818c211d Fix cs: upgrade of php-cs-fixer 2024-06-19 12:18:20 +02:00
a9f0059743 Add PDF signature zone parsing functionality
This update introduces new services into the ChillDocStoreBundle for signature zone parsing within PDFs. The PDFSignatureZoneParser service identifies signature zones within PDF content while the additional classes, PDFPage and PDFSignatureZone, help define these zones and pages. Corresponding tests have also been
2024-06-19 12:17:25 +02:00
5bc542a567 remove symfony/phpunit-bridge 2024-06-19 12:16:51 +02:00
c8ccce83fd add a dependency on smalot/pdfparser to parse signature zone within pdf 2024-06-18 17:47:16 +02:00
4a229ebf6b Initial commit 2024-06-14 15:32:51 +02:00
6db36d5ab6 Remove ChillEventBundle and refactor framework.yaml configurations
This commit involves the deletion of ChillEventBundle from the bundles configuration. Additionally, test framework configurations are handled in a consolidated manner by moving assets configurations (json_manifest_path) from test/framework.yaml to framework.yaml. The obsolete test/framework.yaml has been deleted as it is no longer needed.
2024-06-04 21:55:53 +02:00
59f721934e Refactor export download script to use ES6 and webpack
The export download script was refactored to use ES6 syntax and webpack's modular system. This included separating out the download script into its own file for better organization, removing globally-scoped JavaScript, and adding the new download script as a webpack entry point. Also, the import method for the 'mime' library was adjusted to use ES6 syntax.
2024-06-04 21:53:32 +02:00
84ce8a93f3 Refactor ISOToDateTime to handle case when timezone's server is UTC
A condition is added to check if the timezone is set as '0000' (UTC timezone), if yes then a new Date is returned with the Date.UTC method. This ensures that the time returned correctly reflects the current timezone
2024-06-01 00:40:22 +02:00
ab5f2ffb65 add script to run php-cs-fixer 2024-06-01 00:35:36 +02:00
73bae8ccb9 fix indentation 2024-06-01 00:35:26 +02:00
dcfa569e3a Upgrade CKEditor and refactor configuration with use of typescript 2024-06-01 00:35:08 +02:00
4b07fe3622 Update address list import to latest compiled addresses
The import of the address list has been upgraded to use the latest version of the compiled addresses from Belgian-best-address. In the AddressReferenceBEFromBestAddress class, the RELEASE constant has been updated to point to the v1.1.1 tag.
2024-05-30 16:02:35 +02:00
48bf359d2e Restore feature to see chill assets style preview in dev environment
This commit introduces a new dev.assets.html.twig file and updates the chill.yaml file to add new paths for the SASS Assets tests.
2024-05-28 16:34:32 +02:00
60c7ea601c Update form builder parameter in SearchController
Changed the first argument in the `createNamedBuilder` method from `null` to an empty string. This adjustment ensures the form factory correctly creates the builder in the SearchController.
2024-05-28 16:00:03 +02:00
45 changed files with 1078 additions and 75 deletions

View File

@@ -0,0 +1,6 @@
kind: Feature
body: |
Upgrade import of address list to the last version of compiled addresses of belgian-best-address
time: 2024-05-30T16:00:03.440767606+02:00
custom:
Issue: ""

View File

@@ -0,0 +1,6 @@
kind: Feature
body: |
Upgrade CKEditor and refactor configuration with use of typescript
time: 2024-05-31T19:02:42.776662753+02:00
custom:
Issue: ""

View File

@@ -0,0 +1,8 @@
kind: Feature
body: |-
Electronic signature
Implementation of the electronic signature for documents within chill.
time: 2024-06-14T15:32:36.875891692+02:00
custom:
Issue: ""

View File

@@ -32,6 +32,7 @@
"phpoffice/phpspreadsheet": "^1.16",
"ramsey/uuid-doctrine": "^1.7",
"sensio/framework-extra-bundle": "^5.5",
"smalot/pdfparser": "^2.10",
"spomky-labs/base64url": "^2.0",
"symfony/asset": "^5.4",
"symfony/browser-kit": "^5.4",
@@ -97,7 +98,6 @@
"symfony/debug-bundle": "^5.4",
"symfony/dotenv": "^5.4",
"symfony/maker-bundle": "^1.20",
"symfony/phpunit-bridge": "^5.4",
"symfony/runtime": "^5.4",
"symfony/stopwatch": "^5.4",
"symfony/var-dumper": "^5.4"
@@ -149,6 +149,7 @@
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd"
}
},
"php-cs-fixer": "php-cs-fixer fix --config=./.php-cs-fixer.dist.php --show-progress=none"
}
}

View File

@@ -6,15 +6,16 @@
"@apidevtools/swagger-cli": "^4.0.4",
"@babel/core": "^7.20.5",
"@babel/preset-env": "^7.20.2",
"@ckeditor/ckeditor5-build-classic": "^35.3.2",
"@ckeditor/ckeditor5-dev-utils": "^31.1.13",
"@ckeditor/ckeditor5-build-classic": "^41.4.2",
"@ckeditor/ckeditor5-dev-utils": "^40.2.0",
"@ckeditor/ckeditor5-dev-webpack-plugin": "^31.1.13",
"@ckeditor/ckeditor5-markdown-gfm": "^35.3.2",
"@ckeditor/ckeditor5-theme-lark": "^35.3.2",
"@ckeditor/ckeditor5-vue": "^4.0.1",
"@ckeditor/ckeditor5-dev-translations": "^40.2.0",
"@ckeditor/ckeditor5-markdown-gfm": "^41.4.2",
"@ckeditor/ckeditor5-theme-lark": "^41.4.2",
"@ckeditor/ckeditor5-vue": "^5.1.0",
"@symfony/webpack-encore": "^4.1.0",
"@tsconfig/node14": "^1.0.1",
"@types/dompurify": "^3.0.5",
"@types/dompurify": "^3.0.5",
"bindings": "^1.5.0",
"bootstrap": "5.2.3",
"chokidar": "^3.5.1",
@@ -31,7 +32,7 @@
"select2-bootstrap-theme": "0.1.0-beta.10",
"style-loader": "^3.3.1",
"ts-loader": "^9.3.1",
"typescript": "^4.7.2",
"typescript": "^5.4.5",
"vue-loader": "^17.0.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"

View File

@@ -60,7 +60,7 @@ final class TranslatableActivityTypeTest extends KernelTestCase
$this->assertInstanceOf(
ActivityType::class,
$form->getData()['type'],
'The data is an instance of Chill\\ActivityBundle\\Entity\\ActivityType'
'The data is an instance of Chill\ActivityBundle\Entity\ActivityType'
);
$this->assertEquals($type->getId(), $form->getData()['type']->getId());

View File

@@ -37,12 +37,12 @@ class RemoteEventConverter
* valid when the remote string contains also a timezone, like in
* lastModifiedDate.
*/
final public const REMOTE_DATETIMEZONE_FORMAT = 'Y-m-d\\TH:i:s.u?P';
final public const REMOTE_DATETIMEZONE_FORMAT = 'Y-m-d\TH:i:s.u?P';
/**
* Same as above, but sometimes the date is expressed with only 6 milliseconds.
*/
final public const REMOTE_DATETIMEZONE_FORMAT_ALT = 'Y-m-d\\TH:i:s.uP';
final public const REMOTE_DATETIMEZONE_FORMAT_ALT = 'Y-m-d\TH:i:s.uP';
private const REMOTE_DATE_FORMAT = 'Y-m-d\TH:i:s.u0';

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner\RequestPdfSignMessage;
use Chill\DocStoreBundle\Service\Signature\PDFPage;
use Chill\DocStoreBundle\Service\Signature\PDFSignatureZone;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
class SignatureRequestController
{
public function __construct(
private MessageBusInterface $messageBus,
private StoredObjectManagerInterface $storedObjectManager,
) {}
#[Route('/api/1.0/document/workflow/{id}/signature-request', name: 'chill_docstore_signature_request')]
public function processSignature(StoredObject $storedObject): Response
{
$content = $this->storedObjectManager->read($storedObject);
$this->messageBus->dispatch(new RequestPdfSignMessage(
0,
new PDFSignatureZone(10.0, 10.0, 180.0, 180.0, new PDFPage(0, 500.0, 800.0)),
0,
'test signature',
$content
));
return new Response('<html><head><title>test</title></head><body><p>ok</p></body></html>');
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner;
use Chill\DocStoreBundle\Service\Signature\PDFSignatureZone;
final readonly class RequestPdfSignMessage
{
public function __construct(
public int $signatureId,
public PDFSignatureZone $PDFSignatureZone,
public int $signatureZoneIndex,
public string $reason,
public string $content,
) {}
}

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner;
use Chill\DocStoreBundle\Service\Signature\PDFSignatureZone;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
final readonly class RequestPdfSignMessageSerializer implements SerializerInterface
{
public function __construct(
private NormalizerInterface $normalizer,
private DenormalizerInterface $denormalizer,
) {}
public function decode(array $encodedEnvelope): Envelope
{
$body = $encodedEnvelope['body'];
$headers = $encodedEnvelope['headers'];
if (RequestPdfSignMessage::class !== ($headers['Message'] ?? null)) {
throw new MessageDecodingFailedException('serializer does not support this message');
}
$data = json_decode($body, true);
$zoneSignature = $this->denormalizer->denormalize($data['signatureZone'], PDFSignatureZone::class, 'json', [
AbstractNormalizer::GROUPS => ['write'],
]);
$message = new RequestPdfSignMessage(
$data['signatureId'],
$zoneSignature,
$data['signatureZoneIndex'],
$data['reason'],
base64_decode($data['content']),
);
// in case of redelivery, unserialize any stamps
$stamps = [];
if (isset($headers['stamps'])) {
$stamps = unserialize($headers['stamps']);
}
return new Envelope($message, $stamps);
}
public function encode(Envelope $envelope): array
{
$message = $envelope->getMessage();
if (!$message instanceof RequestPdfSignMessage) {
throw new MessageDecodingFailedException('Message is not a RequestPdfSignMessage');
}
$data = [
'signatureId' => $message->signatureId,
'signatureZoneIndex' => $message->signatureZoneIndex,
'signatureZone' => $this->normalizer->normalize($message->PDFSignatureZone, 'json', [AbstractNormalizer::GROUPS => ['read']]),
'reason' => $message->reason,
'content' => base64_encode($message->content),
];
$allStamps = [];
foreach ($envelope->all() as $stamp) {
if ($stamp instanceof NonSendableStampInterface) {
continue;
}
$allStamps = [...$allStamps, ...$stamp];
}
return [
'body' => json_encode($data, JSON_THROW_ON_ERROR, 512),
'headers' => [
'stamps' => serialize($allStamps),
'Message' => RequestPdfSignMessage::class,
],
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service\Signature;
use Symfony\Component\Serializer\Annotation\Groups;
final readonly class PDFPage
{
public function __construct(
#[Groups(['read'])]
public int $index,
#[Groups(['read'])]
public float $width,
#[Groups(['read'])]
public float $height,
) {}
public function equals(self $page): bool
{
return $page->index === $this->index
&& round($page->width, 2) === round($this->width, 2)
&& round($page->height, 2) === round($this->height, 2);
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service\Signature;
use Symfony\Component\Serializer\Annotation\Groups;
final readonly class PDFSignatureZone
{
public function __construct(
#[Groups(['read'])]
public float $x,
#[Groups(['read'])]
public float $y,
#[Groups(['read'])]
public float $height,
#[Groups(['read'])]
public float $width,
#[Groups(['read'])]
public PDFPage $PDFPage,
) {}
public function equals(self $other): bool
{
return
$this->x == $other->x
&& $this->y == $other->y
&& $this->height == $other->height
&& $this->width == $other->width
&& $this->PDFPage->equals($other->PDFPage);
}
}

View File

@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service\Signature;
use Smalot\PdfParser\Parser;
class PDFSignatureZoneParser
{
public const ZONE_SIGNATURE_START = 'signature_zone';
private Parser $parser;
public function __construct(
public float $defaultHeight = 180.0,
public float $defaultWidth = 180.0,
) {
$this->parser = new Parser();
}
/**
* @return list<PDFSignatureZone>
*/
public function findSignatureZones(string $fileContent): array
{
$pdf = $this->parser->parseContent($fileContent);
$zones = [];
$defaults = $pdf->getObjectsByType('Pages');
$defaultPage = reset($defaults);
$defaultPageDetails = $defaultPage->getDetails();
foreach ($pdf->getPages() as $index => $page) {
$details = $page->getDetails();
$pdfPage = new PDFPage(
$index,
(float) ($details['MediaBox'][2] ?? $defaultPageDetails['MediaBox'][2]),
(float) ($details['MediaBox'][3] ?? $defaultPageDetails['MediaBox'][3]),
);
foreach ($page->getDataTm() as $dataTm) {
if (str_starts_with($dataTm[1], self::ZONE_SIGNATURE_START)) {
$zones[] = new PDFSignatureZone((float) $dataTm[0][4], (float) $dataTm[0][5], $this->defaultHeight, $this->defaultWidth, $pdfPage);
}
}
}
return $zones;
}
}

View File

@@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Tests\Service\Signature\Driver\BaseSigner;
use Chill\DocStoreBundle\Service\Signature\PDFPage;
use Chill\DocStoreBundle\Service\Signature\PDFSignatureZone;
use Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner\RequestPdfSignMessage;
use Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner\RequestPdfSignMessageSerializer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Serializer;
/**
* @internal
*
* @coversNothing
*/
class RequestPdfSignMessageSerializerTest extends TestCase
{
public function testEncode(): void
{
$serializer = $this->buildSerializer();
$envelope = new Envelope(
$request = new RequestPdfSignMessage(
0,
new PDFSignatureZone(10.0, 10.0, 180.0, 180.0, new PDFPage(0, 500.0, 800.0)),
0,
'metadata to add to the signature',
'abc'
),
);
$actual = $serializer->encode($envelope);
$expectedBody = json_encode([
'signatureId' => $request->signatureId,
'signatureZoneIndex' => $request->signatureZoneIndex,
'signatureZone' => ['x' => 10.0],
'reason' => $request->reason,
'content' => base64_encode($request->content),
]);
self::assertIsArray($actual);
self::assertArrayHasKey('body', $actual);
self::assertArrayHasKey('headers', $actual);
self::assertEquals($expectedBody, $actual['body']);
}
public function testDecode(): void
{
$serializer = $this->buildSerializer();
$request = new RequestPdfSignMessage(
0,
new PDFSignatureZone(10.0, 10.0, 180.0, 180.0, new PDFPage(0, 500.0, 800.0)),
0,
'metadata to add to the signature',
'abc'
);
$bodyAsString = json_encode([
'signatureId' => $request->signatureId,
'signatureZoneIndex' => $request->signatureZoneIndex,
'signatureZone' => ['x' => 10.0],
'reason' => $request->reason,
'content' => base64_encode($request->content),
], JSON_THROW_ON_ERROR);
$actual = $serializer->decode([
'body' => $bodyAsString,
'headers' => [
'Message' => RequestPdfSignMessage::class,
],
]);
self::assertInstanceOf(RequestPdfSignMessage::class, $actual->getMessage());
self::assertEquals($request->signatureId, $actual->getMessage()->signatureId);
self::assertEquals($request->signatureZoneIndex, $actual->getMessage()->signatureZoneIndex);
self::assertEquals($request->reason, $actual->getMessage()->reason);
self::assertEquals($request->content, $actual->getMessage()->content);
self::assertNotNull($actual->getMessage()->PDFSignatureZone);
}
private function buildSerializer(): RequestPdfSignMessageSerializer
{
$normalizer =
new class () implements NormalizerInterface {
public function normalize($object, ?string $format = null, array $context = []): array
{
if (!$object instanceof PDFSignatureZone) {
throw new UnexpectedValueException('expected RequestPdfSignMessage');
}
return [
'x' => $object->x,
];
}
public function supportsNormalization($data, ?string $format = null): bool
{
return $data instanceof PDFSignatureZone;
}
};
$denormalizer = new class () implements DenormalizerInterface {
public function denormalize($data, string $type, ?string $format = null, array $context = [])
{
return new PDFSignatureZone(10.0, 10.0, 180.0, 180.0, new PDFPage(0, 500.0, 800.0));
}
public function supportsDenormalization($data, string $type, ?string $format = null)
{
return PDFSignatureZone::class === $type;
}
};
$serializer = new Serializer([$normalizer, $denormalizer]);
return new RequestPdfSignMessageSerializer($serializer, $serializer);
}
}

View File

@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Tests\Service\Signature;
use Chill\DocStoreBundle\Service\Signature\PDFPage;
use PHPUnit\Framework\TestCase;
use Chill\DocStoreBundle\Service\Signature\PDFSignatureZone;
use Chill\DocStoreBundle\Service\Signature\PDFSignatureZoneParser;
/**
* @internal
*
* @coversNothing
*/
class PDFSignatureZoneParserTest extends TestCase
{
private static PDFSignatureZoneParser $parser;
public static function setUpBeforeClass(): void
{
self::$parser = new PDFSignatureZoneParser();
}
/**
* @dataProvider provideFiles
*
* @param list<PDFSignatureZone> $expected
*/
public function testFindSignatureZones(string $filePath, array $expected): void
{
$content = file_get_contents($filePath);
if (false === $content) {
throw new \LogicException("Unable to read file {$filePath}");
}
$actual = self::$parser->findSignatureZones($content);
self::assertEquals(count($expected), count($actual));
foreach ($actual as $index => $signatureZone) {
self::assertObjectEquals($expected[$index], $signatureZone);
}
}
public static function provideFiles(): iterable
{
yield [
__DIR__.'/data/signature_2_signature_page_1.pdf',
[
new PDFSignatureZone(
127.7,
95.289,
180.0,
180.0,
$page = new PDFPage(0, 595.30393, 841.8897)
),
new PDFSignatureZone(
269.5,
95.289,
180.0,
180.0,
$page,
),
],
];
}
}

View File

@@ -211,7 +211,7 @@ class SearchController extends AbstractController
$builder = $this
->get('form.factory')
->createNamedBuilder(
null,
'',
FormType::class,
$data,
['method' => Request::METHOD_POST]

View File

@@ -43,7 +43,7 @@ class ShortMessageCompilerPass implements CompilerPassInterface
$defaultTransporter = new Reference(NullShortMessageSender::class);
} elseif ('ovh' === $dsn['scheme']) {
if (!class_exists('\\'.\Ovh\Api::class)) {
throw new RuntimeException('Class \\Ovh\\Api not found');
throw new RuntimeException('Class \Ovh\Api not found');
}
foreach (['user', 'host', 'pass'] as $component) {

View File

@@ -190,7 +190,7 @@ class ExportManager
// throw an error if the export require other modifier, which is
// not allowed when the export return a `NativeQuery`
if (\count($export->supportsModifiers()) > 0) {
throw new \LogicException("The export with alias `{$exportAlias}` return ".'a `\\Doctrine\\ORM\\NativeQuery` and supports modifiers, which is not allowed. Either the method `supportsModifiers` should return an empty array, or return a `Doctrine\\ORM\\QueryBuilder`');
throw new \LogicException("The export with alias `{$exportAlias}` return ".'a `\Doctrine\ORM\NativeQuery` and supports modifiers, which is not allowed. Either the method `supportsModifiers` should return an empty array, or return a `Doctrine\ORM\QueryBuilder`');
}
} elseif ($query instanceof QueryBuilder) {
// handle filters
@@ -203,7 +203,7 @@ class ExportManager
'dql' => $query->getDQL(),
]);
} else {
throw new \UnexpectedValueException('The method `intiateQuery` should return a `\\Doctrine\\ORM\\NativeQuery` or a `Doctrine\\ORM\\QueryBuilder` object.');
throw new \UnexpectedValueException('The method `intiateQuery` should return a `\Doctrine\ORM\NativeQuery` or a `Doctrine\ORM\QueryBuilder` object.');
}
$result = $export->getResult($query, $data[ExportType::EXPORT_KEY]);

View File

@@ -59,6 +59,10 @@ export const ISOToDatetime = (str: string|null): Date|null => {
[hours, minutes, seconds] = time.split(':').map(s => parseInt(s));
;
if ('0000' === timezone) {
return new Date(Date.UTC(year, month-1, date, hours, minutes, seconds));
}
return new Date(year, month-1, date, hours, minutes, seconds);
}

View File

@@ -15,9 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var mime = require('mime')
import mime from 'mime';
var download_report = (url, container) => {
export const download_report = (url, container) => {
var download_text = container.dataset.downloadText,
alias = container.dataset.alias;
@@ -63,5 +63,3 @@ var download_report = (url, container) => {
.replaceChild(problem_text, container.firstChild);
});
};
module.exports = download_report;

View File

@@ -39,23 +39,5 @@ ClassicEditor.defaultConfig = {
'redo'
]
},
language: 'fr'
language: 'fr',
};
let Fields = [];
Fields.push.apply(Fields, document.querySelectorAll('textarea[ckeditor]'));
// enable for custom fields
//Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));
Fields.forEach(function(field) {
ClassicEditor
.create( field )
.then( editor => {
//console.log( 'CkEditor was initialized', editor );
})
.catch( error => {
console.error( error.stack );
})
;
});

View File

@@ -0,0 +1,15 @@
import ClassicEditor from "./editor_config";
const ckeditorFields: NodeListOf<HTMLTextAreaElement> = document.querySelectorAll('textarea[ckeditor]');
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
ClassicEditor
.create( field )
.then( editor => {
//console.log( 'CkEditor was initialized', editor );
})
.catch( error => {
console.error( error.stack );
})
;
});
//Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));

View File

@@ -0,0 +1,16 @@
import {download_report} from "../../lib/download-report/download-report";
window.addEventListener("DOMContentLoaded", function(e) {
const export_generate_url = window.export_generate_url;
if (typeof export_generate_url === 'undefined') {
console.error('Alias not found!');
throw new Error('Alias not found!');
}
const query = window.location.search,
container = document.querySelector("#download_container")
;
download_report(export_generate_url + "?" + query.toString(), container);
});

View File

@@ -0,0 +1,306 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}
SASS Assets Catalogue
{% endblock %}
{% block css %}
<style media="screen">
h2 { margin: 1.5em 0; }
div.flex-table ul, div.flex-bloc ul { padding-left: 1rem; }
div.flex-table div.item-bloc div.item-row div.item-col:first-child { flex-basis: 20%; }
div.flex-bloc div.item-bloc { flex-basis: 50%; }
</style>
{% endblock %}
{% block content %}
<div class="col-md-10">
<h1 class="display-4">{{ block('title') }}</h1>
<b>Voir aussi: </b>
<a href="{{ path('sass_assets_test1') }}">Test 1</a> |
<a href="{{ path('sass_assets_test2') }}">Test 2</a>
<h2>Flex-table et flex-bloc</h2>
<p>Base d'un placement flex alternatif à l'usage des tables.
Flex-table et flex-bloc utilisent la même structure html (seul la root class change).
Le placement est responsive.
La bordure utilise box-shadow pour simuler border-collapse (table).
</p>
<p>Une classe separator peut être appliquée sur item-row</p>
<xmp>
<div class="flex-table">
<div class="item-bloc">
<div class="item-row">
<div class="item-col"></div>
<div class="item-col"></div>
</div>
<div class="item-row separator">
<div class="item-col"></div>
<div class="item-col"></div>
</div>
</div>
<div class="item-bloc">
<div class="item-row">
<div class="item-col"></div>
<div class="item-col"></div>
</div>
<div class="item-row">
<div class="item-col"></div>
<div class="item-col"></div>
</div>
</div>
</div>
</xmp>
<h3>Flex-table</h3>
<p>On fixe manuellement la largeur de la première colonne :
<pre>div.flex-table div.item-bloc div.item-row div.item-col:first-child { flex-basis: 20%; }</pre>
</p>
<div class="flex-table debug">
<div class="item-bloc">
<div class="item-row">
<div class="item-col">Title row1</div>
<div class="item-col">
<ul class="list-content">
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
</ul>
</div>
</div>
<div class="item-row separator">
<div class="item-col">Title row2</div>
<div class="item-col">Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</div>
</div>
<div class="item-row">
<div class="item-col">Title row3</div>
<div class="item-col">Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</div>
</div>
</div>
<div class="item-bloc">
<div class="item-row">
<div class="item-col">Title row1</div>
<div class="item-col">
<ul class="list-content">
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
</ul>
</div>
</div>
<div class="item-row">
<div class="item-col">Title row2</div>
<div class="item-col">Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</div>
</div>
</div>
</div>
<h3>Flex-bloc</h3>
<p>On fixe manuellement la largeur des blocs :
<pre>div.flex-bloc div.item-bloc { flex-basis: 50%; }</pre>
</p>
<div class="flex-bloc debug">
<div class="item-bloc">
<div class="item-row">
<div class="item-col">Title row1</div>
<div class="item-col">
<ul class="list-content">
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
</ul>
</div>
</div>
<div class="item-row separator">
<div class="item-col">Title row2</div>
<div class="item-col">Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</div>
</div>
<div class="item-row">
<div class="item-col">Title row3</div>
<div class="item-col">Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</div>
</div>
</div>
<div class="item-bloc">
<div class="item-row">
<div class="item-col">Title row1</div>
<div class="item-col">
<ul class="list-content">
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
<li>Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</li>
</ul>
</div>
</div>
<div class="item-row">
<div class="item-col">Title row2</div>
<div class="item-col">Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac viverra et a dui.</div>
</div>
</div>
</div>
<h2>Wrap-list</h2>
<p>Une liste inline qui s'aligne, puis glisse sous son titre.</p>
<div class="wrap-list debug">
<div class="wl-row">
<div class="wl-col title">Usagers concernés</div>
<div class="wl-col list">
<p class="wl-item"><a href="#">Gaston Bah</a></p>
<p class="wl-item"><a href="#">Alain Bah</a></p>
<p class="wl-item"><a href="#">Adèle Gaillot</a></p>
<p class="wl-item"><a href="#">Corentine Bah</a></p>
<p class="wl-item"><a href="#">Justin Bah</a></p>
<p class="wl-item"><a href="#">Michel Sardou</a></p>
<p class="wl-item"><a href="#">Carine Rousseau</a></p>
<p class="wl-item"><a href="#">Mohamed Martin</a></p>
</div>
</div>
<div class="wl-row">
<div class="wl-col title">Problématiques sociales</div>
<div class="wl-col list">
<p class="wl-item"><a href="#">Gaston Bah</a></p>
<p class="wl-item"><a href="#">Alain Bah</a></p>
<p class="wl-item"><a href="#">Adèle Gaillot</a></p>
</div>
</div>
</div>
<xmp>
<div class="wrap-list">
<div class="wl-row">
<div class="wl-col title">title</div>
<div class="wl-col list">
<p class="wl-item">item</p>
<p class="wl-item">item</p>
...
</div>
</div>
...
</div>
</xmp>
<h2>Wrap-header</h2>
<p>Réglage d'une zone de titre sur 2 lignes.</p>
<div class="wrap-header debug">
<div class="wh-row">
<div class="wh-col">
<span class="h3"><b>Title</b></span>
<span class="badge rounded-pill bg-danger">badge</span>
</div>
<div class="wh-col">
<span class="badge rounded-pill bg-primary">badge</span>
</div>
</div>
<div class="wh-row">
<div class="wh-col">from startdate to enddate</div>
<div class="wh-col">text</div>
</div>
</div>
<xmp>
<div class="wrap-header">
<div class="wh-row">
<div class="wh-col">line1 left</div>
<div class="wh-col">line1 right</div>
</div>
<div class="wh-row">
<div class="wh-col">line2 left</div>
<div class="wh-col">line2 right</div>
</div>
</div>
</xmp>
<h2>Float-button top</h2>
<p>Une zone de bouton flotte à droite d'un contenu. On peut voir en faisant varier la largeur que celui-ci vient s'adapter harmonieusement autour des boutons.</p>
<div class="float-button top debug">
<div class="box">
<div class="action">
<ul class="record_actions">
<li><button type="button" name="button">Annuler</button></li>
<li><button type="button" name="button">Voir</button></li>
<li><button type="button" name="button">Enregistrer</button></li>
</ul>
</div>
Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac. Proin fermentum mauris quam, ut suscipit nisl auctor at. Ut vestibulum ligula eget ex congue, efficitur interdum ipsum tincidunt. Integer id sapien et nibh tristique viverra et a dui. Ut blandit pharetra consectetur. Sed scelerisque eget purus at tempus. Etiam sit amet tellus et eros semper tempor. Curabitur suscipit pulvinar enim at lobortis. Ut nisl augue, cursus vel hendrerit sed, posuere vel sapien. Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan. In vitae tristique leo, a fringilla nisl.
</div>
</div>
<xmp>
<div class="float-button top">
<div class="box">
<div class="action">
floating button
</div>
content ...
</div>
</div>
</xmp>
<h2>Float-button bottom</h2>
<p>Avec la même structure, on accroche la zone de bouton en bas, toujours à droite. Voir <a href="https://css-tricks.com/float-an-element-to-the-bottom-corner/">source</a>. </p>
<div class="float-button bottom debug">
<div class="box">
<div class="action">
<ul class="record_actions">
<li><button type="button" name="button">Annuler</button></li>
<li><button type="button" name="button">Voir</button></li>
<li><button type="button" name="button">Enregistrer</button></li>
</ul>
</div>
Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac. Proin fermentum mauris quam, ut suscipit nisl auctor at. Ut vestibulum ligula eget ex congue, efficitur interdum ipsum tincidunt. Integer id sapien et nibh tristique viverra et a dui. Ut blandit pharetra consectetur. Sed scelerisque eget purus at tempus. Etiam sit amet tellus et eros semper tempor. Curabitur suscipit pulvinar enim at lobortis. Ut nisl augue, cursus vel hendrerit sed, posuere vel sapien. Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan. In vitae tristique leo, a fringilla nisl.
</div>
</div>
<xmp>
<div class="float-button bottom">
<div class="box">
<div class="action">
floating button
</div>
content ...
</div>
</div>
</xmp>
<h1>Buttons</h1>
<ul class="record_actions">
<li><a href="#" class="btn btn-submit">submit</a></li>
<li><a href="#" class="btn btn-save">save</a></li>
<li><a href="#" class="btn btn-create">create</a></li>
<li><a href="#" class="btn btn-new">new</a></li>
<li><a href="#" class="btn btn-duplicate">duplicate</a></li>
<li><a href="#" class="btn btn-not-duplicate">not-duplicate</a></li>
<li><a href="#" class="btn btn-reset">reset</a></li>
<li><a href="#" class="btn btn-delete">delete</a></li>
<li><a href="#" class="btn btn-danger">danger</a></li>
<li><a href="#" class="btn btn-remove">remove</a></li>
<li><a href="#" class="btn btn-unlink">unlink</a></li>
<li><a href="#" class="btn btn-action">action</a></li>
<li><a href="#" class="btn btn-edit">edit</a></li>
<li><a href="#" class="btn btn-update">update</a></li>
<li><a href="#" class="btn btn-show">show</a></li>
<li><a href="#" class="btn btn-view">view</a></li>
<li><a href="#" class="btn btn-misc">misc</a></li>
<li><a href="#" class="btn btn-cancel">cancel</a></li>
<li><a href="#" class="btn btn-choose">choose</a></li>
<li><a href="#" class="btn btn-notify">notify</a></li>
<li><a href="#" class="btn btn-tpchild">tpchild</a></li>
<li><a href="#" class="btn btn-chill-beige">my button</a></li>
</ul>
<h2>Variants of <pre>record_actions</pre></h2>
<h3><pre>small</pre></h3>
<ul class="record_actions small">
<li><a href="#" class="btn btn-create"></a></li>
</ul>
<h3><pre>inline</pre></h3>
<div>
This is inline and small
<ul class="record_actions small inline">
<li><a href="#" class="btn btn-create"></a></li>
</ul>
</div>
<xmp><a class="btn btn-submit">Text</a></xmp>
Toutes les classes btn-* de bootstrap sont fonctionnelles
</div>
{% endblock %}

View File

@@ -0,0 +1,84 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}
SASS Assets Tests - page 1
{% endblock %}
{% block css %}
<style media="screen">
</style>
{% endblock %}
{% block content %}
<div class="col-md-8">
<h1>CSS Tests - page 1 : float-button</h1>
<h2>1) avec des li</h2>
<div class="float-button bottom debug">
<div class="box">
<div class="action">
<ul class="record_actions">
<li><button type="button" name="button">Annuler</button></li>
<li><button type="button" name="button">Voir</button></li>
<li><button type="button" name="button">Enregistrer</button></li>
</ul>
</div>
<ul class="list-content fa-ul">
<li><i class="fa fa-li fa-file-text-o"></i>Sed efficitur magna vel massa efficitur venenatis. Sed odio massa, scelerisque sit amet mauris eu, tristique dictum arcu. Sed posuere, elit eget cursus rhoncus, arcu ligula blandit nisi, in vulputate eros massa non risus.</li>
<li><i class="fa fa-li fa-map-marker"></i>
<div class="chill-entity entity-address my-3" data-v-8b2170ec="">
<div class="address multiline" data-v-8b2170ec="">
<p class="street" data-v-8b2170ec="">97, chemin Franck Julien, </p>
<p class="postcode" data-v-8b2170ec="">1000 Bruxelles</p>
<p class="country" data-v-8b2170ec="">Belgique</p>
</div>
<div class="address-more" data-v-8b2170ec="">
<div data-v-8b2170ec="">
<span class="corridor" data-v-8b2170ec="">
<b data-v-8b2170ec="">Couloir</b>: 3
</span>
</div>
</div>
</div>
</li>
<li><i class="fa fa-li fa-mobile"></i><a href="tel: +33 8 27 17 12 19">+33 8 27 17 12 19</a></li>
<li><i class="fa fa-li fa-envelope-o"></i><a href="mailto: gusikowski.yesenia@hotmail.com">gusikowski.yesenia@hotmail.com</a></li>
</ul>
</div>
</div>
<h2>2) avec des p</h2>
<div class="float-button bottom debug">
<div class="box">
<div class="action">
<ul class="record_actions">
<li><button type="button" name="button">Annuler</button></li>
<li><button type="button" name="button">Voir</button></li>
<li><button type="button" name="button">Enregistrer</button></li>
</ul>
</div>
<p>Voir <a href="https://css-tricks.com/float-an-element-to-the-bottom-corner/">trick</a>.</p>
<p>Sed efficitur magna vel massa efficitur venenatis. Sed odio massa, scelerisque sit amet mauris eu, tristique dictum arcu. Sed posuere, elit eget cursus rhoncus, arcu ligula blandit nisi, in vulputate eros massa non risus. Proin lacinia, sapien in pharetra ultricies, justo urna fermentum lectus, non tempor ipsum leo a ante. Aenean porta, ipsum in fringilla hendrerit, nisi justo vestibulum ex, non lacinia risus felis vitae diam. Curabitur sem eros, consectetur a auctor vel, facilisis sit amet sem.</p>
<p>Aenean finibus a nisl a scelerisque. Donec bibendum facilisis odio id euismod. Pellentesque luctus justo ligula, eget dictum ligula ultrices quis. Pellentesque at nunc est. Aenean luctus, tortor in lacinia porta, ex nisl dignissim magna, non vehicula elit risus at elit. Suspendisse in velit non augue egestas laoreet. Etiam blandit lacus at semper aliquam. Integer leo nunc, condimentum sagittis accumsan sit amet, consectetur vel massa. Aenean convallis nibh vel augue ullamcorper tempus. Integer eu laoreet sapien.</p>
</div>
</div>
<h2>3) avec des div</h2>
<div class="float-button bottom debug">
<div class="box">
<div class="action">
<ul class="record_actions">
<li><button type="button" name="button">Annuler</button></li>
<li><button type="button" name="button">Voir</button></li>
<li><button type="button" name="button">Enregistrer</button></li>
</ul>
</div>
<div>Voir <a href="https://css-tricks.com/float-an-element-to-the-bottom-corner/">trick</a>.</div>
<div>Sed efficitur magna vel massa efficitur venenatis. Sed odio massa, scelerisque sit amet mauris eu, tristique dictum arcu. Sed posuere, elit eget cursus rhoncus, arcu ligula blandit nisi, in vulputate eros massa non risus. Proin lacinia, sapien in pharetra ultricies, justo urna fermentum lectus, non tempor ipsum leo a ante. Aenean porta, ipsum in fringilla hendrerit, nisi justo vestibulum ex, non lacinia risus felis vitae diam.
<a href="#">Curabitur</a> sem eros, consectetur a auctor vel, facilisis sit amet sem.</div>
<div>Aenean finibus a nisl a scelerisque. Donec bibendum facilisis odio id euismod. Pellentesque luctus justo ligula, eget dictum ligula ultrices quis. Pellentesque at nunc est. Aenean luctus, tortor in lacinia porta, ex nisl dignissim magna, non vehicula elit risus at elit. Suspendisse in velit non augue egestas laoreet. Etiam blandit lacus at semper aliquam. Integer leo nunc, condimentum sagittis accumsan sit amet, consectetur vel massa. Aenean convallis nibh vel augue ullamcorper tempus. Integer eu laoreet sapien.</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,78 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}
SASS Assets Tests - page 2
{% endblock %}
{% block css %}
{% endblock %}
{% block content %}
<div class="col-md-10">
<h1>CSS Tests - page 2: grid layout</h1>
<h2>1) mgrid 1-2: avec grid-column et grid-row</h2>
<div class="mgrid debug">
<div class="area1">
Nam rhoncus tristique ligula, tincidunt iaculis augue tincidunt ac. Proin fermentum mauris quam, ut suscipit nisl auctor at. Ut vestibulum ligula eget ex congue, efficitur interdum ipsum tincidunt. Integer id sapien et nibh tristique viverra et a dui. Ut blandit pharetra consectetur. Sed scelerisque eget purus at tempus. Etiam sit amet tellus et eros semper tempor. Curabitur suscipit pulvinar enim at lobortis. Ut nisl augue, cursus vel hendrerit sed, posuere vel sapien. Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan. In vitae tristique leo, a fringilla nisl.
</div>
<div class="area2">
<ul class="record_actions">
<li><button type="button" name="button">Annuler</button></li>
<li><button type="button" name="button">Voir</button></li>
<li><button type="button" name="button">Enregistrer</button></li>
</ul>
</div>
</div>
<h2>2) lgrid 3-4: avec grid-template-areas</h2>
<div class="lgrid debug">
<div class="area3">
<i>La zone qu'on crée avec les noms doit être rectangulaires. Actuellement, il n'existe pas de méthode pour créer une zone avec une forme de L (bien que la spécification indique qu'une prochaine version pourrait couvrir cette fonctionnalité).
[...] Si des zones ne sont pas rectangulaires, cela sera également considéré comme invalide.</i>
Voir sur MDN: <a target="_blank" href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Grid_Layout/Grid_Template_Areas#occuper_plusieurs_cellules">Définir des zones sur une grille</a>
</div>
<div class="area4">
<ul class="record_actions">
<li><button type="button" name="button">Annuler</button></li>
<li><button type="button" name="button">Voir</button></li>
<li><button type="button" name="button">Enregistrer</button></li>
</ul>
</div>
</div>
<h2>3) cgrid 5-6-7-8: avec masonry</h2>
<p>Expérimental: dans FF <i>about:config</i>, il faut mettre <i>layout.css.grid-template-masonry-value.enabled = true</i></p>
<div class="cgrid debug">
<div class="item">
1 Integer id sapien et nibh tristique viverra et a dui. Ut blandit pharetra consectetur. Sed scelerisque eget purus at tempus. Etiam sit amet tellus et eros semper tempor. Curabitur suscipit pulvinar enim at lobortis. Ut nisl augue, cursus vel hendrerit sed, posuere vel sapien. Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan. In vitae tristique leo, a fringilla nisl.
</div>
<div class="item">
2 Sed scelerisque eget purus at tempus. Etiam sit amet tellus et eros semper tempor. Curabitur suscipit pulvinar enim at lobortis. Ut nisl augue, cursus vel hendrerit sed, posuere vel sapien. Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan. In vitae tristique leo, a fringilla nisl.
</div>
<div class="item">
3 Curabitur suscipit pulvinar enim at lobortis. Ut nisl augue, cursus vel hendrerit sed, posuere vel sapien. Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan. In vitae tristique leo, a fringilla nisl.
</div>
<div class="item">
4 Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan. In vitae tristique leo, a fringilla nisl.
</div>
<div class="item">
5 Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim a accumsan.
</div>
<div class="item">
6 Proin hendrerit arcu velit, eu ultrices dui interdum eget. Vestibulum consectetur sodales enim.
</div>
<div class="item">
7 Proin hendrerit arcu velit, eu ultrices dui interdum eget.
</div>
<div class="item">
8 Eu ultrices dui interdum eget.
</div>
</div>
</div>
{% endblock %}

View File

@@ -22,15 +22,13 @@
{% block js %}
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function(e) {
var url = "{{ path('chill_main_export_generate', { 'alias' : alias } ) }}",
query = window.location.search,
container = document.querySelector("#download_container")
;
chill.download_report(url+query, container);
});
window.export_generate_url = "{{ path('chill_main_export_generate', { 'alias' : alias } ) }}";
</script>
{{ encore_entry_link_tags('page_download_exports') }}
{% endblock %}
{% block css %}
{{ encore_entry_script_tags('page_download_exports') }}
{% endblock %}
{% block content %}

View File

@@ -14,9 +14,9 @@ namespace Chill\MainBundle\Search\Utils;
class ExtractDateFromPattern
{
private const DATE_PATTERN = [
['([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))', 'Y-m-d'], // 1981-05-12
['((0[1-9]|[12]\\d|3[01])\\/(0[1-9]|1[0-2])\\/([12]\\d{3}))', 'd/m/Y'], // 15/12/1980
['((0[1-9]|[12]\\d|3[01])-(0[1-9]|1[0-2])-([12]\\d{3}))', 'd-m-Y'], // 15/12/1980
['([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))', 'Y-m-d'], // 1981-05-12
['((0[1-9]|[12]\d|3[01])\/(0[1-9]|1[0-2])\/([12]\d{3}))', 'd/m/Y'], // 15/12/1980
['((0[1-9]|[12]\d|3[01])-(0[1-9]|1[0-2])-([12]\d{3}))', 'd-m-Y'], // 15/12/1980
];
public function extractDates(string $subject): SearchExtractionResult

View File

@@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class ExtractPhonenumberFromPattern
{
private const PATTERN = '([\\+]{0,1}[0-9\\ ]{5,})';
private const PATTERN = '([\+]{0,1}[0-9\ ]{5,})';
private readonly string $defaultCarrierCode;

View File

@@ -18,7 +18,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
class AddressReferenceBEFromBestAddress
{
private const RELEASE = 'https://gitea.champs-libres.be/api/v1/repos/Chill-project/belgian-bestaddresses-transform/releases/tags/v1.0.0';
private const RELEASE = 'https://gitea.champs-libres.be/api/v1/repos/Chill-project/belgian-bestaddresses-transform/releases/tags/v1.1.1';
public function __construct(private readonly HttpClientInterface $client, private readonly AddressReferenceBaseImporter $baseImporter, private readonly AddressToReferenceMatcher $addressToReferenceMatcher) {}

View File

@@ -1,10 +1,10 @@
const CKEditorWebpackPlugin = require( '@ckeditor/ckeditor5-dev-webpack-plugin' );
const { styles } = require( '@ckeditor/ckeditor5-dev-utils' );
const {CKEditorTranslationsPlugin} = require("@ckeditor/ckeditor5-dev-translations");
buildCKEditor = function(encore)
{
encore
.addPlugin( new CKEditorWebpackPlugin( {
.addPlugin( new CKEditorTranslationsPlugin( {
language: 'fr',
addMainLanguageTranslationsToAllAssets: true,
verbose: !encore.isProduction(),
@@ -52,12 +52,14 @@ module.exports = function(encore, entries)
Tabs: __dirname + '/Resources/public/lib/tabs'
});
// Page entrypoints
encore.addEntry('page_login', __dirname + '/Resources/public/page/login/index.js');
encore.addEntry('page_location', __dirname + '/Resources/public/page/location/index.js');
encore.addEntry('page_workflow_show', __dirname + '/Resources/public/page/workflow-show/index.js');
encore.addEntry('page_homepage_widget', __dirname + '/Resources/public/page/homepage_widget/index.js');
encore.addEntry('page_export', __dirname + '/Resources/public/page/export/index.js');
encore.addEntry('page_download_exports', __dirname + '/Resources/public/page/export/download-export.js');
buildCKEditor(encore);
@@ -65,7 +67,7 @@ module.exports = function(encore, entries)
encore.addEntry('mod_collection', __dirname + '/Resources/public/module/collection/index.ts');
encore.addEntry('mod_forkawesome', __dirname + '/Resources/public/module/forkawesome/index.js');
encore.addEntry('mod_bootstrap', __dirname + '/Resources/public/module/bootstrap/index.js');
encore.addEntry('mod_ckeditor5', __dirname + '/Resources/public/module/ckeditor5/index.js');
encore.addEntry('mod_ckeditor5', __dirname + '/Resources/public/module/ckeditor5/index');
encore.addEntry('mod_disablebuttons', __dirname + '/Resources/public/module/disable-buttons/index.js');
encore.addEntry('mod_blur', __dirname + '/Resources/public/module/blur/index.js');
encore.addEntry('mod_input_address', __dirname + '/Resources/public/vuejs/Address/mod_input_address_index.js');

View File

@@ -52,7 +52,7 @@
<script>
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from "ChillMainAssets/module/ckeditor5";
import ClassicEditor from "../../../../../../ChillMainBundle/Resources/public/module/ckeditor5/editor_config";
import { mapState } from "vuex";
export default {

View File

@@ -41,7 +41,7 @@
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from "ChillMainAssets/module/ckeditor5";
import ClassicEditor from "ChillMainAssets/module/ckeditor5/editor_config";
export default {
name: "WriteComment",

View File

@@ -331,7 +331,7 @@
import {mapState, mapGetters,} from 'vuex';
import {dateToISO, ISOToDate, ISOToDatetime} from 'ChillMainAssets/chill/js/date';
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/index.js';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/editor_config';
import AddResult from './components/AddResult.vue';
import AddEvaluation from './components/AddEvaluation.vue';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';

View File

@@ -195,7 +195,7 @@
<script>
import {dateToISO, ISOToDate, ISOToDatetime} from 'ChillMainAssets/chill/js/date';
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/index.js';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/editor_config';
import { mapGetters, mapState } from 'vuex';
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
import {buildLink} from 'ChillDocGeneratorAssets/lib/document-generator';

View File

@@ -75,7 +75,7 @@ div.participation-details {
import { mapGetters } from 'vuex';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/index.js';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/editor_config';
export default {
name: 'MemberDetails',

View File

@@ -10,7 +10,7 @@
<script>
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from "ChillMainAssets/module/ckeditor5";
import ClassicEditor from "ChillMainAssets/module/ckeditor5/editor_config";
export default {
name: "PersonComment.vue",

View File

@@ -15,7 +15,7 @@ const personMessages = {
person: {
firstname: "Prénom",
lastname: "Nom",
born: (ctx) => {
born: (ctx: {gender: "man"|"woman"|"unknown"}) => {
if (ctx.gender === 'man') {
return 'Né le';
} else if (ctx.gender === 'woman') {

View File

@@ -74,7 +74,7 @@ final class AccompanyingCourseControllerTest extends WebTestCase
$this->assertResponseRedirects();
$location = $this->client->getResponse()->headers->get('Location');
$this->assertEquals(1, \preg_match('|^\\/[^\\/]+\\/parcours/([\\d]+)/edit$|', (string) $location));
$this->assertEquals(1, \preg_match('|^\/[^\/]+\/parcours/([\d]+)/edit$|', (string) $location));
}
/**
@@ -93,7 +93,7 @@ final class AccompanyingCourseControllerTest extends WebTestCase
$location = $this->client->getResponse()->headers->get('Location');
$matches = [];
$this->assertEquals(1, \preg_match('|^\\/[^\\/]+\\/parcours/([\\d]+)/edit$|', (string) $location, $matches));
$this->assertEquals(1, \preg_match('|^\/[^\/]+\/parcours/([\d]+)/edit$|', (string) $location, $matches));
$id = $matches[1];
$period = self::getContainer()->get(EntityManagerInterface::class)

View File

@@ -41,7 +41,7 @@ final class ChillReportExtensionTest extends KernelTestCase
}
if (!$reportFounded) {
throw new \Exception('Class Chill\\ReportBundle\\Entity\\Report not found in chill_custom_fields.customizables_entities', 1);
throw new \Exception('Class Chill\ReportBundle\Entity\Report not found in chill_custom_fields.customizables_entities', 1);
}
}
}

View File

@@ -32,10 +32,10 @@ return static function (ContainerConfigurator $container) {
->autoconfigure();
$services
->load('Chill\\WopiBundle\\Service\\', __DIR__.'/../../Service');
->load('Chill\WopiBundle\Service\\', __DIR__.'/../../Service');
$services
->load('Chill\\WopiBundle\\Controller\\', __DIR__.'/../../Controller')
->load('Chill\WopiBundle\Controller\\', __DIR__.'/../../Controller')
->tag('controller.service_arguments');
$services

View File

@@ -43,6 +43,4 @@ return [
ChampsLibres\WopiBundle\WopiBundle::class => ['all' => true],
Chill\WopiBundle\ChillWopiBundle::class => ['all' => true],
\Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
Chill\EventBundle\ChillEventBundle::class => ['all' => true],
];

View File

@@ -38,3 +38,5 @@ when@test:
test: true
session:
storage_factory_id: session.storage.factory.mock_file
assets:
json_manifest_path: null

View File

@@ -1,6 +0,0 @@
framework:
test: true
session:
storage_id: session.storage.mock_file
assets:
json_manifest_path: NULL