diff --git a/CHANGELOG.md b/CHANGELOG.md index 4923eb877..c8e0d0f5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to * [person] add validator for accompanying period with a test on social issues (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/76) * [activity] fix visibility for location +* [origin] fix origin: use correctly the translatable strings + + * /!\ everyone must update the origin table. As there is only one row, execute `update chill_person_accompanying_period_origin set label = jsonb_build_object('fr', 'appel téléphonique');` ## Test releases diff --git a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php index 21a830bfd..42e6b0e69 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php +++ b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php @@ -18,6 +18,7 @@ use Chill\DocGeneratorBundle\Context\DocGeneratorContextWithPublicFormInterface; use Chill\DocGeneratorBundle\Context\Exception\ContextNotFoundException; use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; use Chill\DocGeneratorBundle\GeneratorDriver\DriverInterface; +use Chill\DocGeneratorBundle\GeneratorDriver\Exception\TemplateException; use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository; use Chill\DocStoreBundle\Entity\StoredObject; use Chill\MainBundle\Pagination\PaginatorFactory; @@ -28,10 +29,15 @@ use GuzzleHttp\Exception\TransferException; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\Form\Extension\Core\Type\FileType; +use Symfony\Component\HttpFoundation\File\File; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; // TODO à mettre dans services use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\KernelInterface; @@ -78,6 +84,27 @@ final class DocGeneratorTemplateController extends AbstractController $this->client = $client; } + /** + * @Route( + * "{_locale}/admin/doc/gen/generate/test/from/{template}/for/{entityClassName}/{entityId}", + * name="chill_docgenerator_test_generate_from_template" + * ) + */ + public function adminTestGenerateDocFromTemplateAction( + DocGeneratorTemplate $template, + string $entityClassName, + int $entityId, + Request $request + ): Response { + return $this->generateDocFromTemplate( + $template, + $entityClassName, + $entityId, + $request, + true + ); + } + /** * @Route( * "{_locale}/doc/gen/generate/from/{template}/for/{entityClassName}/{entityId}", @@ -89,6 +116,81 @@ final class DocGeneratorTemplateController extends AbstractController string $entityClassName, int $entityId, Request $request + ): Response { + return $this->generateDocFromTemplate( + $template, + $entityClassName, + $entityId, + $request, + false + ); + } + + /** + * @Route( + * "/api/1.0/docgen/templates/by-entity/{entityClassName}", + * name="chill_docgenerator_templates_for_entity_api" + * ) + */ + public function listTemplateApiAction(string $entityClassName): Response + { + $nb = $this->docGeneratorTemplateRepository->countByEntity($entityClassName); + $paginator = $this->paginatorFactory->create($nb); + $entities = $this->docGeneratorTemplateRepository->findByEntity( + $entityClassName, + $paginator->getCurrentPageFirstItemNumber(), + $paginator->getItemsPerPage() + ); + + return $this->json( + new Collection($entities, $paginator), + Response::HTTP_OK, + [], + [AbstractNormalizer::GROUPS => ['read']] + ); + } + + /** + * @Route( + * "{_locale}/admin/doc/gen/generate/test/redirect", + * name="chill_docgenerator_test_generate_redirect" + * ) + * + * @return void + */ + public function redirectToTestGenerate(Request $request): RedirectResponse + { + $template = $request->query->getInt('template'); + + if (null === $template) { + throw new BadRequestHttpException('template parameter is missing'); + } + + $entityClassName = $request->query->get('entityClassName'); + + if (null === $entityClassName) { + throw new BadRequestHttpException('entityClassName is missing'); + } + + $entityId = $request->query->get('entityId'); + + if (null === $entityId) { + throw new BadRequestHttpException('entityId is missing'); + } + + return $this->redirectToRoute( + 'chill_docgenerator_test_generate_from_template', + ['template' => $template, 'entityClassName' => $entityClassName, 'entityId' => $entityId, + 'returnPath' => $request->query->get('returnPath', '/'), ] + ); + } + + private function generateDocFromTemplate( + DocGeneratorTemplate $template, + string $entityClassName, + int $entityId, + Request $request, + bool $isTest ): Response { try { $context = $this->contextManager->getContextByDocGeneratorTemplate($template); @@ -105,9 +207,29 @@ final class DocGeneratorTemplateController extends AbstractController $contextGenerationData = []; if ($context instanceof DocGeneratorContextWithPublicFormInterface - && $context->hasPublicForm($template, $entity)) { - $builder = $this->createFormBuilder($context->getFormData($template, $entity)); + && $context->hasPublicForm($template, $entity) || $isTest) { + if ($context instanceof DocGeneratorContextWithPublicFormInterface) { + $builder = $this->createFormBuilder( + array_merge( + $context->getFormData($template, $entity), + $isTest ? ['test_file' => null] : [] + ) + ); + } else { + $builder = $this->createFormBuilder( + ['test_file' => null] + ); + } + $context->buildPublicForm($builder, $template, $entity); + + if ($isTest) { + $builder->add('test_file', FileType::class, [ + 'label' => 'Template file', + 'required' => false, + ]); + } + $form = $builder->getForm()->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { @@ -121,43 +243,72 @@ final class DocGeneratorTemplateController extends AbstractController } } - $getUrlGen = $this->tempUrlGenerator->generate( - 'GET', - $template->getFile()->getFilename() - ); + if ($isTest && null !== $contextGenerationData['test_file']) { + /** @var File $file */ + $file = $contextGenerationData['test_file']; + $templateResource = fopen($file->getPathname(), 'rb'); + } else { + $getUrlGen = $this->tempUrlGenerator->generate( + 'GET', + $template->getFile()->getFilename() + ); - $data = $this->client->request('GET', $getUrlGen->url); + $data = $this->client->request('GET', $getUrlGen->url); - $iv = $template->getFile()->getIv(); // iv as an Array - $ivGoodFormat = pack('C*', ...$iv); // iv as a String (ok for openssl_decrypt) + $iv = $template->getFile()->getIv(); // iv as an Array + $ivGoodFormat = pack('C*', ...$iv); // iv as a String (ok for openssl_decrypt) - $method = 'AES-256-CBC'; + $method = 'AES-256-CBC'; - $key = $template->getFile()->getKeyInfos()['k']; - $keyGoodFormat = Base64Url::decode($key); + $key = $template->getFile()->getKeyInfos()['k']; + $keyGoodFormat = Base64Url::decode($key); - $dataDecrypted = openssl_decrypt($data->getContent(), $method, $keyGoodFormat, 1, $ivGoodFormat); + $dataDecrypted = openssl_decrypt($data->getContent(), $method, $keyGoodFormat, 1, $ivGoodFormat); - if (false === $dataDecrypted) { - throw new Exception('Error during Decrypt ', 1); + if (false === $dataDecrypted) { + throw new Exception('Error during Decrypt ', 1); + } + + if (false === $templateResource = fopen('php://memory', 'r+b')) { + $this->logger->error('Could not write data to memory'); + + throw new HttpException(500); + } + fwrite($templateResource, $dataDecrypted); + rewind($templateResource); } - if (false === $templateResource = fopen('php://memory', 'r+b')) { - $this->logger->error('Could not write data to memory'); - - throw new HttpException(500); - } - - fwrite($templateResource, $dataDecrypted); - rewind($templateResource); - $datas = $context->getData($template, $entity, $contextGenerationData); dump('datas compiled', $datas); - $generatedResource = $this->driver->generateFromResource($templateResource, $template->getFile()->getType(), $datas, $template->getFile()->getFilename()); + try { + $generatedResource = $this->driver->generateFromResource($templateResource, $template->getFile()->getType(), $datas, $template->getFile()->getFilename()); + } catch (TemplateException $e) { + $msg = implode("\n", $e->getErrors()); + + return new Response($msg, 400, [ + 'Content-Type' => 'text/plain', + ]); + } fclose($templateResource); + if ($isTest) { + return new StreamedResponse( + static function () use ($generatedResource) { + fpassthru($generatedResource); + fclose($generatedResource); + }, + Response::HTTP_OK, + [ + 'Content-Transfer-Encoding', 'binary', + 'Content-Type' => 'application/vnd.oasis.opendocument.text', + 'Content-Disposition' => sprintf('attachment; filename="%s.odt"', 'generated'), + 'Content-Length' => fstat($generatedResource)['size'], + ], + ); + } + $genDocName = 'doc_' . sprintf('%010d', mt_rand()) . 'odt'; $getUrlGen = $this->tempUrlGenerator->generate( @@ -206,28 +357,4 @@ final class DocGeneratorTemplateController extends AbstractController throw new Exception('Unable to generate document.'); } - - /** - * @Route( - * "/api/1.0/docgen/templates/by-entity/{entityClassName}", - * name="chill_docgenerator_templates_for_entity_api" - * ) - */ - public function listTemplateApiAction(string $entityClassName): Response - { - $nb = $this->docGeneratorTemplateRepository->countByEntity($entityClassName); - $paginator = $this->paginatorFactory->create($nb); - $entities = $this->docGeneratorTemplateRepository->findByEntity( - $entityClassName, - $paginator->getCurrentPageFirstItemNumber(), - $paginator->getItemsPerPage() - ); - - return $this->json( - new Collection($entities, $paginator), - Response::HTTP_OK, - [], - [AbstractNormalizer::GROUPS => ['read']] - ); - } } diff --git a/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/Exception/TemplateException.php b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/Exception/TemplateException.php new file mode 100644 index 000000000..214c77621 --- /dev/null +++ b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/Exception/TemplateException.php @@ -0,0 +1,35 @@ +errors = $errors; + } + + public function getErrors(): array + { + return $this->errors; + } +} diff --git a/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php index 8889e72b1..7101e562d 100644 --- a/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php +++ b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\DocGeneratorBundle\GeneratorDriver; +use Chill\DocGeneratorBundle\GeneratorDriver\Exception\TemplateException; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Mime\Part\DataPart; @@ -45,6 +46,7 @@ class RelatorioDriver implements DriverInterface 'template' => new DataPart($template, $templateName ?? uniqid('template_'), $resourceType), ]; $form = new FormDataPart($formFields); + dump(json_encode($data)); try { $response = $this->relatorioClient->request('POST', $this->url, [ @@ -54,10 +56,21 @@ class RelatorioDriver implements DriverInterface return $response->toStream(); } catch (HttpExceptionInterface $e) { + $content = $e->getResponse()->getContent(false); + + if (400 === $e->getResponse()->getStatusCode()) { + $content = json_decode($content, true); + $this->logger->error('relatorio: template error', [ + 'error' => $content['message'] ?? '_not defined', + ]); + + throw new TemplateException([$content['message']]); + } + $this->logger->error('relatorio: error while generating document', [ 'msg' => $e->getMessage(), 'response' => $e->getResponse()->getStatusCode(), - 'content' => $e->getResponse()->getContent(false), + 'content' => $content, ]); throw $e; diff --git a/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig index 1cdad36ff..29050ce02 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig +++ b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig @@ -6,6 +6,7 @@