diff --git a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php index 2ee60d80a..abccdccc7 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\DocStoreBundle\Entity; use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface; -use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists; +use Chill\DocStoreBundle\Validator\Constraints\AsyncFileExists; use ChampsLibres\WopiLib\Contract\Entity\Document; use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; diff --git a/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php b/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php index 0fced39d3..7ae41f96e 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php @@ -14,13 +14,10 @@ namespace Chill\DocStoreBundle\Form; use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument; use Chill\DocStoreBundle\Entity\Document; use Chill\DocStoreBundle\Entity\DocumentCategory; -use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillTextareaType; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\ORM\EntityRepository; -use Doctrine\Persistence\ObjectManager; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -29,33 +26,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class AccompanyingCourseDocumentType extends AbstractType { - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; - - /** - * @var ObjectManager - */ - protected $om; - - /** - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * the user running this form. - * - * @var User - */ - protected $user; - public function __construct( - TranslatableStringHelper $translatableStringHelper - ) { - $this->translatableStringHelper = $translatableStringHelper; - } + private readonly TranslatableStringHelperInterface $translatableStringHelper + ) {} public function buildForm(FormBuilderInterface $builder, array $options) { diff --git a/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php b/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php index f3506d631..6396314e2 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php @@ -20,23 +20,15 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class DocumentCategoryType extends AbstractType { - private $chillBundlesFlipped; - - public function __construct($kernelBundles) - { - // TODO faire un service dans CHillMain - foreach ($kernelBundles as $key => $value) { - if (str_starts_with((string) $key, 'Chill')) { - $this->chillBundlesFlipped[$value] = $key; - } - } - } - public function buildForm(FormBuilderInterface $builder, array $options) { + $bundles = [ + 'chill-doc-store' => 'chill-doc-store', + ]; + $builder ->add('bundleId', ChoiceType::class, [ - 'choices' => $this->chillBundlesFlipped, + 'choices' => $bundles, 'disabled' => false, ]) ->add('idInsideBundle', null, [ @@ -44,7 +36,7 @@ class DocumentCategoryType extends AbstractType ]) ->add('documentClass', null, [ 'disabled' => false, - ]) // cahcerh par default PersonDocument + ]) ->add('name', TranslatableStringFormType::class); } diff --git a/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php b/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php index 77484208f..414d94f20 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php @@ -11,7 +11,7 @@ declare(strict_types=1); namespace Chill\DocStoreBundle\Form; -use ChampsLibres\AsyncUploaderBundle\Form\Type\AsyncUploaderType; +use Chill\DocStoreBundle\Form\Type\AsyncUploaderType; use Chill\DocStoreBundle\Entity\StoredObject; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\AbstractType; @@ -26,15 +26,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; */ class StoredObjectType extends AbstractType { - /** - * @var EntityManagerInterface - */ - protected $em; - - public function __construct(EntityManagerInterface $em) - { - $this->em = $em; - } + public function __construct(private readonly EntityManagerInterface $em) {} public function buildForm(FormBuilderInterface $builder, array $options) { diff --git a/src/Bundle/ChillDocStoreBundle/Form/Type/AsyncUploaderType.php b/src/Bundle/ChillDocStoreBundle/Form/Type/AsyncUploaderType.php new file mode 100644 index 000000000..58d4eebb1 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Form/Type/AsyncUploaderType.php @@ -0,0 +1,77 @@ +get('chill_doc_store')['openstack']['temp_url']; + + $this->expires_delay = $config['max_expires_delay']; + $this->max_submit_delay = $config['max_submit_delay']; + $this->max_post_file_size = $config['max_post_file_size']; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'expires_delay' => $this->expires_delay, + 'max_post_size' => $this->max_post_file_size, + 'submit_delay' => $this->max_submit_delay, + 'max_files' => 1, + 'error_bubbling' => false, + ]); + + $resolver->setAllowedTypes('expires_delay', ['int']); + $resolver->setAllowedTypes('max_post_size', ['int']); + $resolver->setAllowedTypes('max_files', ['int']); + $resolver->setAllowedTypes('submit_delay', ['int']); + } + + public function buildView( + FormView $view, + FormInterface $form, + array $options + ) { + $view->vars['attr']['data-async-file-upload'] = true; + $view->vars['attr']['data-generate-temp-url-post'] = $this + ->url_generator->generate('async_upload.generate_url', [ + 'expires_delay' => $options['expires_delay'], + 'method' => 'post', + 'submit_delay' => $options['submit_delay'], + ]); + $view->vars['attr']['data-temp-url-get'] = $this->url_generator + ->generate('async_upload.generate_url', ['method' => 'GET']); + $view->vars['attr']['data-max-files'] = $options['max_files']; + $view->vars['attr']['data-max-post-size'] = $options['max_post_size']; + } + + public function getParent() + { + return HiddenType::class; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Validator/Constraints/AsyncFileExistsValidatorTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Validator/Constraints/AsyncFileExistsValidatorTest.php new file mode 100644 index 000000000..6e46ee370 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Tests/Validator/Constraints/AsyncFileExistsValidatorTest.php @@ -0,0 +1,67 @@ + 404]); + } + + return new MockResponse('', ['http_code' => 200]); + }); + + $generator = $this->prophesize(TempUrlGeneratorInterface::class); + $generator->generate(Argument::in(['GET', 'HEAD']), Argument::type('string'), Argument::any()) + ->will(fn (array $args): SignedUrl => new SignedUrl($args[0], 'https://object.store.example/container/'.$args[1], new \DateTimeImmutable('1 hours'))); + + return new AsyncFileExistsValidator($generator->reveal(), $client); + } + + public function testWhenFileExistsIsValid(): void + { + $this->validator->validate((new StoredObject())->setFilename('present'), new AsyncFileExists()); + + $this->assertNoViolation(); + } + + public function testWhenFileIsNotPresent(): void + { + $this->validator->validate( + (new StoredObject())->setFilename('is_404'), + new AsyncFileExists(['message' => 'my_message']) + ); + + $this->buildViolation('my_message')->setParameter('{{ filename }}', 'is_404')->assertRaised(); + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Validator/Constraints/AsyncFileExists.php b/src/Bundle/ChillDocStoreBundle/Validator/Constraints/AsyncFileExists.php new file mode 100644 index 000000000..4e251629b --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Validator/Constraints/AsyncFileExists.php @@ -0,0 +1,32 @@ +validateObject($value->getFilename(), $constraint); + } elseif (is_string($value)) { + $this->validateObject($value, $constraint); + } else { + throw new UnexpectedValueException($value, StoredObject::class.' or string'); + } + } + + protected function validateObject(string $file, Constraint $constraint): void + { + if (!$constraint instanceof AsyncFileExists) { + throw new UnexpectedTypeException($constraint, AsyncFileExists::class); + } + + $urlHead = $this->tempUrlGenerator->generate( + 'HEAD', + $file, + 30 + ); + + try { + $response = $this->client->request('HEAD', $urlHead->url); + + if (404 === $response->getStatusCode()) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ filename }}', $file) + ->addViolation(); + } + } catch (HttpExceptionInterface $exception) { + if (404 !== $exception->getResponse()->getStatusCode()) { + throw $exception; + } + } + } +} diff --git a/src/Bundle/ChillDocStoreBundle/config/services.yaml b/src/Bundle/ChillDocStoreBundle/config/services.yaml index c510064f1..27c04a60e 100644 --- a/src/Bundle/ChillDocStoreBundle/config/services.yaml +++ b/src/Bundle/ChillDocStoreBundle/config/services.yaml @@ -8,18 +8,6 @@ services: tags: - { name: doctrine.repository_service } - Chill\DocStoreBundle\Form\DocumentCategoryType: - class: Chill\DocStoreBundle\Form\DocumentCategoryType - arguments: [ "%kernel.bundles%" ] - tags: - - { name: form.type } - - Chill\DocStoreBundle\Form\PersonDocumentType: - class: Chill\DocStoreBundle\Form\PersonDocumentType - # arguments: - # - "@chill.main.helper.translatable_string" - tags: - - { name: form.type, alias: chill_docstorebundle_form_document } Chill\DocStoreBundle\Security\Authorization\: resource: "./../Security/Authorization" @@ -54,6 +42,9 @@ services: Chill\DocStoreBundle\GenericDoc\Renderer\: resource: '../GenericDoc/Renderer/' + Chill\DocStoreBundle\Validator\: + resource: '../Validator' + Chill\DocStoreBundle\AsyncUpload\Driver\: resource: '../AsyncUpload/Driver/' diff --git a/src/Bundle/ChillDocStoreBundle/config/services/form.yaml b/src/Bundle/ChillDocStoreBundle/config/services/form.yaml index 8d53d81f1..7515f306a 100644 --- a/src/Bundle/ChillDocStoreBundle/config/services/form.yaml +++ b/src/Bundle/ChillDocStoreBundle/config/services/form.yaml @@ -1,13 +1,15 @@ services: - Chill\DocStoreBundle\Form\StoredObjectType: - arguments: - $em: '@Doctrine\ORM\EntityManagerInterface' - tags: - - { name: form.type } + _defaults: + autowire: true + autoconfigure: true - Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType: - class: Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType - arguments: - - "@chill.main.helper.translatable_string" - tags: - - { name: form.type, alias: chill_docstorebundle_form_document } + Chill\DocStoreBundle\Form\: + resource: '../../Form' + + Chill\DocStoreBundle\Form\PersonDocumentType: + tags: + - { name: form.type, alias: chill_docstorebundle_form_document } + + Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType: + tags: + - { name: form.type, alias: chill_docstorebundle_form_document }