Merge remote-tracking branch 'origin/docgenerator_oct_nov_21' into features/docgen-widget-generate-template

This commit is contained in:
Julien Fastré 2021-11-30 18:31:33 +01:00
commit 0710d6572b
9 changed files with 178 additions and 30 deletions

View File

@ -20,29 +20,47 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Serializer\Model\Collection; use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
use Exception;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\TransferException; use GuzzleHttp\Exception\TransferException;
use PhpOffice\PhpWord\TemplateProcessor; use PhpOffice\PhpWord\TemplateProcessor;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\HeaderUtils;
use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlOpenstackGenerator;
use Jose\Component\Core\JWK;
use Base64Url\Base64Url;
use Symfony\Component\HttpKernel\KernelInterface;
// TODO à mettre dans services // TODO à mettre dans services
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
class DocGeneratorTemplateController extends AbstractController use Symfony\Contracts\HttpClient\HttpClientInterface;
final class DocGeneratorTemplateController extends AbstractController
{ {
private DocGeneratorTemplateRepository $docGeneratorTemplateRepository; private DocGeneratorTemplateRepository $docGeneratorTemplateRepository;
private PaginatorFactory $paginatorFactory; private PaginatorFactory $paginatorFactory;
public function __construct(DocGeneratorTemplateRepository $docGeneratorTemplateRepository, PaginatorFactory $paginatorFactory) private KernelInterface $kernel;
{
private HttpClientInterface $client;
public function __construct(
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
PaginatorFactory $paginatorFactory,
KernelInterface $kernel,
HttpClientInterface $client
) {
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository; $this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
$this->paginatorFactory = $paginatorFactory; $this->paginatorFactory = $paginatorFactory;
$this->kernel = $kernel;
$this->client = $client;
} }
/** /**
@ -60,11 +78,39 @@ class DocGeneratorTemplateController extends AbstractController
): Response { ): Response {
$getUrlGen = $tempUrlGenerator->generate( $getUrlGen = $tempUrlGenerator->generate(
'GET', 'GET',
$template->getFile() $template->getFile()->getFilename());
);
$tmpfname = tempnam(sys_get_temp_dir(), 'DOC_TEMPLATE'); $data = $this->client->request('GET', $getUrlGen->url);
file_put_contents($tmpfname, file_get_contents($getUrlGen->url));
$iv = $template->getFile()->getIv(); // iv as an Array
$ivGoodFormat = pack('C*', ...$iv); // iv as a String (ok for openssl_decrypt)
$method = 'AES-256-CBC';
$key = $template->getFile()->getKeyInfos()['k'];
$keyGoodFormat = Base64Url::decode($key);
$dataDecrypted = openssl_decrypt($data->getContent(), $method, $keyGoodFormat, 1, $ivGoodFormat);
if ($dataDecrypted === FALSE) {
throw new \Exception("Error during Decrypt ", 1);
}
$tmpfnameDeCrypted = tempnam($this->kernel->getCacheDir(), 'DECRYPT_DOC_TEMPLATE'); // plus ou moins
if (!$handle = fopen($tmpfnameDeCrypted, 'a')) {
echo "Cannot open file ($tmpfnameDeCrypted)";
exit;
}
if (fwrite($handle, $dataDecrypted) === FALSE) {
echo "Cannot write to file ($tmpfnameDeCrypted)";
exit;
}
dump("Success, wrote ($dataDecrypted) to file ($tmpfnameDeCrypted)");
fclose($handle);
$entity = $this->getDoctrine()->getRepository($entityClassName)->find($entityId); $entity = $this->getDoctrine()->getRepository($entityClassName)->find($entityId);
@ -72,10 +118,10 @@ class DocGeneratorTemplateController extends AbstractController
$context = new HouseholdMemberSelectionContext(); $context = new HouseholdMemberSelectionContext();
$datas = $context->getData($entity); $datas = $context->getData($entity);
} else { } else {
throw new Exception('Not implemented', 1); throw new \Exception('Not implemented', 1);
} }
$templateProcessor = new TemplateProcessor($tmpfname); $templateProcessor = new TemplateProcessor($tmpfnameDeCrypted);
foreach ($datas['setValues'] as $setValuesConf) { foreach ($datas['setValues'] as $setValuesConf) {
$templateProcessor->setValues($setValuesConf); $templateProcessor->setValues($setValuesConf);
@ -85,12 +131,10 @@ class DocGeneratorTemplateController extends AbstractController
$templateProcessor->cloneRowAndSetValues($cloneRowAndSetValues[0], $cloneRowAndSetValues[1]); $templateProcessor->cloneRowAndSetValues($cloneRowAndSetValues[0], $cloneRowAndSetValues[1]);
} }
$tmpfname2 = tempnam(sys_get_temp_dir(), 'DOC_GENERATED'); $tmpfnameGenerated = tempnam($this->kernel->getCacheDir(), 'DOC_GENERATED');
$templateProcessor->saveAs($tmpfname2); $templateProcessor->saveAs($tmpfnameGenerated);
unlink($tmpfname); $fileContent = fopen($tmpfnameGenerated, 'rb'); // the generated file content
$fileContent = fopen($tmpfname2, 'rb'); // the generated file content
$genDocName = 'doc_' . sprintf('%010d', mt_rand()) . '.docx'; $genDocName = 'doc_' . sprintf('%010d', mt_rand()) . '.docx';
@ -99,7 +143,8 @@ class DocGeneratorTemplateController extends AbstractController
$genDocName $genDocName
); );
unlink($tmpfname2); unlink($tmpfnameDeCrypted);
unlink($tmpfnameGenerated);
$client = new Client(); $client = new Client();
@ -140,7 +185,7 @@ class DocGeneratorTemplateController extends AbstractController
} }
throw new Exception('Unable to generate document.'); throw new Exception('Unable to generate document.');
} }
/** /**
* @Route( * @Route(

View File

@ -14,8 +14,8 @@ namespace Chill\DocGeneratorBundle\DataFixtures\ORM;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Chill\DocStoreBundle\Entity\StoredObject;
/** /**
* Load DocGeneratorTemplate. * Load DocGeneratorTemplate.
@ -28,13 +28,23 @@ class LoadDocGeneratorTemplate extends AbstractFixture
[ [
'name' => ['fr' => 'FORMULAIRE AEB'], 'name' => ['fr' => 'FORMULAIRE AEB'],
'desc' => 'stocké sur openstack comedienbe', 'desc' => 'stocké sur openstack comedienbe',
'file' => 'FORMULAIRE_AEB_WITH_DATA_INJ.docx', 'file' => [
'filename' => 'pKNlhCrQDCRsAuC8vYHDKa',
'key' => '{"alg":"A256CBC","ext":true,"k":"_VihnD41-VDHlpS-ouwtbMPnu-OXVdtA7ENQWWtAQYM","key_ops":["encrypt","decrypt"],"kty":"oct"}',
'iv' => '[86,231,83,148,117,107,149,173,130,19,105,194,224,145,8,48]',
'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
],
'context' => 'Chill\DocGeneratorBundle\Context\HouseholdMemberSelectionContext', 'context' => 'Chill\DocGeneratorBundle\Context\HouseholdMemberSelectionContext',
'entities' => [AccompanyingPeriodWorkEvaluation::class], 'entities' => [AccompanyingPeriodWorkEvaluation::class],
], [ ], [
'name' => ['fr' => 'AIDE ALIMENTAIRE'], 'name' => ['fr' => 'AIDE ALIMENTAIRE'],
'desc' => 'stocké sur openstack comedienbe', 'desc' => 'stocké sur openstack comedienbe',
'file' => 'AIDE_ALIMENTAIRE.docx', 'file' => [
'filename' => 'pKNlhCrQDCRsAuC8vYHDKa',
'key' => '{"alg":"A256CBC","ext":true,"k":"_VihnD41-VDHlpS-ouwtbMPnu-OXVdtA7ENQWWtAQYM","key_ops":["encrypt","decrypt"],"kty":"oct"}',
'iv' => '[86,231,83,148,117,107,149,173,130,19,105,194,224,145,8,48]',
'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
],
'context' => 'Chill\DocGeneratorBundle\Context\HouseholdMemberSelectionContext', 'context' => 'Chill\DocGeneratorBundle\Context\HouseholdMemberSelectionContext',
'entities' => ['Chill\PersonBundle\Entity\AccompanyingPeriod', 'Chill\PersonBundle\Entity\SocialWork\SocialAction', AccompanyingPeriodWorkEvaluation::class], 'entities' => ['Chill\PersonBundle\Entity\AccompanyingPeriod', 'Chill\PersonBundle\Entity\SocialWork\SocialAction', AccompanyingPeriodWorkEvaluation::class],
], ],
@ -43,10 +53,19 @@ class LoadDocGeneratorTemplate extends AbstractFixture
foreach ($templates as $template) { foreach ($templates as $template) {
echo 'Adding doc generator templates ' . $template['file'] . ")\n"; echo 'Adding doc generator templates ' . $template['file'] . ")\n";
$newStoredObj = (new StoredObject())
->setFilename($template['file']['filename'])
->setKeyInfos(json_decode($template['file']['key'], true))
->setIv(json_decode($template['file']['iv'], true))
->setCreationDate(new \DateTime('today'))
->setType($template['file']['type']);
$manager->persist($newStoredObj);
$newTemplate = (new DocGeneratorTemplate()) $newTemplate = (new DocGeneratorTemplate())
->setName($template['name']) ->setName($template['name'])
->setDescription($template['desc']) ->setDescription($template['desc'])
->setFile($template['file']) ->setFile($newStoredObj)
->setContext($template['context']) ->setContext($template['context'])
->setEntities($template['entities']); ->setEntities($template['entities']);

View File

@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer; use Symfony\Component\Serializer\Annotation as Serializer;
use Chill\DocStoreBundle\Entity\StoredObject;
/** /**
* @ORM\Entity * @ORM\Entity
@ -50,9 +51,9 @@ class DocGeneratorTemplate
private array $entities = []; private array $entities = [];
/** /**
* @ORM\Column(type="string", length=255) * @ORM\ManyToOne(targetEntity=StoredObject::class, cascade={"persist"}).)
*/ */
private string $file; private ?StoredObject $file = null;
/** /**
* @ORM\Id * @ORM\Id
@ -61,6 +62,7 @@ class DocGeneratorTemplate
* @Serializer\Groups({"read"}) * @Serializer\Groups({"read"})
*/ */
private int $id; private int $id;
/** /**
* @ORM\Column(type="json") * @ORM\Column(type="json")
@ -83,7 +85,7 @@ class DocGeneratorTemplate
return $this->entities; return $this->entities;
} }
public function getFile(): ?string public function getFile(): ?StoredObject
{ {
return $this->file; return $this->file;
} }
@ -93,10 +95,11 @@ class DocGeneratorTemplate
return $this->id; return $this->id;
} }
public function getName(): ?array public function getName(): ?array
{ {
return $this->name; return $this->name;
} }
public function setContext(string $context): self public function setContext(string $context): self
{ {
@ -119,7 +122,7 @@ class DocGeneratorTemplate
return $this; return $this;
} }
public function setFile(string $file): self public function setFile(StoredObject $file): self
{ {
$this->file = $file; $this->file = $file;

View File

@ -14,8 +14,12 @@ namespace Chill\DocGeneratorBundle\Form;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\MainBundle\Form\Type\TranslatableStringFormType; use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\DocStoreBundle\Form\StoredObjectType;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class DocGeneratorTemplateType extends AbstractType class DocGeneratorTemplateType extends AbstractType
{ {
@ -25,8 +29,19 @@ class DocGeneratorTemplateType extends AbstractType
->add('name', TranslatableStringFormType::class, [ ->add('name', TranslatableStringFormType::class, [
'label' => 'Nom', 'label' => 'Nom',
]) ])
->add('context')
->add('entities', ChoiceType::class, [
'multiple' => true,
'choices' => [
'AccompanyingPeriod' => 'Chill\PersonBundle\Entity\AccompanyingPeriod',
'SocialWork\SocialAction' => 'Chill\PersonBundle\Entity\SocialWork\SocialAction',
'AccompanyingPeriod\AccompanyingPeriodWorkEvaluation' => AccompanyingPeriodWorkEvaluation::class
]])
->add('description') ->add('description')
->add('file'); ->add('file', StoredObjectType::class, [
'error_bubbling' => true
])
;
} }
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)

View File

@ -10,3 +10,12 @@
{% block content_form_actions_save_and_show %}{% endblock %} {% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %} {% endembed %}
{% endblock %} {% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@ -5,7 +5,7 @@
{% block table_entities_thead_tr %} {% block table_entities_thead_tr %}
<th></th> <th></th>
<th>{{ 'Title'|trans }}</th> <th>{{ 'Title'|trans }}</th>
<th>{{ 'File'|trans }}</th> <th>{{ 'Edit'|trans }}</th>
{% endblock %} {% endblock %}
{% block table_entities_tbody %} {% block table_entities_tbody %}
@ -13,7 +13,11 @@
<tr> <tr>
<td>{{ entity.id }}</td> <td>{{ entity.id }}</td>
<td>{{ entity.name | localize_translatable_string }}</td> <td>{{ entity.name | localize_translatable_string }}</td>
<td>{{ entity.file }}</td> <td>
<a href="{{ chill_path_add_return_path('chill_crud_docgen_template_edit', { 'id': entity.id }) }}" class="btn btn-edit">
{{ 'Edit'|trans }}
</a>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

View File

@ -9,3 +9,12 @@
{% block content_form_actions_save_and_show %}{% endblock %} {% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %} {% endembed %}
{% endblock %} {% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@ -15,3 +15,8 @@ services:
resource: '../Serializer/Normalizer/' resource: '../Serializer/Normalizer/'
tags: tags:
- { name: 'serializer.normalizer', priority: -152 } - { name: 'serializer.normalizer', priority: -152 }
Chill\DocGeneratorBundle\Controller\:
resource: "../Controller"
autowire: true
autoconfigure: true

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\DocGenerator;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Using DocStore objects inside the DocGenTemplate
*/
final class Version20211103111010 extends AbstractMigration
{
public function getDescription(): string
{
return 'Using DocStore objects inside the DocGenTemplate';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_docgen_template ADD file_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_docgen_template DROP file');
$this->addSql('ALTER TABLE chill_docgen_template ALTER entities SET NOT NULL');
$this->addSql('ALTER TABLE chill_docgen_template ALTER context SET NOT NULL');
$this->addSql('ALTER TABLE chill_docgen_template ADD CONSTRAINT FK_49A347E893CB796C FOREIGN KEY (file_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_49A347E893CB796C ON chill_docgen_template (file_id)');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_docgen_template DROP CONSTRAINT FK_49A347E893CB796C');
$this->addSql('DROP INDEX IDX_49A347E893CB796C');
$this->addSql('ALTER TABLE chill_docgen_template ADD file VARCHAR(255) NOT NULL');
$this->addSql('ALTER TABLE chill_docgen_template DROP file_id');
$this->addSql('ALTER TABLE chill_docgen_template ALTER entities DROP NOT NULL');
$this->addSql('ALTER TABLE chill_docgen_template ALTER context DROP NOT NULL');
}
}