From c28c2bf119ad82193812f3a3381ddb739610fd4f Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Fri, 6 Apr 2018 17:09:51 +0200 Subject: [PATCH 01/58] First commit --- ChillDocStoreBundle.php | 9 + Controller/DocumentCategoryController.php | 129 ++++++++++++++ Controller/DocumentPersonController.php | 163 ++++++++++++++++++ .../ChillDocStoreExtension.php | 28 +++ DependencyInjection/Configuration.php | 29 ++++ Entity/Document.php | 160 +++++++++++++++++ Entity/DocumentCategory.php | 98 +++++++++++ Entity/PersonDocument.php | 45 +++++ .../DocumentCategoryRepository.php | 39 +++++ Form/DocumentCategoryType.php | 50 ++++++ Form/PersonDocumentType.php | 104 +++++++++++ Resources/config/routing.yml | 3 + Resources/config/services.yml | 27 +++ .../migrations/Version20180322123800.php | 45 +++++ .../DocumentCategory/_delete_form.html.twig | 21 +++ .../views/DocumentCategory/_form.html.twig | 20 +++ .../views/DocumentCategory/edit.html.twig | 31 ++++ .../views/DocumentCategory/index.html.twig | 60 +++++++ .../views/DocumentCategory/new.html.twig | 29 ++++ .../views/DocumentCategory/show.html.twig | 54 ++++++ .../PersonDocument/_delete_form.html.twig | 5 + .../views/PersonDocument/_form.html.twig | 4 + Resources/views/PersonDocument/edit.html.twig | 33 ++++ .../views/PersonDocument/index.html.twig | 66 +++++++ Resources/views/PersonDocument/new.html.twig | 31 ++++ Resources/views/PersonDocument/show.html.twig | 68 ++++++++ .../Authorization/PersonDocumentVoter.php | 83 +++++++++ 27 files changed, 1434 insertions(+) create mode 100644 ChillDocStoreBundle.php create mode 100644 Controller/DocumentCategoryController.php create mode 100644 Controller/DocumentPersonController.php create mode 100644 DependencyInjection/ChillDocStoreExtension.php create mode 100644 DependencyInjection/Configuration.php create mode 100644 Entity/Document.php create mode 100644 Entity/DocumentCategory.php create mode 100644 Entity/PersonDocument.php create mode 100644 EntityRepository/DocumentCategoryRepository.php create mode 100644 Form/DocumentCategoryType.php create mode 100644 Form/PersonDocumentType.php create mode 100644 Resources/config/routing.yml create mode 100644 Resources/config/services.yml create mode 100644 Resources/migrations/Version20180322123800.php create mode 100644 Resources/views/DocumentCategory/_delete_form.html.twig create mode 100644 Resources/views/DocumentCategory/_form.html.twig create mode 100644 Resources/views/DocumentCategory/edit.html.twig create mode 100644 Resources/views/DocumentCategory/index.html.twig create mode 100644 Resources/views/DocumentCategory/new.html.twig create mode 100644 Resources/views/DocumentCategory/show.html.twig create mode 100644 Resources/views/PersonDocument/_delete_form.html.twig create mode 100644 Resources/views/PersonDocument/_form.html.twig create mode 100644 Resources/views/PersonDocument/edit.html.twig create mode 100644 Resources/views/PersonDocument/index.html.twig create mode 100644 Resources/views/PersonDocument/new.html.twig create mode 100644 Resources/views/PersonDocument/show.html.twig create mode 100644 Security/Authorization/PersonDocumentVoter.php diff --git a/ChillDocStoreBundle.php b/ChillDocStoreBundle.php new file mode 100644 index 000000000..60649a163 --- /dev/null +++ b/ChillDocStoreBundle.php @@ -0,0 +1,9 @@ +getDoctrine()->getManager(); + $categories = $em->getRepository("ChillDocStoreBundle:DocumentCategory")->findAll(); + + return $this->render( + 'ChillDocStoreBundle:DocumentCategory:index.html.twig', + ['document_categories' => $categories]); + } + + /** + * @Route("/new", name="document_category_new", methods="GET|POST") + */ + public function new(Request $request): Response + { + $em = $this->getDoctrine()->getManager(); + $documentCategory = new DocumentCategory(); + $documentCategory + ->setBundleId('Chill\DocStoreBundle\ChillDocStoreBundle'); + $documentCategory + ->setIdInsideBundle( + $em->getRepository("ChillDocStoreBundle:DocumentCategory") + ->nextIdInsideBundle()); + $documentCategory + ->setDocumentClass(PersonDocument::class); + + $form = $this->createForm(DocumentCategoryType::class, $documentCategory); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->persist($documentCategory); + $em->flush(); + + return $this->redirectToRoute('document_category_index'); + } else { + $documentCategory->setBundleId( + 'Chill\DocStoreBundle\ChillDocStoreBundle'); + } + + return $this->render('ChillDocStoreBundle:DocumentCategory:new.html.twig', [ + 'document_category' => $documentCategory, + 'form' => $form->createView(), + ]); + } + + /** + * @Route("/{bundleId}/{idInsideBundle}", name="document_category_show", methods="GET") + */ + public function show($bundleId, $idInsideBundle): Response + { + $em = $this->getDoctrine()->getManager(); + $documentCategory = $em + ->getRepository("ChillDocStoreBundle:DocumentCategory") + ->findOneBy( + ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]); + + return $this->render( + 'ChillDocStoreBundle:DocumentCategory:show.html.twig', + ['document_category' => $documentCategory]); + } + + /** + * @Route("/{bundleId}/{idInsideBundle}/edit", name="document_category_edit", methods="GET|POST") + */ + public function edit(Request $request, $bundleId, $idInsideBundle): Response + { + $em = $this->getDoctrine()->getManager(); + $documentCategory = $em + ->getRepository("ChillDocStoreBundle:DocumentCategory") + ->findOneBy( + ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]); + + $form = $this->createForm(DocumentCategoryType::class, $documentCategory); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->getDoctrine()->getManager()->flush(); + + return $this->redirectToRoute('document_category_edit', [ + 'bundleId' => $documentCategory->getBundleId(), + 'idInsideBundle' => $documentCategory->getIdInsideBundle(),]); + } + + return $this->render('ChillDocStoreBundle:DocumentCategory:edit.html.twig', [ + 'document_category' => $documentCategory, + 'form' => $form->createView(), + ]); + } + + /** + * @Route("/{bundleId}/{idInsideBundle}", name="document_category_delete", methods="DELETE") + */ + public function delete(Request $request, $bundleId, $idInsideBundle): Response + { + $em = $this->getDoctrine()->getManager(); + $documentCategory = $em + ->getRepository("ChillDocStoreBundle:DocumentCategory") + ->findOneBy( + ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]); + + if ($this->isCsrfTokenValid('delete'.$bundleId.$idInsideBundle, $request->request->get('_token'))) { + $em->remove($documentCategory); + $em->flush(); + } + + return $this->redirectToRoute('document_category_index'); + } +} diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php new file mode 100644 index 000000000..5a5464f2c --- /dev/null +++ b/Controller/DocumentPersonController.php @@ -0,0 +1,163 @@ +getDoctrine()->getManager(); + + if ($person === NULL) { + throw $this->createNotFoundException('Person not found'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + + $reachableScopes = $this->get('chill.main.security.authorization.helper') + ->getReachableScopes( + $this->getUser(), new Role('CHILL_PERSON_DOCUMENT_SEE'), + $person->getCenter()); + + $documents = $em + ->getRepository("ChillDocStoreBundle:PersonDocument") + ->findBy( + array('person' => $person, 'scope' => $reachableScopes), + array('date' => 'DESC') + ); + + return $this->render( + 'ChillDocStoreBundle:PersonDocument:index.html.twig', + [ + 'documents' => $documents, + 'person' => $person + ]); + } + + /** + * @Route("/new", name="person_document_new", methods="GET|POST") + */ + public function new(Request $request, Person $person): Response + { + if ($person === NULL) { + throw $this->createNotFoundException('person not found'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + + $user = $this->get('security.context')->getToken()->getUser(); + $document = new PersonDocument(); + $document->setUser($user); + $document->setPerson($person); + $document->setDate(new \DateTime('Now')); + + $form = $this->createForm(PersonDocumentType::class, $document, array( + 'center' => $document->getCenter(), + 'role' => new Role('CHILL_PERSON_DOCUMENT_CREATE') + )); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_DOCUMENT_CREATE', $document, + 'creation of this activity not allowed'); + + $em = $this->getDoctrine()->getManager(); + $em->persist($document); + $em->flush(); + + return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]); + } + + return $this->render('ChillDocStoreBundle:PersonDocument:new.html.twig', [ + 'document' => $document, + 'form' => $form->createView(), + 'person' => $person, + ]); + } + + /** + * @Route("/{id}", name="person_document_show", methods="GET") + */ + public function show(Person $person, PersonDocument $document): Response + { + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_SEE', $document); + + return $this->render( + 'ChillDocStoreBundle:PersonDocument:show.html.twig', + ['document' => $document, 'person' => $person]); + } + + /** + * @Route("/{id}/edit", name="person_document_edit", methods="GET|POST") + */ + public function edit(Request $request, Person $person, PersonDocument $document): Response + { + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_UPDATE', $document); + + $user = $this->get('security.context')->getToken()->getUser(); + $document->setUser($user); + $document->setDate(new \DateTime('Now')); + + $form = $this->createForm( + PersonDocumentType::class, $document, array( + 'center' => $document->getCenter(), + 'role' => new Role('CHILL_PERSON_DOCUMENT_UPDATE'), + )); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->getDoctrine()->getManager()->flush(); + + return $this->redirectToRoute( + 'person_document_edit', + ['id' => $document->getId(), 'person' => $person->getId()]); + } + + return $this->render( + 'ChillDocStoreBundle:PersonDocument:edit.html.twig', + [ + 'document' => $document, + 'form' => $form->createView(), + 'person' => $person, + ]); + } + + /** + * @Route("/{id}", name="person_document_delete", methods="DELETE") + */ + public function delete(Request $request, Person $person, PersonDocument $document): Response + { + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_DELETE', $document); + + if ($this->isCsrfTokenValid('delete'.$document->getId(), $request->request->get('_token'))) { + $em = $this->getDoctrine()->getManager(); + $em->remove($document); + $em->flush(); + } + + return $this->redirectToRoute( + 'person_document_index', ['person' => $person->getId()]); + } +} diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php new file mode 100644 index 000000000..a41e10f7d --- /dev/null +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -0,0 +1,28 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php new file mode 100644 index 000000000..162f6ce99 --- /dev/null +++ b/DependencyInjection/Configuration.php @@ -0,0 +1,29 @@ +root('chill_doc_store'); + + // Here you should define the parameters that are allowed to + // configure your bundle. See the documentation linked above for + // more information on that topic. + + return $treeBuilder; + } +} diff --git a/Entity/Document.php b/Entity/Document.php new file mode 100644 index 000000000..c1724fd4b --- /dev/null +++ b/Entity/Document.php @@ -0,0 +1,160 @@ +id; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function setTitle(string $title): self + { + $this->title = $title; + + return $this; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(string $description): self + { + $this->description = $description; + + return $this; + } + + /** + * @return DocumentCategory + */ + public function getCategory(): ?DocumentCategory + { + return $this->category; + } + + public function setCategory(DocumentCategory $category): self + { + $this->category = $category; + + return $this; + } + + public function getContent(): ?string + { + return $this->content; + } + + public function setContent(string $content): self + { + $this->content = $content; + + return $this; + } + + /** + * Get scope + * + * @return \Chill\MainBundle\Entity\Scope + */ + public function getScope() + { + return $this->scope; + } + + public function setScope($scope): self + { + $this->scope = $scope; + + return $this; + } + + public function getUser() + { + return $this->user; + } + + public function setUser($user): self + { + $this->user = $user; + + return $this; + } + + public function getDate(): ?\DateTimeInterface + { + return $this->date; + } + + public function setDate(\DateTimeInterface $date): self + { + $this->date = $date; + + return $this; + } +} diff --git a/Entity/DocumentCategory.php b/Entity/DocumentCategory.php new file mode 100644 index 000000000..82fe30984 --- /dev/null +++ b/Entity/DocumentCategory.php @@ -0,0 +1,98 @@ +bundleId; + } + + public function setBundleId($bundleId) + { + $this->bundleId = $bundleId; + } + + public function getIdInsideBundle() + { + return $this->idInsideBundle; + } + + public function setIdInsideBundle($idInsideBundle): self + { + $this->idInsideBundle = $idInsideBundle; + + return $this; + } + + public function getDocumentClass() + { + return $this->documentClass; + } + + public function setDocumentClass($documentClass): self + { + $this->documentClass = $documentClass; + + return $this; + } + + public function getName($locale = null) + { + if ($locale) { + if (isset($this->name[$locale])) { + return $this->name[$locale]; + } else { + foreach ($this->name as $name) { + if (!empty($name)) { + return $name; + } + } + } + return ''; + } else { + return $this->name; + } + } + + public function setName($name): self + { + $this->name = $name; + + return $this; + } +} diff --git a/Entity/PersonDocument.php b/Entity/PersonDocument.php new file mode 100644 index 000000000..a0aefbb10 --- /dev/null +++ b/Entity/PersonDocument.php @@ -0,0 +1,45 @@ +person; + } + + public function setPerson($person): self + { + $this->person = $person; + + return $this; + } + + public function getCenter() + { + return $this->getPerson()->getCenter(); + } +} diff --git a/EntityRepository/DocumentCategoryRepository.php b/EntityRepository/DocumentCategoryRepository.php new file mode 100644 index 000000000..d803405e4 --- /dev/null +++ b/EntityRepository/DocumentCategoryRepository.php @@ -0,0 +1,39 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\DocStoreBundle\EntityRepository; + +use Doctrine\ORM\EntityRepository; +use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; + +/** + * Get an available idInsideBUndle + */ +class DocumentCategoryRepository extends EntityRepository +{ + public function nextIdInsideBundle() + { + $array_res = $this->getEntityManager() + ->createQuery( + 'SELECT MAX(c.idInsideBundle) + 1 FROM ChillDocStoreBundle:DocumentCategory c') + ->getSingleResult(); + + return $array_res[1] ?: 0; + } +} diff --git a/Form/DocumentCategoryType.php b/Form/DocumentCategoryType.php new file mode 100644 index 000000000..9a3f75d8f --- /dev/null +++ b/Form/DocumentCategoryType.php @@ -0,0 +1,50 @@ + $value) { + if(substr($key, 0, 5) === 'Chill') { + $this->chillBundlesFlipped[$value] = $key; + } + } + } + + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('bundleId', ChoiceType::class, array( + 'choices' => $this->chillBundlesFlipped, + 'disabled' => true, + )) + ->add('idInsideBundle', null, array( + 'disabled' => true, + )) + ->add('documentClass', null, array( + 'disabled' => true, + )) // cahcerh par default PersonDocument + ->add('name', TranslatableStringFormType::class) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => DocumentCategory::class, + ]); + } +} diff --git a/Form/PersonDocumentType.php b/Form/PersonDocumentType.php new file mode 100644 index 000000000..b9d68693e --- /dev/null +++ b/Form/PersonDocumentType.php @@ -0,0 +1,104 @@ +getToken()->getUser() instanceof User) { + throw new \RuntimeException("you should have a valid user"); + } + $this->user = $tokenStorage->getToken()->getUser(); + $this->authorizationHelper = $authorizationHelper; + $this->om = $om; + $this->translatableStringHelper = $translatableStringHelper; + } + + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('title') + ->add('description') + ->add('content') + //->add('center') + ->add('scope') + ->add('date', 'date', array('required' => false, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy')) + ->add('category', EntityType::class, array( + 'class' => 'ChillDocStoreBundle:DocumentCategory', + 'query_builder' => function (EntityRepository $er) { + return $er->createQueryBuilder('c') + ->where('c.documentClass = :docClass') + ->setParameter('docClass', PersonDocument::class); + }, + 'choice_label' => function ($entity = null) { + return $entity ? $this->translatableStringHelper->localize($entity->getName()) : ''; + }, + )) + ; + + $this->appendScopeChoices($builder, $options['role'], + $options['center'], $this->user, $this->authorizationHelper, + $this->translatableStringHelper, $this->om); + + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Document::class, + ]); + + $this->appendScopeChoicesOptions($resolver); + } +} diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml new file mode 100644 index 000000000..c02dc76ab --- /dev/null +++ b/Resources/config/routing.yml @@ -0,0 +1,3 @@ +app: + resource: "@ChillDocStoreBundle/Controller/" + type: annotation diff --git a/Resources/config/services.yml b/Resources/config/services.yml new file mode 100644 index 000000000..e8e185fa9 --- /dev/null +++ b/Resources/config/services.yml @@ -0,0 +1,27 @@ +parameters: +# cl_chill_person.example.class: Chill\PersonBundle\Example + +services: + 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: + - "@security.token_storage" + - "@chill.main.security.authorization.helper" + - "@doctrine.orm.entity_manager" + - "@chill.main.helper.translatable_string" + tags: + - { name: form.type, alias: chill_docstorebundle_form_document } + + Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter: + class: Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter + arguments: + - "@chill.main.security.authorization.helper" + tags: + - { name: security.voter } + - { name: chill.role } diff --git a/Resources/migrations/Version20180322123800.php b/Resources/migrations/Version20180322123800.php new file mode 100644 index 000000000..dc77d78c5 --- /dev/null +++ b/Resources/migrations/Version20180322123800.php @@ -0,0 +1,45 @@ +addSql("CREATE SEQUENCE PersonDocument_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); + $this->addSql("CREATE TABLE DocumentCategory (bundle_id VARCHAR(255) NOT NULL, id_inside_bundle INT NOT NULL, name JSON NOT NULL, document_class VARCHAR(255) NOT NULL, PRIMARY KEY(bundle_id, id_inside_bundle));"); + $this->addSql("COMMENT ON COLUMN DocumentCategory.name IS '(DC2Type:json_array)';"); + $this->addSql("CREATE TABLE PersonDocument (id INT NOT NULL, category_bundle_id VARCHAR(255) DEFAULT NULL, category_id_inside_bundle INT DEFAULT NULL, scope_id INT DEFAULT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, title TEXT NOT NULL, description TEXT NOT NULL, content TEXT NOT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id));"); + $this->addSql("CREATE INDEX IDX_BAADC20C369A0BE36EF62EFC ON PersonDocument (category_bundle_id, category_id_inside_bundle);"); + $this->addSql("CREATE INDEX IDX_BAADC20C682B5931 ON PersonDocument (scope_id);"); + $this->addSql("CREATE INDEX IDX_BAADC20CA76ED395 ON PersonDocument (user_id);"); + $this->addSql("CREATE INDEX IDX_BAADC20C217BBB47 ON PersonDocument (person_id);"); + $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C369A0BE36EF62EFC FOREIGN KEY (category_bundle_id, category_id_inside_bundle) REFERENCES DocumentCategory (bundle_id, id_inside_bundle) NOT DEFERRABLE INITIALLY IMMEDIATE;"); + $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); + $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20CA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); + $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C369A0BE36EF62EFC"); + $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C682B5931"); + $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20CA76ED395"); + $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C217BBB47"); + $this->addSql("DROP TABLE DocumentCategory;"); + $this->addSql("DROP TABLE PersonDocument;"); + $this->addSql("DROP SEQUENCE PersonDocument_id_seq;"); + } +} diff --git a/Resources/views/DocumentCategory/_delete_form.html.twig b/Resources/views/DocumentCategory/_delete_form.html.twig new file mode 100644 index 000000000..5d77512dd --- /dev/null +++ b/Resources/views/DocumentCategory/_delete_form.html.twig @@ -0,0 +1,21 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +
+ + + +
diff --git a/Resources/views/DocumentCategory/_form.html.twig b/Resources/views/DocumentCategory/_form.html.twig new file mode 100644 index 000000000..e2a0a004d --- /dev/null +++ b/Resources/views/DocumentCategory/_form.html.twig @@ -0,0 +1,20 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{{ form_start(form) }} + {{ form_widget(form) }} + +{{ form_end(form) }} diff --git a/Resources/views/DocumentCategory/edit.html.twig b/Resources/views/DocumentCategory/edit.html.twig new file mode 100644 index 000000000..68c74a29d --- /dev/null +++ b/Resources/views/DocumentCategory/edit.html.twig @@ -0,0 +1,31 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillMainBundle::Admin/layout.html.twig" %} + +{% block title %}{{ 'Document category edit'|trans }}{% endblock title %} + +{% block admin_content %} +

{{ 'Document category edit'|trans }}

+ + {{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig', {'button_label': 'Update'}) }} + + + {{ 'Back to the category list' | trans }} + + + {{ include('ChillDocStoreBundle:DocumentCategory:_delete_form.html.twig') }} +{% endblock %} diff --git a/Resources/views/DocumentCategory/index.html.twig b/Resources/views/DocumentCategory/index.html.twig new file mode 100644 index 000000000..3aaa7fcf0 --- /dev/null +++ b/Resources/views/DocumentCategory/index.html.twig @@ -0,0 +1,60 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillMainBundle::Admin/layout.html.twig" %} + +{% block title %}{{ 'Document category list' | trans }}{% endblock title %} + +{% block admin_content %} +

{{ 'Document category list' | trans }}

+ + + + + + + + + + + + + {% for document_category in document_categories %} + + + + + + + + + {% else %} + + + + {% endfor %} + +
{{ 'Creator bundle id' | trans }}{{ 'Internal id inside creator bundle' | trans }}{{ 'Document class' | trans }}{{ 'Name' | trans }}{{ 'Actions' | trans }}
{{ document_category.bundleId }}{{ document_category.idInsideBundle }}{{ document_category.documentClass }}{{ document_category.name | localize_translatable_string}} + + {{ 'show' | trans }} + + + {{ 'edit' | trans }} + +
{{ 'no records found' | trans }}
+ + {{ 'Create new' | trans }} +{% endblock %} diff --git a/Resources/views/DocumentCategory/new.html.twig b/Resources/views/DocumentCategory/new.html.twig new file mode 100644 index 000000000..a87d42585 --- /dev/null +++ b/Resources/views/DocumentCategory/new.html.twig @@ -0,0 +1,29 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillMainBundle::Admin/layout.html.twig" %} + +{% block title %}{{ 'Create new document category' | trans }}{% endblock title %} + +{% block admin_content %} +

{{ 'Create new DocumentCategory' | trans }}

+ + {{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig') }} + + + {{ 'Back to the category list' | trans }} + +{% endblock %} diff --git a/Resources/views/DocumentCategory/show.html.twig b/Resources/views/DocumentCategory/show.html.twig new file mode 100644 index 000000000..cf323781d --- /dev/null +++ b/Resources/views/DocumentCategory/show.html.twig @@ -0,0 +1,54 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillMainBundle::Admin/layout.html.twig" %} + +{% block title %}{{ 'Document category show'|trans }}{% endblock title %} + +{% block admin_content %} +

Document category

+ + + + + + + + + + + + + + + + + + + + +
{{ 'Creator bundle id' | trans }}{{ document_category.bundleId }}
{{ 'Internal id inside creator bundle' | trans }}{{ document_category.idInsideBundle }}
{{ 'Document class' | trans }}{{ document_category.documentClass }}
{{ 'Name' | trans }}{{ document_category.name | localize_translatable_string }}
+ + + {{ 'Back to the category list' | trans }} + + + + {{ 'Edit' | trans }} + + + {{ include('ChillDocStoreBundle:DocumentCategory:_delete_form.html.twig') }} +{% endblock %} diff --git a/Resources/views/PersonDocument/_delete_form.html.twig b/Resources/views/PersonDocument/_delete_form.html.twig new file mode 100644 index 000000000..80ae22935 --- /dev/null +++ b/Resources/views/PersonDocument/_delete_form.html.twig @@ -0,0 +1,5 @@ +
+ + + +
diff --git a/Resources/views/PersonDocument/_form.html.twig b/Resources/views/PersonDocument/_form.html.twig new file mode 100644 index 000000000..56f80b630 --- /dev/null +++ b/Resources/views/PersonDocument/_form.html.twig @@ -0,0 +1,4 @@ +{{ form_start(form) }} + {{ form_widget(form) }} + +{{ form_end(form) }} diff --git a/Resources/views/PersonDocument/edit.html.twig b/Resources/views/PersonDocument/edit.html.twig new file mode 100644 index 000000000..db39eca56 --- /dev/null +++ b/Resources/views/PersonDocument/edit.html.twig @@ -0,0 +1,33 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} + +{% extends "ChillPersonBundle::layout.html.twig" %} + +{% set activeRouteKey = '' %} + +{% block title %}{{ 'Editing document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} +{% block personcontent %} +

{{ 'Edit Document' | trans }}

+ + {{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig', {'button_label': 'Update'}) }} + + + {{ 'Back to list' | trans }} + + + {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} +{% endblock %} diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig new file mode 100644 index 000000000..acedd7175 --- /dev/null +++ b/Resources/views/PersonDocument/index.html.twig @@ -0,0 +1,66 @@ +{# + * Copyright (C) 2018, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} + +{% extends "ChillPersonBundle::layout.html.twig" %} + +{% set activeRouteKey = '' %} + +{% block title %}{{ 'Documents for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} + +{% block personcontent %} +

{{ 'Document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}

+ + + + + + + + + + + + + + {% for document in documents %} + + + + + + + + + {% else %} + + + + {% endfor %} + +
{{ 'Title' | trans }}{{ 'Description' | trans }}{{ 'Content' | trans }}{{ 'Last modification by' | trans }}{{ 'Last update' | trans }}{{ 'Actions' | trans }}
{{ document.title }}{{ document.description }}{{ document.content }}{{ document.user }}{{ document.date ? document.date|date('Y-m-d H:i:s') : '' }} + + show + + + edit + +
no records found
+ + + {{ 'Create new' | trans }} + +{% endblock %} diff --git a/Resources/views/PersonDocument/new.html.twig b/Resources/views/PersonDocument/new.html.twig new file mode 100644 index 000000000..2a423051d --- /dev/null +++ b/Resources/views/PersonDocument/new.html.twig @@ -0,0 +1,31 @@ +{# + * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillPersonBundle::layout.html.twig" %} + +{% set activeRouteKey = '' %} + +{% block title %}{{ 'New document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} + +{% block personcontent %} +

{{ 'Create new Document' | trans }}

+ + {{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig') }} + + + {{ 'back to list' | trans }} + +{% endblock %} diff --git a/Resources/views/PersonDocument/show.html.twig b/Resources/views/PersonDocument/show.html.twig new file mode 100644 index 000000000..c5b42345e --- /dev/null +++ b/Resources/views/PersonDocument/show.html.twig @@ -0,0 +1,68 @@ +{# + * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillPersonBundle::layout.html.twig" %} + +{% set activeRouteKey = '' %} + +{% block title %}{{ 'Detail of document of %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} + +{% block personcontent %} +

{{ 'Document' | trans }}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ 'Title' | trans }}{{ document.title }}
{{ 'Description' | trans }}{{ document.description }}
{{ 'Content' | trans }}{{ document.content }}
{{ 'Center' | trans}}{{ document.center }}
{{ 'Scope' | trans }}{{ document.scope.name | localize_translatable_string }}
{{ 'Last modificiation by' | trans }}{{ document.user }}
{{ 'Last update' | trans }}{{ document.date ? document.date|date('Y-m-d H:i:s') : '' }}
+ + + {{ 'Back to list' | trans }} + + + + {{ 'Edit' | trans }} + + + {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} +{% endblock %} diff --git a/Security/Authorization/PersonDocumentVoter.php b/Security/Authorization/PersonDocumentVoter.php new file mode 100644 index 000000000..55302b77c --- /dev/null +++ b/Security/Authorization/PersonDocumentVoter.php @@ -0,0 +1,83 @@ +. + */ + +namespace Chill\DocStoreBundle\Security\Authorization; + +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\ProvideRoleInterface; + +/** + * + */ +class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleInterface +{ + const CREATE = 'CHILL_PERSON_DOCUMENT_CREATE'; + const SEE = 'CHILL_PERSON_DOCUMENT_SEE'; + const SEE_DETAILS = 'CHILL_PERSON_DOCUMENT_SEE_DETAILS'; + const UPDATE = 'CHILL_PERSON_DOCUMENT_UPDATE'; + const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE'; + + /** + * + * @var AuthorizationHelper + */ + protected $helper; + + public function __construct(AuthorizationHelper $helper) + { + $this->helper = $helper; + } + + protected function getSupportedAttributes() + { + return array(self::CREATE, self::SEE, self::UPDATE, self::DELETE, + self::SEE_DETAILS); + } + + protected function getSupportedClasses() + { + return array('Chill\DocStoreBundle\Entity\PersonDocument'); + } + + protected function isGranted($attribute, $report, $user = null) + { + if (! $user instanceof \Chill\MainBundle\Entity\User){ + return false; + } + + return $this->helper->userHasAccess($user, $report, $attribute); + } + + public function getRoles() + { + return $this->getSupportedAttributes(); + } + + public function getRolesWithoutScope() + { + return array(); + } + + + public function getRolesWithHierarchy() + { + return ['PersonDocument' => $this->getRoles() ]; + } +} From 2dc4f6a3b0ad8e2b03bcd425fe7103cb721c0129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 5 Jun 2018 10:27:14 +0200 Subject: [PATCH 02/58] add composer.json file --- .gitignore | 1 + composer.json | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..57872d0f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/composer.json b/composer.json new file mode 100644 index 000000000..0d6b8de9d --- /dev/null +++ b/composer.json @@ -0,0 +1,10 @@ +{ + "name": "chill-project/chill-doc-store", + "description": "A Chill bundle to store documents", + "type": "symfony-bundle", + "require": { + "chill-project/main": "upgrade-sf3", + "chill-project/person": "upgrade-sf3" + }, + "license": "AGPL-3.0" +} From 3e40bebf45caf4e1b39a9cb6b1ffb22dc1fb869c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 5 Jun 2018 11:38:33 +0200 Subject: [PATCH 03/58] fix error in branch version --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0d6b8de9d..7134bcc1e 100644 --- a/composer.json +++ b/composer.json @@ -3,8 +3,8 @@ "description": "A Chill bundle to store documents", "type": "symfony-bundle", "require": { - "chill-project/main": "upgrade-sf3", - "chill-project/person": "upgrade-sf3" + "chill-project/main": "dev-upgrade-sf3@dev", + "chill-project/person": "dev-upgrade-sf3@dev" }, "license": "AGPL-3.0" } From 205769bf6bee6d82409edf88176f483cda3d2a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 5 Jun 2018 12:01:47 +0200 Subject: [PATCH 04/58] add namespace --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 7134bcc1e..0fc56a5bf 100644 --- a/composer.json +++ b/composer.json @@ -2,6 +2,9 @@ "name": "chill-project/chill-doc-store", "description": "A Chill bundle to store documents", "type": "symfony-bundle", + "autoload": { + "psr-4": { "Chill\\DocStoreBundle\\" : "" } + }, "require": { "chill-project/main": "dev-upgrade-sf3@dev", "chill-project/person": "dev-upgrade-sf3@dev" From f8b7533e18d1e333e556580f42b40ab8f58d52e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 5 Jun 2018 12:06:55 +0200 Subject: [PATCH 05/58] move table to schema and remove old migration file --- Entity/DocumentCategory.php | 1 + Entity/PersonDocument.php | 1 + .../migrations/Version20180322123800.php | 45 ------------------- 3 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 Resources/migrations/Version20180322123800.php diff --git a/Entity/DocumentCategory.php b/Entity/DocumentCategory.php index 82fe30984..29d02efb4 100644 --- a/Entity/DocumentCategory.php +++ b/Entity/DocumentCategory.php @@ -7,6 +7,7 @@ use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** + * @ORM\Table("chill_doc.document_category") * @ORM\Entity(repositoryClass="Chill\DocStoreBundle\EntityRepository\DocumentCategoryRepository") */ class DocumentCategory diff --git a/Entity/PersonDocument.php b/Entity/PersonDocument.php index a0aefbb10..b38023ddb 100644 --- a/Entity/PersonDocument.php +++ b/Entity/PersonDocument.php @@ -11,6 +11,7 @@ use Chill\PersonBundle\Entity\Person; /** + * @ORM\Table("chill_doc.person_document") * @ORM\Entity() */ class PersonDocument extends Document implements HasCenterInterface, HasScopeInterface diff --git a/Resources/migrations/Version20180322123800.php b/Resources/migrations/Version20180322123800.php deleted file mode 100644 index dc77d78c5..000000000 --- a/Resources/migrations/Version20180322123800.php +++ /dev/null @@ -1,45 +0,0 @@ -addSql("CREATE SEQUENCE PersonDocument_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE TABLE DocumentCategory (bundle_id VARCHAR(255) NOT NULL, id_inside_bundle INT NOT NULL, name JSON NOT NULL, document_class VARCHAR(255) NOT NULL, PRIMARY KEY(bundle_id, id_inside_bundle));"); - $this->addSql("COMMENT ON COLUMN DocumentCategory.name IS '(DC2Type:json_array)';"); - $this->addSql("CREATE TABLE PersonDocument (id INT NOT NULL, category_bundle_id VARCHAR(255) DEFAULT NULL, category_id_inside_bundle INT DEFAULT NULL, scope_id INT DEFAULT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, title TEXT NOT NULL, description TEXT NOT NULL, content TEXT NOT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_BAADC20C369A0BE36EF62EFC ON PersonDocument (category_bundle_id, category_id_inside_bundle);"); - $this->addSql("CREATE INDEX IDX_BAADC20C682B5931 ON PersonDocument (scope_id);"); - $this->addSql("CREATE INDEX IDX_BAADC20CA76ED395 ON PersonDocument (user_id);"); - $this->addSql("CREATE INDEX IDX_BAADC20C217BBB47 ON PersonDocument (person_id);"); - $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C369A0BE36EF62EFC FOREIGN KEY (category_bundle_id, category_id_inside_bundle) REFERENCES DocumentCategory (bundle_id, id_inside_bundle) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20CA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - } - - /** - * @param Schema $schema - */ - public function down(Schema $schema) - { - $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C369A0BE36EF62EFC"); - $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C682B5931"); - $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20CA76ED395"); - $this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C217BBB47"); - $this->addSql("DROP TABLE DocumentCategory;"); - $this->addSql("DROP TABLE PersonDocument;"); - $this->addSql("DROP SEQUENCE PersonDocument_id_seq;"); - } -} From a1ee85b0c0f75fa1770392fdc924c868eafedd79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 5 Jun 2018 12:36:14 +0200 Subject: [PATCH 06/58] Load routes automatically --- .../ChillDocStoreExtension.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index a41e10f7d..167b6aa75 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -6,13 +6,14 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; /** * This is the class that loads and manages your bundle configuration * * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} */ -class ChillDocStoreExtension extends Extension +class ChillDocStoreExtension extends Extension implements PrependExtensionInterface { /** * {@inheritdoc} @@ -25,4 +26,21 @@ class ChillDocStoreExtension extends Extension $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); } + + public function prepend(ContainerBuilder $container) + { + $this->prependRoute($container); + } + + protected function prependRoute(ContainerBuilder $container) + { + //declare routes for task bundle + $container->prependExtensionConfig('chill_main', array( + 'routing' => array( + 'resources' => array( + '@ChillDocStoreBundle/Resources/config/routing.yml' + ) + ) + )); + } } From eda8f2c0331218e53030a108a552c450f7d52f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 5 Jun 2018 14:53:30 +0200 Subject: [PATCH 07/58] improve CRUD and switch to symfony3 --- Controller/DocumentPersonController.php | 14 +++--- .../ChillDocStoreExtension.php | 14 ++++++ Entity/Document.php | 6 +-- Form/PersonDocumentType.php | 40 +++++++--------- Resources/config/services.yml | 3 -- .../migrations/Version20180605102533.php | 39 +++++++++++++++ .../views/PersonDocument/_form.html.twig | 5 +- Resources/views/PersonDocument/edit.html.twig | 23 +++++++-- .../views/PersonDocument/index.html.twig | 48 ++++++++++++------- Resources/views/PersonDocument/new.html.twig | 15 ++++-- .../Authorization/PersonDocumentVoter.php | 38 +++++++++------ 11 files changed, 167 insertions(+), 78 deletions(-) create mode 100644 Resources/migrations/Version20180605102533.php diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php index 5a5464f2c..56b6feb91 100644 --- a/Controller/DocumentPersonController.php +++ b/Controller/DocumentPersonController.php @@ -11,6 +11,8 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Chill\PersonBundle\Entity\Person; use Symfony\Component\Security\Core\Role\Role; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; /** * @Route("/{_locale}/person/{person}/document") @@ -30,11 +32,11 @@ class DocumentPersonController extends Controller throw $this->createNotFoundException('Person not found'); } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); $reachableScopes = $this->get('chill.main.security.authorization.helper') ->getReachableScopes( - $this->getUser(), new Role('CHILL_PERSON_DOCUMENT_SEE'), + $this->getUser(), new Role(PersonDocumentVoter::SEE), $person->getCenter()); $documents = $em @@ -61,11 +63,10 @@ class DocumentPersonController extends Controller throw $this->createNotFoundException('person not found'); } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); - $user = $this->get('security.context')->getToken()->getUser(); $document = new PersonDocument(); - $document->setUser($user); + $document->setUser($this->getUser()); $document->setPerson($person); $document->setDate(new \DateTime('Now')); @@ -115,8 +116,7 @@ class DocumentPersonController extends Controller $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_UPDATE', $document); - $user = $this->get('security.context')->getToken()->getUser(); - $document->setUser($user); + $document->setUser($this->getUser()); $document->setDate(new \DateTime('Now')); $form = $this->createForm( diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index 167b6aa75..62ab5b480 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -7,6 +7,7 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; +use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; /** * This is the class that loads and manages your bundle configuration @@ -30,6 +31,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf public function prepend(ContainerBuilder $container) { $this->prependRoute($container); + $this->prependAuthorization($container); } protected function prependRoute(ContainerBuilder $container) @@ -43,4 +45,16 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf ) )); } + + protected function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', array( + 'role_hierarchy' => array( + PersonDocumentVoter::UPDATE => [PersonDocumentVoter::SEE_DETAILS], + PersonDocumentVoter::CREATE => [PersonDocumentVoter::SEE_DETAILS], + PersonDocumentVoter::DELETE => [PersonDocumentVoter::SEE_DETAILS], + PersonDocumentVoter::SEE_DETAILS => [PersonDocumentVoter::SEE], + ) + )); + } } diff --git a/Entity/Document.php b/Entity/Document.php index c1724fd4b..cbabcf850 100644 --- a/Entity/Document.php +++ b/Entity/Document.php @@ -28,7 +28,7 @@ class Document implements HasScopeInterface /** * @ORM\Column(type="text") */ - private $description; + private $description = ''; /** * @ORM\ManyToOne(targetEntity="Chill\DocStoreBundle\Entity\DocumentCategory") @@ -83,9 +83,9 @@ class Document implements HasScopeInterface return $this->description; } - public function setDescription(string $description): self + public function setDescription($description): self { - $this->description = $description; + $this->description = (string) $description; return $this; } diff --git a/Form/PersonDocumentType.php b/Form/PersonDocumentType.php index b9d68693e..28cc582f5 100644 --- a/Form/PersonDocumentType.php +++ b/Form/PersonDocumentType.php @@ -17,12 +17,14 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInt use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Doctrine\Common\Persistence\ObjectManager; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\ScopePickerType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; class PersonDocumentType extends AbstractType { - use AppendScopeChoiceTypeTrait; - /** * the user running this form * @@ -49,18 +51,9 @@ class PersonDocumentType extends AbstractType protected $translatableStringHelper; public function __construct( - TokenStorageInterface $tokenStorage, - AuthorizationHelper $authorizationHelper, - ObjectManager $om, TranslatableStringHelper $translatableStringHelper ) { - if (!$tokenStorage->getToken()->getUser() instanceof User) { - throw new \RuntimeException("you should have a valid user"); - } - $this->user = $tokenStorage->getToken()->getUser(); - $this->authorizationHelper = $authorizationHelper; - $this->om = $om; $this->translatableStringHelper = $translatableStringHelper; } @@ -68,12 +61,16 @@ class PersonDocumentType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('title') - ->add('description') + ->add('title', TextType::class) + ->add('description', TextareaType::class, [ + 'required' => false + ]) ->add('content') - //->add('center') - ->add('scope') - ->add('date', 'date', array('required' => false, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy')) + ->add('scope', ScopePickerType::class, [ + 'center' => $options['center'], + 'role' => $options['role'] + ]) + ->add('date', ChillDateType::class) ->add('category', EntityType::class, array( 'class' => 'ChillDocStoreBundle:DocumentCategory', 'query_builder' => function (EntityRepository $er) { @@ -87,10 +84,6 @@ class PersonDocumentType extends AbstractType )) ; - $this->appendScopeChoices($builder, $options['role'], - $options['center'], $this->user, $this->authorizationHelper, - $this->translatableStringHelper, $this->om); - } public function configureOptions(OptionsResolver $resolver) @@ -98,7 +91,10 @@ class PersonDocumentType extends AbstractType $resolver->setDefaults([ 'data_class' => Document::class, ]); - - $this->appendScopeChoicesOptions($resolver); + + $resolver->setRequired(['role', 'center']) + ->setAllowedTypes('role', [ \Symfony\Component\Security\Core\Role\Role::class ]) + ->setAllowedTypes('center', [ \Chill\MainBundle\Entity\Center::class ]) + ; } } diff --git a/Resources/config/services.yml b/Resources/config/services.yml index e8e185fa9..4439c8dbb 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -11,9 +11,6 @@ services: Chill\DocStoreBundle\Form\PersonDocumentType: class: Chill\DocStoreBundle\Form\PersonDocumentType arguments: - - "@security.token_storage" - - "@chill.main.security.authorization.helper" - - "@doctrine.orm.entity_manager" - "@chill.main.helper.translatable_string" tags: - { name: form.type, alias: chill_docstorebundle_form_document } diff --git a/Resources/migrations/Version20180605102533.php b/Resources/migrations/Version20180605102533.php new file mode 100644 index 000000000..5661277e2 --- /dev/null +++ b/Resources/migrations/Version20180605102533.php @@ -0,0 +1,39 @@ +abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE SCHEMA chill_doc'); + $this->addSql('CREATE SEQUENCE chill_doc.person_document_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_doc.document_category (bundle_id VARCHAR(255) NOT NULL, id_inside_bundle INT NOT NULL, document_class VARCHAR(255) NOT NULL, name JSON NOT NULL, PRIMARY KEY(bundle_id, id_inside_bundle))'); + $this->addSql('COMMENT ON COLUMN chill_doc.document_category.name IS \'(DC2Type:json_array)\''); + $this->addSql('CREATE TABLE chill_doc.person_document (id INT NOT NULL, category_bundle_id VARCHAR(255) DEFAULT NULL, category_id_inside_bundle INT DEFAULT NULL, scope_id INT DEFAULT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, title TEXT NOT NULL, description TEXT NOT NULL, content TEXT NOT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_41DA53C369A0BE36EF62EFC ON chill_doc.person_document (category_bundle_id, category_id_inside_bundle)'); + $this->addSql('CREATE INDEX IDX_41DA53C682B5931 ON chill_doc.person_document (scope_id)'); + $this->addSql('CREATE INDEX IDX_41DA53CA76ED395 ON chill_doc.person_document (user_id)'); + $this->addSql('CREATE INDEX IDX_41DA53C217BBB47 ON chill_doc.person_document (person_id)'); + $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C369A0BE36EF62EFC FOREIGN KEY (category_bundle_id, category_id_inside_bundle) REFERENCES chill_doc.document_category (bundle_id, id_inside_bundle) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53CA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema) : void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP SCHEMA chill_doc CASCADE'); + + } +} diff --git a/Resources/views/PersonDocument/_form.html.twig b/Resources/views/PersonDocument/_form.html.twig index 56f80b630..d5e483e36 100644 --- a/Resources/views/PersonDocument/_form.html.twig +++ b/Resources/views/PersonDocument/_form.html.twig @@ -1,4 +1 @@ -{{ form_start(form) }} - {{ form_widget(form) }} - -{{ form_end(form) }} +{{ form_widget(form) }} diff --git a/Resources/views/PersonDocument/edit.html.twig b/Resources/views/PersonDocument/edit.html.twig index db39eca56..a81705328 100644 --- a/Resources/views/PersonDocument/edit.html.twig +++ b/Resources/views/PersonDocument/edit.html.twig @@ -23,11 +23,26 @@ {% block personcontent %}

{{ 'Edit Document' | trans }}

+ {{ form_start(form) }} {{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig', {'button_label': 'Update'}) }} - - {{ 'Back to list' | trans }} - +
    +
  • + + {{ 'Back to the list' | trans }} + +
  • +
  • + +
  • + {% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %} +
  • + {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} +
  • + {% endif %} +
+ + {{ form_end(form) }} + - {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} {% endblock %} diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig index acedd7175..50cd0579a 100644 --- a/Resources/views/PersonDocument/index.html.twig +++ b/Resources/views/PersonDocument/index.html.twig @@ -28,10 +28,8 @@ {{ 'Title' | trans }} - {{ 'Description' | trans }} - {{ 'Content' | trans }} - {{ 'Last modification by' | trans }} - {{ 'Last update' | trans }} + {{ 'Category'|trans }} + {{ 'Circle' | trans }} {{ 'Actions' | trans }} @@ -39,28 +37,42 @@ {% for document in documents %} {{ document.title }} - {{ document.description }} - {{ document.content }} - {{ document.user }} - {{ document.date ? document.date|date('Y-m-d H:i:s') : '' }} + {{ document.category.name|localize_translatable_string }} + {{ document.scope.name|localize_translatable_string }} - - show - - - edit - + {% else %} - no records found + {{ 'Any document found'|trans }} {% endfor %} - - {{ 'Create new' | trans }} - + {% if is_granted('CHILL_PERSON_DOCUMENT_CREATE', person) %} + + {% endif %} {% endblock %} diff --git a/Resources/views/PersonDocument/new.html.twig b/Resources/views/PersonDocument/new.html.twig index 2a423051d..0e7ee778e 100644 --- a/Resources/views/PersonDocument/new.html.twig +++ b/Resources/views/PersonDocument/new.html.twig @@ -23,9 +23,18 @@ {% block personcontent %}

{{ 'Create new Document' | trans }}

+ {{ form_start(form) }} {{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig') }} - - {{ 'back to list' | trans }} - + + {{ form_end(form) }} {% endblock %} diff --git a/Security/Authorization/PersonDocumentVoter.php b/Security/Authorization/PersonDocumentVoter.php index 55302b77c..47bfed38b 100644 --- a/Security/Authorization/PersonDocumentVoter.php +++ b/Security/Authorization/PersonDocumentVoter.php @@ -21,12 +21,14 @@ namespace Chill\DocStoreBundle\Security\Authorization; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\MainBundle\Security\ProvideRoleInterface; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; +use Chill\DocStoreBundle\Entity\PersonDocument; +use Chill\PersonBundle\Entity\Person; /** * */ -class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleInterface +class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { const CREATE = 'CHILL_PERSON_DOCUMENT_CREATE'; const SEE = 'CHILL_PERSON_DOCUMENT_SEE'; @@ -44,16 +46,29 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleInter { $this->helper = $helper; } - - protected function getSupportedAttributes() + + public function getRoles() { - return array(self::CREATE, self::SEE, self::UPDATE, self::DELETE, - self::SEE_DETAILS); + return [ + self::CREATE, + self::SEE, + self::SEE_DETAILS, + self::UPDATE, + self::DELETE + ]; } - - protected function getSupportedClasses() + + protected function supports($attribute, $subject) { - return array('Chill\DocStoreBundle\Entity\PersonDocument'); + if (\in_array($attribute, $this->getRoles()) && $subject instanceof PersonDocument) { + return true; + } + + if ($subject instanceof Person && $attribute === self::CREATE) { + return true; + } + + return false; } protected function isGranted($attribute, $report, $user = null) @@ -65,11 +80,6 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleInter return $this->helper->userHasAccess($user, $report, $attribute); } - public function getRoles() - { - return $this->getSupportedAttributes(); - } - public function getRolesWithoutScope() { return array(); From b5bf8b8884f4592306e9f8b5318206384eeeb8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 6 Jun 2018 22:19:54 +0200 Subject: [PATCH 08/58] upload and retrieve document --- .../ChillDocStoreExtension.php | 14 +- Entity/Document.php | 21 +- Entity/StoredObject.php | 164 ++++++++++++++++ Form/PersonDocumentType.php | 2 +- Form/StoredObjectType.php | 72 +++++++ Object/ObjectToAsyncFileTransformer.php | 53 +++++ Object/PersistenceChecker.php | 40 ++++ Resources/config/services/media.yml | 9 + .../migrations/Version20180606133338.php | 38 ++++ .../public/module/async_upload/downloader.js | 67 +++++++ Resources/public/module/async_upload/index.js | 2 + .../public/module/async_upload/uploader.js | 183 ++++++++++++++++++ Resources/views/Form/fields.html.twig | 7 + Resources/views/Macro/macro.html.twig | 3 + .../views/PersonDocument/index.html.twig | 9 + Resources/views/PersonDocument/new.html.twig | 4 + chill.webpack.config.js | 5 + 17 files changed, 688 insertions(+), 5 deletions(-) create mode 100644 Entity/StoredObject.php create mode 100644 Form/StoredObjectType.php create mode 100644 Object/ObjectToAsyncFileTransformer.php create mode 100644 Object/PersistenceChecker.php create mode 100644 Resources/config/services/media.yml create mode 100644 Resources/migrations/Version20180606133338.php create mode 100644 Resources/public/module/async_upload/downloader.js create mode 100644 Resources/public/module/async_upload/index.js create mode 100644 Resources/public/module/async_upload/uploader.js create mode 100644 Resources/views/Form/fields.html.twig create mode 100644 Resources/views/Macro/macro.html.twig create mode 100644 chill.webpack.config.js diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index 62ab5b480..e57851427 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -26,12 +26,15 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); + $loader->load('services/media.yml'); + } public function prepend(ContainerBuilder $container) { $this->prependRoute($container); $this->prependAuthorization($container); + $this->prependTwig($container); } protected function prependRoute(ContainerBuilder $container) @@ -40,7 +43,8 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $container->prependExtensionConfig('chill_main', array( 'routing' => array( 'resources' => array( - '@ChillDocStoreBundle/Resources/config/routing.yml' + '@ChillDocStoreBundle/Resources/config/routing.yml', + '@ChampsLibresAsyncUploaderBundle/Resources/config/routing.yml' ) ) )); @@ -57,4 +61,12 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf ) )); } + + protected function prependTwig(ContainerBuilder $container) + { + $twigConfig = array( + 'form_themes' => array('@ChillDocStore/Form/fields.html.twig') + ); + $container->prependExtensionConfig('twig', $twigConfig); + } } diff --git a/Entity/Document.php b/Entity/Document.php index cbabcf850..1cfa94d8e 100644 --- a/Entity/Document.php +++ b/Entity/Document.php @@ -40,9 +40,12 @@ class Document implements HasScopeInterface private $category; /** - * @ORM\Column(type="text") + * @ORM\ManyToOne( + * targetEntity="Chill\DocStoreBundle\Entity\StoredObject", + * cascade={"persist"} + * ) */ - private $content; + private $object; /** * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") @@ -65,7 +68,7 @@ class Document implements HasScopeInterface { return $this->id; } - + public function getTitle(): ?string { return $this->title; @@ -157,4 +160,16 @@ class Document implements HasScopeInterface return $this; } + + public function getObject(): ?StoredObject + { + return $this->object; + } + + public function setObject(StoredObject $object) + { + $this->object = $object; + + return $this; + } } diff --git a/Entity/StoredObject.php b/Entity/StoredObject.php new file mode 100644 index 000000000..b89ec3754 --- /dev/null +++ b/Entity/StoredObject.php @@ -0,0 +1,164 @@ + + * + * @ORM\Entity() + * @ORM\Table("chill_doc.stored_object") + */ +class StoredObject implements AsyncFileInterface +{ + /** + * @ORM\Id() + * @ORM\GeneratedValue() + * @ORM\Column(type="integer") + */ + private $id; + + /** + * @ORM\Column(type="text") + */ + private $filename; + + /** + * @ORM\Column(type="json_array", name="key") + * @var array + */ + private $keyInfos = array(); + + /** + * + * @var int[] + * @ORM\Column(type="json_array", name="iv") + */ + private $iv = array(); + + /** + * + * @var \DateTime + * @ORM\Column(type="datetime", name="creation_date") + */ + private $creationDate; + + /** + * + * @var string + * @ORM\Column(type="text", name="type") + */ + private $type = ''; + + /** + * + * @var array + * @ORM\Column(type="json_array", name="datas") + */ + private $datas = []; + + public function __construct() + { + $this->creationDate = new \DateTime(); + } + + public function getId() + { + return $this->id; + } + + public function getFilename() + { + return $this->filename; + } + + public function getCreationDate(): \DateTime + { + return $this->creationDate; + } + + public function getType() + { + return $this->type; + } + + public function getDatas() + { + return $this->datas; + } + + public function setFilename($filename) + { + $this->filename = $filename; + + return $this; + } + + public function setCreationDate(\DateTime $creationDate) + { + $this->creationDate = $creationDate; + return $this; + } + + public function setType($type) + { + $this->type = $type; + + return $this; + } + + public function setDatas(array $datas) + { + $this->datas = $datas; + + return $this; + } + + public function getObjectName() + { + return $this->getFilename(); + } + + public function setAsyncFile(/*AsyncFileInterface*/ $async) + { + dump($async); + //$this->setFilename($async->getObjectName()); + } + + public function getAsyncFile() + { + return $this; + } + + public function getKeyInfos() + { + return $this->keyInfos; + } + + public function getIv() + { + return $this->iv; + } + + public function setKeyInfos($keyInfos) + { + $this->keyInfos = $keyInfos; + + return $this; + } + + public function setIv($iv) + { + $this->iv = $iv; + + return $this; + } + + +} diff --git a/Form/PersonDocumentType.php b/Form/PersonDocumentType.php index 28cc582f5..ebd4c5d9a 100644 --- a/Form/PersonDocumentType.php +++ b/Form/PersonDocumentType.php @@ -65,7 +65,7 @@ class PersonDocumentType extends AbstractType ->add('description', TextareaType::class, [ 'required' => false ]) - ->add('content') + ->add('object', StoredObjectType::class) ->add('scope', ScopePickerType::class, [ 'center' => $options['center'], 'role' => $options['role'] diff --git a/Form/StoredObjectType.php b/Form/StoredObjectType.php new file mode 100644 index 000000000..1ae861362 --- /dev/null +++ b/Form/StoredObjectType.php @@ -0,0 +1,72 @@ + + */ +class StoredObjectType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('filename', AsyncUploaderType::class) + ->add('keyInfos', HiddenType::class) + ->add('iv', HiddenType::class) + ; + + $builder + ->get('keyInfos') + ->addModelTransformer(new CallbackTransformer( + [$this, 'transform'], [$this, 'reverseTransform'] + )) + ; + $builder + ->get('iv') + ->addModelTransformer(new CallbackTransformer( + [$this, 'transform'], [$this, 'reverseTransform'] + )) + ; + } + + public function getBlockPrefix() + { + return 'stored_object'; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefault('data_class', StoredObject::class) + ; + } + + public function reverseTransform($value) + { + if ($value === null) { + return null; + } + + return \json_decode($value, true); + } + + public function transform($object) + { + if ($object === null) { + return null; + } + + return \json_encode($object); + } +} diff --git a/Object/ObjectToAsyncFileTransformer.php b/Object/ObjectToAsyncFileTransformer.php new file mode 100644 index 000000000..5501be6ce --- /dev/null +++ b/Object/ObjectToAsyncFileTransformer.php @@ -0,0 +1,53 @@ + + */ +class ObjectToAsyncFileTransformer implements AsyncFileTransformerInterface +{ + /** + * + * @var EntityManagerInterface + */ + protected $em; + + public function __construct(EntityManagerInterface $em) + { + $this->em = $em; + } + + public function toAsyncFile($data) + { + dump($data); + + if ($data instanceof StoredObject) { + return $data; + } + } + + public function toData(AsyncFileInterface $asyncFile) + { + dump($asyncFile); + + $object = $this->em + ->getRepository(StoredObject::class) + ->findByFilename($asyncFile->getObjectName()) + ; + + return $object ?? (new StoredObject()) + ->setFilename($asyncFile->getObjectName()) + ; + } +} diff --git a/Object/PersistenceChecker.php b/Object/PersistenceChecker.php new file mode 100644 index 000000000..3e0c58189 --- /dev/null +++ b/Object/PersistenceChecker.php @@ -0,0 +1,40 @@ + + */ +class PersistenceChecker implements PersistenceCheckerInterface +{ + /** + * + * @var EntityManagerInterface + */ + protected $em; + + public function __construct(EntityManagerInterface $em) + { + $this->em = $em; + } + + + public function isPersisted($object_name): bool + { + $qb = $this->em->createQueryBuilder(); + $qb->select('COUNT(m)') + ->from(StoredObject::class, 'm') + ->where($qb->expr()->eq('m.filename', ':object_name')) + ->setParameter('object_name', $object_name) + ; + + return 1 === $qb->getQuery()->getSingleScalarResult(); + } +} diff --git a/Resources/config/services/media.yml b/Resources/config/services/media.yml new file mode 100644 index 000000000..e6afe2155 --- /dev/null +++ b/Resources/config/services/media.yml @@ -0,0 +1,9 @@ +services: + chill_doc_store.persistence_checker: + class: Chill\DocStoreBundle\Object\PersistenceChecker + arguments: + $em: '@Doctrine\ORM\EntityManagerInterface' + + Chill\DocStoreBundle\Object\ObjectToAsyncFileTransformer: + arguments: + $em: '@Doctrine\ORM\EntityManagerInterface' diff --git a/Resources/migrations/Version20180606133338.php b/Resources/migrations/Version20180606133338.php new file mode 100644 index 000000000..43dae7aa4 --- /dev/null +++ b/Resources/migrations/Version20180606133338.php @@ -0,0 +1,38 @@ +abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE SEQUENCE chill_doc.stored_object_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_doc.stored_object (id INT NOT NULL, filename TEXT NOT NULL, key JSON NOT NULL, iv JSON NOT NULL, creation_date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, type TEXT NOT NULL, datas JSON NOT NULL, PRIMARY KEY(id))'); + $this->addSql('COMMENT ON COLUMN chill_doc.stored_object.key IS \'(DC2Type:json_array)\''); + $this->addSql('COMMENT ON COLUMN chill_doc.stored_object.iv IS \'(DC2Type:json_array)\''); + $this->addSql('COMMENT ON COLUMN chill_doc.stored_object.datas IS \'(DC2Type:json_array)\''); + $this->addSql('ALTER TABLE chill_doc.person_document ADD object_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_doc.person_document DROP content'); + $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C232D562B FOREIGN KEY (object_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_41DA53C232D562B ON chill_doc.person_document (object_id)'); + } + + public function down(Schema $schema) : void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_doc.person_document DROP CONSTRAINT FK_41DA53C232D562B'); + $this->addSql('DROP SEQUENCE chill_doc.stored_object_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_doc.stored_object'); + $this->addSql('ALTER TABLE chill_doc.person_document ADD content TEXT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_doc.person_document DROP object_id'); + } +} diff --git a/Resources/public/module/async_upload/downloader.js b/Resources/public/module/async_upload/downloader.js new file mode 100644 index 000000000..55f0a3550 --- /dev/null +++ b/Resources/public/module/async_upload/downloader.js @@ -0,0 +1,67 @@ +var algo = 'AES-CBC'; + +var initializeButtons = (root) => { + var + buttons = root.querySelectorAll('a[data-download-button]'); + + for (let i = 0; i < buttons.length; i ++) { + initialize(buttons[i]); + } +}; + +var initialize = (button) => { + button.addEventListener('click', onClick); +}; + +var onClick = e => download(e.target); + +var download = (button) => { + console.log(button.dataset.key); + var + keyData = JSON.parse(button.dataset.key), + //keyData, // = JSON.parse(keyString), + ivData = JSON.parse(button.dataset.iv), + iv = new Uint8Array(ivData), + url = button.dataset.tempUrlGet, + data, key + ; + console.log('keyData', keyData); + console.log('iv', iv); + console.log('url', url); + + window.crypto.subtle.importKey('jwk', keyData, { name: algo, iv: iv}, false, ['decrypt']) + .then(nKey => { + key = nKey; + console.log(key); + + return window.fetch(url); + }) + .then(r => { + if (r.ok) { + return r.arrayBuffer(); + } else { + console.log(r); + throw new Error(r.statusCode); + } + }) + .then(buffer => { + return window.crypto.subtle.decrypt({ name: algo, iv: iv }, key, buffer); + }) + .then(decrypted => { + var + blob = new Blob([decrypted]), + url = window.URL.createObjectURL(blob) + ; + button.href = url; + button.removeEventListener('click', onClick); + }) + .catch(error => { + console.log(error); + }) + ; +}; + +window.addEventListener('load', function(e) { + console.log('load'); + initializeButtons(e.target); +}); diff --git a/Resources/public/module/async_upload/index.js b/Resources/public/module/async_upload/index.js new file mode 100644 index 000000000..9fa7deeeb --- /dev/null +++ b/Resources/public/module/async_upload/index.js @@ -0,0 +1,2 @@ +require('./uploader.js'); +require('./downloader.js'); \ No newline at end of file diff --git a/Resources/public/module/async_upload/uploader.js b/Resources/public/module/async_upload/uploader.js new file mode 100644 index 000000000..6fdc7cb66 --- /dev/null +++ b/Resources/public/module/async_upload/uploader.js @@ -0,0 +1,183 @@ +var algo = 'AES-CBC'; + +var keyDefinition = { + name: algo, + length: 256 +}; + +var searchForZones = function(root) { + var zones = root.querySelectorAll('div[data-stored-object]'); + + for(let i=0; i < zones.length; i++) { + initialize(zones[i]); + } +}; + + +var initialize = function(zone) { + console.log('initialize zone'); + + var + dropZone = document.createElement('div'), + input = document.createElement('input') + ; + + input.type = 'file'; + input.addEventListener('change', function(e) { + handleInputFile(zone); + }); + + dropZone.classList.add('chill-doc__dropzone__drop'); + + zone.insertBefore(input, zone.firstChild); + zone.insertBefore(dropZone, zone.firstChild); +}; + +var handleInputFile = function (zone) { + console.log('handle file'); + + var + file = zone.querySelector('input[type="file"]').files[0], + + reader = new FileReader() + ; + + reader.onload = e => { + transmitArrayBuffer(zone, e.target.result); + }; + + reader.readAsArrayBuffer(file); +}; + +var createFilename = () => { + var text = ""; + var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + for (let i = 0; i < 7; i++) + text += possible.charAt(Math.floor(Math.random() * possible.length)); + + return text; +}; + +var transmitArrayBuffer = (zone, data) => { + var + iv = crypto.getRandomValues(new Uint8Array(16)), + generateTempUrlPost = zone.querySelector('input[data-async-file-upload]').dataset.generateTempUrlPost, + suffix = createFilename(), + jsKey, rawKey, encryptedData, uploadData + ; + + window.crypto.subtle.generateKey(keyDefinition, true, [ "encrypt", "decrypt" ]) + .then(key => { + console.log('key', key); + console.log('iv', iv); + console.log('iv to string', iv.join(',')); + jsKey = key; + + // we register the key somwhere + return window.crypto.subtle.exportKey('jwk', key); + }).then(exportedKey => { + rawKey = exportedKey; + + console.log('rawkey', rawKey); + console.log('data', data); + // we start encryption + return window.crypto.subtle.encrypt({ name: algo, iv: iv}, jsKey, data); + }) + .then(encrypted => { + console.log('encrypted', encrypted); + + encryptedData = encrypted; + + // we get the url and parameters to upload document + return window.fetch(generateTempUrlPost); + }) + .then(response => response.json()) + .then(data => { + console.log(encryptedData); + console.log(data); + var + formData = new FormData(); + + uploadData = data; + + formData.append("redirect", data.redirect); + formData.append("max_file_size", data.max_file_size); + formData.append("max_file_count", data.max_file_count); + formData.append("expires", data.expires); + formData.append("signature", data.signature); + formData.append("file", new Blob([ encryptedData ]), suffix); + + console.log('filename', suffix); + console.log('formData', formData); + + return window.fetch(data.url, { + method: 'POST', + mode: 'cors', + body: formData + }); + }) + .then(response => { + if (response.ok) { + console.log('sent'); + + storeDataInForm(zone, suffix, rawKey, iv, uploadData); + + } else { + console.log('response', response); + throw new Error("error while sending data"); + } + }) + .catch(error => { + console.log(error); + }) + +// return window.crypto.subtle.importKey('jwk', rawKey, { name: algo, iv: iv }, false, [ "decrypt"]); +// +// .then(key => { +// console.log('decrypt'); +// console.log(key); +// +// return window.crypto.subtle.decrypt({ name: algo, iv: iv }, key, encryptedData); +// }) +// .then(decrypted => { +// console.log('decrypted'); +// decrypt(zone, decrypted, 'decrypted'); +// }) + + ; +}; + +var storeDataInForm = (zone, suffix, jskey, iv, uploaddata) => { + var + inputKey = zone.querySelector('input[data-stored-object-key]'), + inputIv = zone.querySelector('input[data-stored-object-iv]'), + inputObject = zone.querySelector('input[data-async-file-upload]') + ; + + inputKey.value = JSON.stringify(jskey); + inputIv.value = JSON.stringify(iv); + inputObject.value = uploaddata.prefix + suffix; +}; + +var decrypt = (zone, arraybuffer, name) => { + console.log('arraybuffer', arraybuffer); + var + link = document.createElement('a'), + data = new Blob([ arraybuffer ]) + ; + + link.innerHTML = name; + + link.href = window.URL.createObjectURL(data); + link.download = 'file'; + + zone.appendChild(link); +}; + + +window.addEventListener('load', function(e) { + searchForZones(document); +}); + + diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig new file mode 100644 index 000000000..bb744282a --- /dev/null +++ b/Resources/views/Form/fields.html.twig @@ -0,0 +1,7 @@ +{% block stored_object_widget %} +
+ {{ form_widget(form.filename) }} + {{ form_widget(form.keyInfos, { 'attr': { 'data-stored-object-key': 1 } }) }} + {{ form_widget(form.iv, { 'attr': { 'data-stored-object-iv': 1 } }) }} +
+{% endblock %} diff --git a/Resources/views/Macro/macro.html.twig b/Resources/views/Macro/macro.html.twig new file mode 100644 index 000000000..7042998d1 --- /dev/null +++ b/Resources/views/Macro/macro.html.twig @@ -0,0 +1,3 @@ +{% macro download_button(storedObject) %} + {{ 'Download'|trans }} +{% endmacro %} diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig index 50cd0579a..dc35ceae9 100644 --- a/Resources/views/PersonDocument/index.html.twig +++ b/Resources/views/PersonDocument/index.html.twig @@ -19,8 +19,14 @@ {% set activeRouteKey = '' %} +{% import "@ChillDocStore/Macro/macro.html.twig" as m %} + {% block title %}{{ 'Documents for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} +{% block js %} + +{% endblock %} + {% block personcontent %}

{{ 'Document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}

@@ -42,6 +48,9 @@ {{ form_end(form) }} {% endblock %} + +{% block js %} + +{% endblock %} diff --git a/chill.webpack.config.js b/chill.webpack.config.js new file mode 100644 index 000000000..e98df7a23 --- /dev/null +++ b/chill.webpack.config.js @@ -0,0 +1,5 @@ +module.exports = function(encore) { + let file = __dirname + '/Resources/public/module/async_upload/index.js'; + + encore.addEntry('async_upload', file); +}; From 299491cb5b248085a1931ae39fb67ee5bc181444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 7 Jun 2018 15:31:20 +0200 Subject: [PATCH 09/58] add mime types to documents --- Form/StoredObjectType.php | 1 + .../public/module/async_upload/downloader.js | 97 ++++++++++++------- .../public/module/async_upload/uploader.js | 65 ++----------- Resources/views/Form/fields.html.twig | 1 + Resources/views/Macro/macro.html.twig | 4 +- .../views/PersonDocument/index.html.twig | 2 +- 6 files changed, 74 insertions(+), 96 deletions(-) diff --git a/Form/StoredObjectType.php b/Form/StoredObjectType.php index 1ae861362..31dc25528 100644 --- a/Form/StoredObjectType.php +++ b/Form/StoredObjectType.php @@ -22,6 +22,7 @@ class StoredObjectType extends AbstractType { $builder ->add('filename', AsyncUploaderType::class) + ->add('type', HiddenType::class) ->add('keyInfos', HiddenType::class) ->add('iv', HiddenType::class) ; diff --git a/Resources/public/module/async_upload/downloader.js b/Resources/public/module/async_upload/downloader.js index 55f0a3550..6783d1fe9 100644 --- a/Resources/public/module/async_upload/downloader.js +++ b/Resources/public/module/async_upload/downloader.js @@ -1,3 +1,5 @@ +var mime = require('mime-types'); + var algo = 'AES-CBC'; var initializeButtons = (root) => { @@ -16,52 +18,73 @@ var initialize = (button) => { var onClick = e => download(e.target); var download = (button) => { - console.log(button.dataset.key); var keyData = JSON.parse(button.dataset.key), - //keyData, // = JSON.parse(keyString), ivData = JSON.parse(button.dataset.iv), iv = new Uint8Array(ivData), - url = button.dataset.tempUrlGet, - data, key + urlGenerator = button.dataset.tempUrlGetGenerator, + hasFilename = 'filename' in button.dataset, + filename = button.dataset.filename, + labelPreparing = button.dataset.labelPreparing, + labelReady = button.dataset.labelReady, + mimeType = button.dataset.mimeType, + extension = mime.extension(mimeType), + key, url ; - console.log('keyData', keyData); - console.log('iv', iv); - console.log('url', url); - window.crypto.subtle.importKey('jwk', keyData, { name: algo, iv: iv}, false, ['decrypt']) - .then(nKey => { - key = nKey; - console.log(key); - - return window.fetch(url); - }) - .then(r => { - if (r.ok) { - return r.arrayBuffer(); - } else { - console.log(r); - throw new Error(r.statusCode); + button.textContent = labelPreparing; + + window.fetch(urlGenerator) + .then((r) => { + if (r.ok) { + return r.json(); + } else { + throw new Error("error while downloading url " + r.status + " " + r.statusText); + } + }) + .then(data => { + url = data.url; + + return window.crypto.subtle.importKey('jwk', keyData, { name: algo, iv: iv}, false, ['decrypt']); + }) + .then(nKey => { + key = nKey; + + return window.fetch(url); + }) + .then(r => { + if (r.ok) { + return r.arrayBuffer(); + } else { + throw new Error(r.status + r.statusText); + } + }) + .then(buffer => { + return window.crypto.subtle.decrypt({ name: algo, iv: iv }, key, buffer); + }) + .then(decrypted => { + var + blob = new Blob([decrypted], { type: mimeType }), + url = window.URL.createObjectURL(blob) + ; + button.href = url; + button.target = '_parent'; + button.type = mimeType; + button.textContent = labelReady; + if (hasFilename) { + button.download = filename; + if (extension !== false) { + button.download = button.download + '.' + extension; } - }) - .then(buffer => { - return window.crypto.subtle.decrypt({ name: algo, iv: iv }, key, buffer); - }) - .then(decrypted => { - var - blob = new Blob([decrypted]), - url = window.URL.createObjectURL(blob) - ; - button.href = url; - button.removeEventListener('click', onClick); - }) - .catch(error => { - console.log(error); - }) - ; + } + button.removeEventListener('click', onClick); + }) + .catch(error => { + console.log(error); + }) + ; }; window.addEventListener('load', function(e) { - console.log('load'); initializeButtons(e.target); }); diff --git a/Resources/public/module/async_upload/uploader.js b/Resources/public/module/async_upload/uploader.js index 6fdc7cb66..c871152d3 100644 --- a/Resources/public/module/async_upload/uploader.js +++ b/Resources/public/module/async_upload/uploader.js @@ -15,8 +15,6 @@ var searchForZones = function(root) { var initialize = function(zone) { - console.log('initialize zone'); - var dropZone = document.createElement('div'), input = document.createElement('input') @@ -34,16 +32,14 @@ var initialize = function(zone) { }; var handleInputFile = function (zone) { - console.log('handle file'); - var file = zone.querySelector('input[type="file"]').files[0], - + type = file.type, reader = new FileReader() ; reader.onload = e => { - transmitArrayBuffer(zone, e.target.result); + transmitArrayBuffer(zone, e.target.result, type); }; reader.readAsArrayBuffer(file); @@ -59,7 +55,7 @@ var createFilename = () => { return text; }; -var transmitArrayBuffer = (zone, data) => { +var transmitArrayBuffer = (zone, data, type) => { var iv = crypto.getRandomValues(new Uint8Array(16)), generateTempUrlPost = zone.querySelector('input[data-async-file-upload]').dataset.generateTempUrlPost, @@ -69,9 +65,6 @@ var transmitArrayBuffer = (zone, data) => { window.crypto.subtle.generateKey(keyDefinition, true, [ "encrypt", "decrypt" ]) .then(key => { - console.log('key', key); - console.log('iv', iv); - console.log('iv to string', iv.join(',')); jsKey = key; // we register the key somwhere @@ -79,13 +72,10 @@ var transmitArrayBuffer = (zone, data) => { }).then(exportedKey => { rawKey = exportedKey; - console.log('rawkey', rawKey); - console.log('data', data); // we start encryption return window.crypto.subtle.encrypt({ name: algo, iv: iv}, jsKey, data); }) .then(encrypted => { - console.log('encrypted', encrypted); encryptedData = encrypted; @@ -94,8 +84,6 @@ var transmitArrayBuffer = (zone, data) => { }) .then(response => response.json()) .then(data => { - console.log(encryptedData); - console.log(data); var formData = new FormData(); @@ -108,9 +96,6 @@ var transmitArrayBuffer = (zone, data) => { formData.append("signature", data.signature); formData.append("file", new Blob([ encryptedData ]), suffix); - console.log('filename', suffix); - console.log('formData', formData); - return window.fetch(data.url, { method: 'POST', mode: 'cors', @@ -119,65 +104,33 @@ var transmitArrayBuffer = (zone, data) => { }) .then(response => { if (response.ok) { - console.log('sent'); - - storeDataInForm(zone, suffix, rawKey, iv, uploadData); + storeDataInForm(zone, suffix, rawKey, iv, uploadData, type); } else { - console.log('response', response); throw new Error("error while sending data"); } }) .catch(error => { + window.alert("Error while sending document."); console.log(error); }) - -// return window.crypto.subtle.importKey('jwk', rawKey, { name: algo, iv: iv }, false, [ "decrypt"]); -// -// .then(key => { -// console.log('decrypt'); -// console.log(key); -// -// return window.crypto.subtle.decrypt({ name: algo, iv: iv }, key, encryptedData); -// }) -// .then(decrypted => { -// console.log('decrypted'); -// decrypt(zone, decrypted, 'decrypted'); -// }) - ; }; -var storeDataInForm = (zone, suffix, jskey, iv, uploaddata) => { +var storeDataInForm = (zone, suffix, jskey, iv, uploaddata, type) => { var inputKey = zone.querySelector('input[data-stored-object-key]'), inputIv = zone.querySelector('input[data-stored-object-iv]'), - inputObject = zone.querySelector('input[data-async-file-upload]') + inputObject = zone.querySelector('input[data-async-file-upload]'), + inputType = zone.querySelector('input[data-async-file-type]') ; inputKey.value = JSON.stringify(jskey); inputIv.value = JSON.stringify(iv); + inputType.value = type; inputObject.value = uploaddata.prefix + suffix; }; -var decrypt = (zone, arraybuffer, name) => { - console.log('arraybuffer', arraybuffer); - var - link = document.createElement('a'), - data = new Blob([ arraybuffer ]) - ; - - link.innerHTML = name; - - link.href = window.URL.createObjectURL(data); - link.download = 'file'; - - zone.appendChild(link); -}; - - window.addEventListener('load', function(e) { searchForZones(document); }); - - diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index bb744282a..ee21c0cb1 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -3,5 +3,6 @@ {{ form_widget(form.filename) }} {{ form_widget(form.keyInfos, { 'attr': { 'data-stored-object-key': 1 } }) }} {{ form_widget(form.iv, { 'attr': { 'data-stored-object-iv': 1 } }) }} + {{ form_widget(form.type, { 'attr': { 'data-async-file-type': 1 } }) }} {% endblock %} diff --git a/Resources/views/Macro/macro.html.twig b/Resources/views/Macro/macro.html.twig index 7042998d1..36b2793e3 100644 --- a/Resources/views/Macro/macro.html.twig +++ b/Resources/views/Macro/macro.html.twig @@ -1,3 +1,3 @@ -{% macro download_button(storedObject) %} - {{ 'Download'|trans }} +{% macro download_button(storedObject, filename = null) %} + {{ 'Download'|trans }} {% endmacro %} diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig index dc35ceae9..8c73cc739 100644 --- a/Resources/views/PersonDocument/index.html.twig +++ b/Resources/views/PersonDocument/index.html.twig @@ -49,7 +49,7 @@
    {% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
  • - {{ m.download_button(document.object) }} + {{ m.download_button(document.object, document.title) }}
  • From fcc74c993dc8ed749f55940ad5dd89bd6f81e4bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 7 Jun 2018 16:54:13 +0200 Subject: [PATCH 10/58] add validation of existing file --- Controller/DocumentPersonController.php | 21 +++++++++++++ .../ChillDocStoreExtension.php | 1 + Entity/Document.php | 7 ++++- Entity/StoredObject.php | 4 +++ Form/PersonDocumentType.php | 4 ++- Resources/config/services/controller.yml | 8 +++++ Resources/translation/messages.yml | 2 ++ Resources/translation/validators.fr.yml | 1 + .../views/PersonDocument/_form.html.twig | 1 - Resources/views/PersonDocument/edit.html.twig | 30 ++++++++++++++++--- Resources/views/PersonDocument/new.html.twig | 4 ++- 11 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 Resources/config/services/controller.yml create mode 100644 Resources/translation/messages.yml create mode 100644 Resources/translation/validators.fr.yml delete mode 100644 Resources/views/PersonDocument/_form.html.twig diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php index 56b6feb91..0ff91e853 100644 --- a/Controller/DocumentPersonController.php +++ b/Controller/DocumentPersonController.php @@ -13,6 +13,7 @@ use Chill\PersonBundle\Entity\Person; use Symfony\Component\Security\Core\Role\Role; use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; +use Symfony\Component\Translation\TranslatorInterface; /** * @Route("/{_locale}/person/{person}/document") @@ -21,6 +22,18 @@ use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; */ class DocumentPersonController extends Controller { + + /** + * + * @var TranslatorInterface + */ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + /** * @Route("/", name="person_document_index", methods="GET") */ @@ -84,8 +97,12 @@ class DocumentPersonController extends Controller $em = $this->getDoctrine()->getManager(); $em->persist($document); $em->flush(); + + $this->addFlash('success', $this->translator->trans("The document is successfully registered")); return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]); + } elseif ($form->isSubmitted() and !$form->isValid()) { + $this->addFlash('error', $this->translator->trans("This form contains errors")); } return $this->render('ChillDocStoreBundle:PersonDocument:new.html.twig', [ @@ -128,10 +145,14 @@ class DocumentPersonController extends Controller if ($form->isSubmitted() && $form->isValid()) { $this->getDoctrine()->getManager()->flush(); + + $this->addFlash('success', $this->translator->trans("The document is successfully updated")); return $this->redirectToRoute( 'person_document_edit', ['id' => $document->getId(), 'person' => $person->getId()]); + } elseif ($form->isSubmitted() and !$form->isValid()) { + $this->addFlash('error', $this->translator->trans("This form contains errors")); } return $this->render( diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index e57851427..86da6ac79 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -27,6 +27,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); $loader->load('services/media.yml'); + $loader->load('services/controller.yml'); } diff --git a/Entity/Document.php b/Entity/Document.php index 1cfa94d8e..ee744fbfa 100644 --- a/Entity/Document.php +++ b/Entity/Document.php @@ -6,7 +6,8 @@ use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Chill\MainBundle\Entity\HasScopeInterface; use Chill\MainBundle\Entity\User; - +use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists; +use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\MappedSuperclass() @@ -22,6 +23,9 @@ class Document implements HasScopeInterface /** * @ORM\Column(type="text") + * @Assert\Length( + * min=2, max=250 + * ) */ private $title; @@ -44,6 +48,7 @@ class Document implements HasScopeInterface * targetEntity="Chill\DocStoreBundle\Entity\StoredObject", * cascade={"persist"} * ) + * @Assert\Valid() */ private $object; diff --git a/Entity/StoredObject.php b/Entity/StoredObject.php index b89ec3754..dde739ee1 100644 --- a/Entity/StoredObject.php +++ b/Entity/StoredObject.php @@ -6,6 +6,7 @@ namespace Chill\DocStoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface; +use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists; /** * Represent a document stored in an object store @@ -14,6 +15,9 @@ use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface; * * @ORM\Entity() * @ORM\Table("chill_doc.stored_object") + * @AsyncFileExists( + * message="The file is not stored properly" + * ) */ class StoredObject implements AsyncFileInterface { diff --git a/Form/PersonDocumentType.php b/Form/PersonDocumentType.php index ebd4c5d9a..d99c7b2b8 100644 --- a/Form/PersonDocumentType.php +++ b/Form/PersonDocumentType.php @@ -65,7 +65,9 @@ class PersonDocumentType extends AbstractType ->add('description', TextareaType::class, [ 'required' => false ]) - ->add('object', StoredObjectType::class) + ->add('object', StoredObjectType::class, [ + 'error_bubbling' => true + ]) ->add('scope', ScopePickerType::class, [ 'center' => $options['center'], 'role' => $options['role'] diff --git a/Resources/config/services/controller.yml b/Resources/config/services/controller.yml new file mode 100644 index 000000000..379d36829 --- /dev/null +++ b/Resources/config/services/controller.yml @@ -0,0 +1,8 @@ +services: + Chill\DocStoreBundle\Controller\: + resource: '../../../Controller' + tags: ['controller.service_arguments'] + + Chill\DocStoreBundle\Controller\DocumentPersonController: + autowire: true + \ No newline at end of file diff --git a/Resources/translation/messages.yml b/Resources/translation/messages.yml new file mode 100644 index 000000000..68a2b380b --- /dev/null +++ b/Resources/translation/messages.yml @@ -0,0 +1,2 @@ +## YAML Template. +--- diff --git a/Resources/translation/validators.fr.yml b/Resources/translation/validators.fr.yml new file mode 100644 index 000000000..cf2283889 --- /dev/null +++ b/Resources/translation/validators.fr.yml @@ -0,0 +1 @@ +The file is not stored properly: Le fichier n'est pas téléchargé correctement diff --git a/Resources/views/PersonDocument/_form.html.twig b/Resources/views/PersonDocument/_form.html.twig deleted file mode 100644 index d5e483e36..000000000 --- a/Resources/views/PersonDocument/_form.html.twig +++ /dev/null @@ -1 +0,0 @@ -{{ form_widget(form) }} diff --git a/Resources/views/PersonDocument/edit.html.twig b/Resources/views/PersonDocument/edit.html.twig index a81705328..49cf1456d 100644 --- a/Resources/views/PersonDocument/edit.html.twig +++ b/Resources/views/PersonDocument/edit.html.twig @@ -17,14 +17,32 @@ {% extends "ChillPersonBundle::layout.html.twig" %} +{% import "@ChillDocStore/Macro/macro.html.twig" as m %} + {% set activeRouteKey = '' %} {% block title %}{{ 'Editing document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} {% block personcontent %}

    {{ 'Edit Document' | trans }}

    + + {{ form_errors(form) }} {{ form_start(form) }} - {{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig', {'button_label': 'Update'}) }} + + {{ form_row(form.title) }} + {{ form_row(form.date) }} + {{ form_row(form.category) }} + {{ form_row(form.scope) }} + {{ form_row(form.description) }} +
    +
    + +
    +
    + {{ m.download_button(document.object, document.title) }} +
    +
    + {{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
    • @@ -33,16 +51,20 @@
    • - +
    • - {% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %} + {# {% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
    • {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }}
    • - {% endif %} + {% endif %} #}
    {{ form_end(form) }} {% endblock %} + +{% block js %} + +{% endblock %} diff --git a/Resources/views/PersonDocument/new.html.twig b/Resources/views/PersonDocument/new.html.twig index d962acf9c..088cf8b25 100644 --- a/Resources/views/PersonDocument/new.html.twig +++ b/Resources/views/PersonDocument/new.html.twig @@ -22,9 +22,11 @@ {% block personcontent %}

    {{ 'Create new Document' | trans }}

    + + {{ form_errors(form) }} {{ form_start(form) }} - {{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig') }} + {{ form_widget(form) }}
    • From 686473be39287400e5ba87c9487838d61c4f5c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 7 Jun 2018 21:54:37 +0200 Subject: [PATCH 11/58] translation, layout, and menu --- .../ChillDocStoreExtension.php | 1 + Menu/MenuBuilder.php | 87 +++++++++++++++++ Resources/config/services/menu.yml | 8 ++ Resources/translation/messages.yml | 2 - Resources/translations/messages.fr.yml | 13 +++ .../validators.fr.yml | 0 Resources/views/Macro/macro.html.twig | 2 +- .../views/PersonDocument/index.html.twig | 10 +- Resources/views/PersonDocument/new.html.twig | 10 +- Resources/views/PersonDocument/show.html.twig | 97 ++++++++++--------- 10 files changed, 173 insertions(+), 57 deletions(-) create mode 100644 Menu/MenuBuilder.php create mode 100644 Resources/config/services/menu.yml delete mode 100644 Resources/translation/messages.yml create mode 100644 Resources/translations/messages.fr.yml rename Resources/{translation => translations}/validators.fr.yml (100%) diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index 86da6ac79..aae7c1a16 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -28,6 +28,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $loader->load('services.yml'); $loader->load('services/media.yml'); $loader->load('services/controller.yml'); + $loader->load('services/menu.yml'); } diff --git a/Menu/MenuBuilder.php b/Menu/MenuBuilder.php new file mode 100644 index 000000000..03a8b7038 --- /dev/null +++ b/Menu/MenuBuilder.php @@ -0,0 +1,87 @@ + + */ +class MenuBuilder implements LocalMenuBuilderInterface +{ + /** + * + * @var TokenStorageInterface + */ + protected $tokenStorage; + + /** + * + * @var AuthorizationHelper + */ + protected $authorizationHelper; + + /** + * + * @var TranslatorInterface + */ + protected $translator; + + public function __construct( + TokenStorageInterface $tokenStorage, + AuthorizationHelper $authorizationHelper, + TranslatorInterface $translator + ){ + $this->tokenStorage = $tokenStorage; + $this->authorizationHelper = $authorizationHelper; + $this->translator = $translator; + } + + + public function buildMenu($menuId, MenuItem $menu, array $parameters) + { + switch($menuId) { + case 'person': + $this->buildMenuPerson($menu, $parameters); + break; + default: + throw new \LogicException("this menuid $menuId is not implemented"); + } + } + + protected function buildMenuPerson(MenuItem $menu, array $parameters) + { + /* @var $person \Chill\PersonBundle\Entity\Person */ + $person = $parameters['person']; + $user = $this->tokenStorage->getToken()->getUser(); + + if ($this->authorizationHelper->userHasAccess($user, + $person->getCenter(), PersonDocumentVoter::SEE)) { + + $menu->addChild($this->translator->trans('Documents'), [ + 'route' => 'person_document_index', + 'routeParameters' => [ + 'person' => $person->getId() + ] + ]) + ->setExtras([ + 'order'=> 350 + ]); + } + + } + + public static function getMenuIds(): array + { + return [ 'person' ]; + } +} diff --git a/Resources/config/services/menu.yml b/Resources/config/services/menu.yml new file mode 100644 index 000000000..069cd64d4 --- /dev/null +++ b/Resources/config/services/menu.yml @@ -0,0 +1,8 @@ +services: + Chill\DocStoreBundle\Menu\MenuBuilder: + arguments: + $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' + $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' + $translator: '@Symfony\Component\Translation\TranslatorInterface' + tags: + - { name: 'chill.menu_builder' } diff --git a/Resources/translation/messages.yml b/Resources/translation/messages.yml deleted file mode 100644 index 68a2b380b..000000000 --- a/Resources/translation/messages.yml +++ /dev/null @@ -1,2 +0,0 @@ -## YAML Template. ---- diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml new file mode 100644 index 000000000..b73cef05f --- /dev/null +++ b/Resources/translations/messages.fr.yml @@ -0,0 +1,13 @@ +Document: Document +Documents for %name%: Documents de %name% +Preparing: En préparation +Ready to show: Prêt à être visualisé +Download: Télécharger +Create new document: Créer un nouveau document +New document for %name%: Nouveau document pour %name% +Editing document for %name%: Modification d'un document pour %name% +Edit Document: Modification d'un document +Existing document: Document existant +The document is successfully updated: Le document est mis à jour + + diff --git a/Resources/translation/validators.fr.yml b/Resources/translations/validators.fr.yml similarity index 100% rename from Resources/translation/validators.fr.yml rename to Resources/translations/validators.fr.yml diff --git a/Resources/views/Macro/macro.html.twig b/Resources/views/Macro/macro.html.twig index 36b2793e3..a9f990dca 100644 --- a/Resources/views/Macro/macro.html.twig +++ b/Resources/views/Macro/macro.html.twig @@ -1,3 +1,3 @@ {% macro download_button(storedObject, filename = null) %} - {{ 'Download'|trans }} + {{ 'Download'|trans }} {% endmacro %} diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig index 8c73cc739..806ef67d5 100644 --- a/Resources/views/PersonDocument/index.html.twig +++ b/Resources/views/PersonDocument/index.html.twig @@ -28,7 +28,7 @@ {% endblock %} {% block personcontent %} -

      {{ 'Document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}

      +

      {{ 'Documents for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}

      @@ -52,16 +52,12 @@ {{ m.download_button(document.object, document.title) }}
    • - - {{ 'See'|trans }} - +
    • {% endif %} {% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
    • - - {{ 'Edit'|trans }} - +
    • {% endif %} diff --git a/Resources/views/PersonDocument/new.html.twig b/Resources/views/PersonDocument/new.html.twig index 088cf8b25..93974b80e 100644 --- a/Resources/views/PersonDocument/new.html.twig +++ b/Resources/views/PersonDocument/new.html.twig @@ -21,12 +21,18 @@ {% block title %}{{ 'New document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} {% block personcontent %} -

      {{ 'Create new Document' | trans }}

      +

      {{ 'New document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}

      {{ form_errors(form) }} {{ form_start(form) }} - {{ form_widget(form) }} + + {{ form_row(form.title) }} + {{ form_row(form.date) }} + {{ form_row(form.category) }} + {{ form_row(form.scope) }} + {{ form_row(form.description) }} + {{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
      • diff --git a/Resources/views/PersonDocument/show.html.twig b/Resources/views/PersonDocument/show.html.twig index c5b42345e..989cd1a07 100644 --- a/Resources/views/PersonDocument/show.html.twig +++ b/Resources/views/PersonDocument/show.html.twig @@ -18,51 +18,58 @@ {% set activeRouteKey = '' %} +{% import "@ChillDocStore/Macro/macro.html.twig" as m %} + {% block title %}{{ 'Detail of document of %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} -{% block personcontent %} -

        {{ 'Document' | trans }}

        - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      {{ 'Title' | trans }}{{ document.title }}
      {{ 'Description' | trans }}{{ document.description }}
      {{ 'Content' | trans }}{{ document.content }}
      {{ 'Center' | trans}}{{ document.center }}
      {{ 'Scope' | trans }}{{ document.scope.name | localize_translatable_string }}
      {{ 'Last modificiation by' | trans }}{{ document.user }}
      {{ 'Last update' | trans }}{{ document.date ? document.date|date('Y-m-d H:i:s') : '' }}
      - - - {{ 'Back to list' | trans }} - - - - {{ 'Edit' | trans }} - - - {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} +{% block js %} + +{% endblock %} + +{% block personcontent %} +

      {{ 'Document %title%' | trans({ '%title%': document.title }) }}

      + +
      +
      {{ 'Title'|trans }}
      +
      {{ document.title }}
      + +
      {{ 'Scope' | trans }}
      +
      {{ document.scope.name | localize_translatable_string }}
      + +
      {{ 'Category'|trans }}
      +
      {{ document.category.name|localize_translatable_string }}
      + +
      {{ 'Description' | trans }}
      +
      + {% if document.description is empty %} + {{ 'Any description' }} + {% else %} +
      + {{ document.description }} +
      + {% endif %} +
      + +
      + +
        +
      • + + {{ 'Back to the list' | trans }} + +
      • + +
      • + {{ m.download_button(document.object, document.title) }} +
      • + + {% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %} +
      • + + {{ 'Edit' | trans }} + +
      • + {% endif %} + + {# {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} #} {% endblock %} From 32402d8c7a868e64d6ef00dcfceefbbf6b1dd00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 8 Jun 2018 16:15:46 +0200 Subject: [PATCH 12/58] click on link after download --- Resources/public/module/async_upload/downloader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/public/module/async_upload/downloader.js b/Resources/public/module/async_upload/downloader.js index 6783d1fe9..10f03b6ad 100644 --- a/Resources/public/module/async_upload/downloader.js +++ b/Resources/public/module/async_upload/downloader.js @@ -78,6 +78,7 @@ var download = (button) => { } } button.removeEventListener('click', onClick); + button.click(); }) .catch(error => { console.log(error); From 0eccda06d6252de614e6e725087a355c3ffa7212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 10 Sep 2018 10:49:37 +0200 Subject: [PATCH 13/58] improve doc storing --- Entity/Document.php | 15 +++--------- Entity/DocumentCategory.php | 22 +++++++----------- Form/PersonDocumentType.php | 1 + Form/StoredObjectType.php | 29 ++++++++++++++++++++---- Resources/translations/messages.fr.yml | 4 ++-- Resources/translations/validators.fr.yml | 1 + Resources/views/Macro/macro.html.twig | 6 ++++- 7 files changed, 45 insertions(+), 33 deletions(-) diff --git a/Entity/Document.php b/Entity/Document.php index ee744fbfa..67159ad7d 100644 --- a/Entity/Document.php +++ b/Entity/Document.php @@ -49,6 +49,9 @@ class Document implements HasScopeInterface * cascade={"persist"} * ) * @Assert\Valid() + * @Assert\NotNull( + * message="Upload a document" + * ) */ private $object; @@ -113,18 +116,6 @@ class Document implements HasScopeInterface return $this; } - public function getContent(): ?string - { - return $this->content; - } - - public function setContent(string $content): self - { - $this->content = $content; - - return $this; - } - /** * Get scope * diff --git a/Entity/DocumentCategory.php b/Entity/DocumentCategory.php index 29d02efb4..a2a8167cc 100644 --- a/Entity/DocumentCategory.php +++ b/Entity/DocumentCategory.php @@ -37,15 +37,16 @@ class DocumentCategory * @ORM\Column(type="json_array") */ private $name; - - public function getBundleId() // ::class BundleClass (FQDN) - { - return $this->bundleId; - } - - public function setBundleId($bundleId) + + public function __construct($bundleId, $idInsideBundle) { $this->bundleId = $bundleId; + $this->idInsideBundle = $idInsideBundle; + } + + public function getBundleId() // ::class BundleClass (FQDN) + { + return $this->bundleId; } public function getIdInsideBundle() @@ -53,13 +54,6 @@ class DocumentCategory return $this->idInsideBundle; } - public function setIdInsideBundle($idInsideBundle): self - { - $this->idInsideBundle = $idInsideBundle; - - return $this; - } - public function getDocumentClass() { return $this->documentClass; diff --git a/Form/PersonDocumentType.php b/Form/PersonDocumentType.php index d99c7b2b8..ffb494ec8 100644 --- a/Form/PersonDocumentType.php +++ b/Form/PersonDocumentType.php @@ -74,6 +74,7 @@ class PersonDocumentType extends AbstractType ]) ->add('date', ChillDateType::class) ->add('category', EntityType::class, array( + 'placeholder' => 'Choose a document category', 'class' => 'ChillDocStoreBundle:DocumentCategory', 'query_builder' => function (EntityRepository $er) { return $er->createQueryBuilder('c') diff --git a/Form/StoredObjectType.php b/Form/StoredObjectType.php index 31dc25528..824bd62ad 100644 --- a/Form/StoredObjectType.php +++ b/Form/StoredObjectType.php @@ -31,14 +31,17 @@ class StoredObjectType extends AbstractType ->get('keyInfos') ->addModelTransformer(new CallbackTransformer( [$this, 'transform'], [$this, 'reverseTransform'] - )) - ; + )); $builder ->get('iv') ->addModelTransformer(new CallbackTransformer( [$this, 'transform'], [$this, 'reverseTransform'] - )) - ; + )); + + $builder + ->addModelTransformer(new CallbackTransformer( + [ $this, 'transformObject'], [$this, 'reverseTransformObject'] + )); } public function getBlockPrefix() @@ -70,4 +73,22 @@ class StoredObjectType extends AbstractType return \json_encode($object); } + + public function transformObject($object = null) + { + return $object; + } + + public function reverseTransformObject($object) + { + if (NULL === $object) { + return null; + } + + if (NULL === $object->getFilename()) { + return null; + } + + return $object; + } } diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index b73cef05f..5bc81ad59 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -9,5 +9,5 @@ Editing document for %name%: Modification d'un document pour %name% Edit Document: Modification d'un document Existing document: Document existant The document is successfully updated: Le document est mis à jour - - +No document to download: Aucun document à télécharger +'Choose a document category': Choisissez une catégorie de document diff --git a/Resources/translations/validators.fr.yml b/Resources/translations/validators.fr.yml index cf2283889..38f21d4ab 100644 --- a/Resources/translations/validators.fr.yml +++ b/Resources/translations/validators.fr.yml @@ -1 +1,2 @@ The file is not stored properly: Le fichier n'est pas téléchargé correctement +Upload a document: Téléversez un document \ No newline at end of file diff --git a/Resources/views/Macro/macro.html.twig b/Resources/views/Macro/macro.html.twig index a9f990dca..4579d4c1e 100644 --- a/Resources/views/Macro/macro.html.twig +++ b/Resources/views/Macro/macro.html.twig @@ -1,3 +1,7 @@ {% macro download_button(storedObject, filename = null) %} - {{ 'Download'|trans }} + {% if storedObject is null %} + + {% else %} + {{ 'Download'|trans }} + {% endif %} {% endmacro %} From d058748ed02a8209a84f8ac4a19cd20888305d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 10 Sep 2018 11:02:51 +0200 Subject: [PATCH 14/58] deploy to packagist --- .gitlab-ci.yml | 25 +++++++++++++++++++++++++ CHANGELOG.md | 6 ++++++ 2 files changed, 31 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 CHANGELOG.md diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..e9826c3fb --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,25 @@ +.test_definition: &test_definition + services: + - chill/database:latest + before_script: + - composer config github-oauth.github.com $GITHUB_TOKEN + - composer install + - cp Resources/test/Fixtures/App/app/config/parameters.gitlab-ci.yml Resources/test/Fixtures/App/app/config/parameters.yml + - php Resources/test/Fixtures/App/app/console --env=test cache:warmup + - php Resources/test/Fixtures/App/app/console doctrine:migrations:migrate --env=test --no-interaction + - php Resources/test/Fixtures/App/app/console doctrine:fixtures:load --env=test --no-interaction + + +stages: + - deploy + +deploy-packagist: + stage: deploy + image: chill/ci-image:php-7.2 + before_script: + # test that PACKAGIST USERNAME and PACKAGIST_TOKEN variable are set + - if [ -z ${PACKAGIST_USERNAME+x} ]; then echo "Please set PACKAGIST_USERNAME variable"; exit -1; fi + - if [ -z ${PACKAGIST_TOKEN+x} ]; then echo "Please set PACKAGIST_TOKEN variable"; exit -1; fi + script: + - STATUSCODE=$(curl -XPOST -H'content-type:application/json' "https://packagist.org/api/update-package?username=$PACKAGIST_USERNAME&apiToken=$PACKAGIST_TOKEN" -d"{\"repository\":{\"url\":\"$CI_PROJECT_URL.git\"}}" --silent --output /dev/stderr --write-out "%{http_code}") + - if [ $STATUSCODE = "202" ]; then exit 0; else exit $STATUSCODE; fi diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..b79e475db --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ + +Dev branches +============ + +- adding .gitlab-ci to upgrade automatically packagist (master) + From d791e17ee9d51f334669a8814424dcafc854cf49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 10 Sep 2018 11:05:36 +0200 Subject: [PATCH 15/58] set remote to master --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0fc56a5bf..8a06d5cef 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,8 @@ "psr-4": { "Chill\\DocStoreBundle\\" : "" } }, "require": { - "chill-project/main": "dev-upgrade-sf3@dev", - "chill-project/person": "dev-upgrade-sf3@dev" + "chill-project/main": "dev-master@dev", + "chill-project/person": "dev-master@dev" }, "license": "AGPL-3.0" } From 47d64b11bfc396f6291359587a3583066ff65e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 10 Sep 2018 11:29:56 +0200 Subject: [PATCH 16/58] set deps to stable branches --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 8a06d5cef..dda0ff821 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,7 @@ "psr-4": { "Chill\\DocStoreBundle\\" : "" } }, "require": { - "chill-project/main": "dev-master@dev", - "chill-project/person": "dev-master@dev" + "chill-project/person": "~1.5.0" }, "license": "AGPL-3.0" } From 170795d92ff9f45ba265a90d7a4aa3398110cb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 10 Sep 2018 11:37:37 +0200 Subject: [PATCH 17/58] set deps to async-upload --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index dda0ff821..32cc7695d 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,8 @@ "psr-4": { "Chill\\DocStoreBundle\\" : "" } }, "require": { - "chill-project/person": "~1.5.0" + "chill-project/person": "~1.5.0", + "champs-libres/async-uploader-bundle": "~1.0" }, "license": "AGPL-3.0" } From c02ae50fb66d6941137a0e2a8bcbf0433a932369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 11 Sep 2018 13:56:10 +0200 Subject: [PATCH 18/58] Addign fixtures for doc acl and document categories --- CHANGELOG.md | 1 + DataFixtures/ORM/LoadDocumentACL.php | 92 +++++++++++++++++++ DataFixtures/ORM/LoadDocumentCategory.php | 60 ++++++++++++ .../ChillDocStoreExtension.php | 2 +- Entity/StoredObject.php | 11 --- Resources/config/services/fixtures.yml | 4 + 6 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 DataFixtures/ORM/LoadDocumentACL.php create mode 100644 DataFixtures/ORM/LoadDocumentCategory.php create mode 100644 Resources/config/services/fixtures.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index b79e475db..4b11bc76a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,4 +3,5 @@ Dev branches ============ - adding .gitlab-ci to upgrade automatically packagist (master) +- adding fixtures for ACL and DocumentCategory diff --git a/DataFixtures/ORM/LoadDocumentACL.php b/DataFixtures/ORM/LoadDocumentACL.php new file mode 100644 index 000000000..c17e795e6 --- /dev/null +++ b/DataFixtures/ORM/LoadDocumentACL.php @@ -0,0 +1,92 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\DocStoreBundle\DataFixtures\ORM; + +use Doctrine\Common\DataFixtures\AbstractFixture; +use Doctrine\Common\DataFixtures\OrderedFixtureInterface; +use Doctrine\Common\Persistence\ObjectManager; +use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; +use Chill\MainBundle\Entity\RoleScope; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; + +/** + * Adding acl for person document + * + */ +class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface +{ + public function getOrder() + { + return 35000; + } + + + public function load(ObjectManager $manager) + { + foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { + $permissionsGroup = $this->getReference($permissionsGroupRef); + printf("processing permission group %s \n", $permissionsGroup->getName()); + foreach (LoadScopes::$references as $scopeRef){ + $scope = $this->getReference($scopeRef); + printf("processing scope %s \n", $scope->getName()['en']); + //create permission group + switch ($permissionsGroup->getName()) { + case 'social': + if ($scope->getName()['en'] === 'administrative') { + printf("denying power on administrative \n"); + break 2; // we do not want any power on administrative + } + break; + case 'administrative': + case 'direction': + if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + printf("denying power on %s\n", $scope->getName()['en']); + break 2; // we do not want any power on social or administrative + } + break; + } + + printf("Adding Person report acl to %s " + . "permission group, scope '%s' \n", + $permissionsGroup->getName(), $scope->getName()['en']); + $roleScopeUpdate = (new RoleScope()) + ->setRole(PersonDocumentVoter::CREATE) + ->setScope($scope); + $permissionsGroup->addRoleScope($roleScopeUpdate); + $roleScopeCreate = (new RoleScope()) + ->setRole(PersonDocumentVoter::UPDATE) + ->setScope($scope); + $permissionsGroup->addRoleScope($roleScopeCreate); + $roleScopeDelete = (new RoleScope()) + ->setRole(PersonDocumentVoter::DELETE) + ->setScope($scope); + $permissionsGroup->addRoleScope($roleScopeDelete); + $manager->persist($roleScopeUpdate); + $manager->persist($roleScopeCreate); + $manager->persist($roleScopeDelete); + } + + } + + $manager->flush(); + } + +} diff --git a/DataFixtures/ORM/LoadDocumentCategory.php b/DataFixtures/ORM/LoadDocumentCategory.php new file mode 100644 index 000000000..37e55c5b7 --- /dev/null +++ b/DataFixtures/ORM/LoadDocumentCategory.php @@ -0,0 +1,60 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +namespace Chill\DocStoreBundle\DataFixtures\ORM; + +use Doctrine\Common\DataFixtures\AbstractFixture; +use Doctrine\Common\DataFixtures\OrderedFixtureInterface; +use Doctrine\Common\Persistence\ObjectManager; +use Chill\DocStoreBundle\Entity\DocumentCategory; + +/** + * + * + */ +class LoadDocumentCategory extends AbstractFixture implements OrderedFixtureInterface +{ + public function getOrder() + { + return 35010; + } + + public function load(ObjectManager $manager) + { + $category = (new DocumentCategory('chill-doc-store', 10)) + ->setDocumentClass(\Chill\DocStoreBundle\Entity\PersonDocument::class) + ->setName([ + 'fr' => "Document d'identité", + 'en' => "Identity" + ]) + ; + + $manager->persist($category); + + $category = (new DocumentCategory('chill-doc-store', 20)) + ->setDocumentClass(\Chill\DocStoreBundle\Entity\PersonDocument::class) + ->setName([ + 'fr' => "Courrier reçu", + 'en' => "Received email" + ]) + ; + + $manager->persist($category); + + $manager->flush(); + } +} diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index aae7c1a16..44141741e 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -29,7 +29,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $loader->load('services/media.yml'); $loader->load('services/controller.yml'); $loader->load('services/menu.yml'); - + $loader->load('services/fixtures.yml'); } public function prepend(ContainerBuilder $container) diff --git a/Entity/StoredObject.php b/Entity/StoredObject.php index dde739ee1..e145ff1ab 100644 --- a/Entity/StoredObject.php +++ b/Entity/StoredObject.php @@ -129,17 +129,6 @@ class StoredObject implements AsyncFileInterface return $this->getFilename(); } - public function setAsyncFile(/*AsyncFileInterface*/ $async) - { - dump($async); - //$this->setFilename($async->getObjectName()); - } - - public function getAsyncFile() - { - return $this; - } - public function getKeyInfos() { return $this->keyInfos; diff --git a/Resources/config/services/fixtures.yml b/Resources/config/services/fixtures.yml new file mode 100644 index 000000000..c9bc451d6 --- /dev/null +++ b/Resources/config/services/fixtures.yml @@ -0,0 +1,4 @@ +services: + Chill\DocStoreBundle\DataFixtures\ORM\: + resource: ../../../DataFixtures/ORM + tags: [ 'doctrine.fixture.orm' ] From 771b43d7dde7e79a4b7054c9c4f5a86a3f2b91c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 11 Sep 2018 16:55:11 +0200 Subject: [PATCH 19/58] changelog to 1.5.1 --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b11bc76a..0e547a960 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ -Dev branches -============ +version 1.5.1 +============= -- adding .gitlab-ci to upgrade automatically packagist (master) +- adding .gitlab-ci to upgrade automatically packagist - adding fixtures for ACL and DocumentCategory From 8549fbf2897bf290b3ccd0d7f20e93240fd5757a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 12 Sep 2018 15:12:03 +0200 Subject: [PATCH 20/58] fix some translations --- Resources/translations/messages.fr.yml | 3 +++ Resources/views/PersonDocument/index.html.twig | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 5bc81ad59..e35862872 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -11,3 +11,6 @@ Existing document: Document existant The document is successfully updated: Le document est mis à jour No document to download: Aucun document à télécharger 'Choose a document category': Choisissez une catégorie de document +Any document found: Aucun document trouvé +The document is successfully registered: Le document est enregistré +The document is successfully updated: Le document est mis à jour \ No newline at end of file diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig index 806ef67d5..34cb0e905 100644 --- a/Resources/views/PersonDocument/index.html.twig +++ b/Resources/views/PersonDocument/index.html.twig @@ -65,7 +65,7 @@ {% else %} - {{ 'Any document found'|trans }} + {{ 'Any document found'|trans }} {% endfor %} From 3c1f36dc19782ffa40c8ce9d6aff2bfc73352ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 12 Sep 2018 15:13:51 +0200 Subject: [PATCH 21/58] fix missing translations --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e547a960..009097ad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,8 @@ version 1.5.1 - adding .gitlab-ci to upgrade automatically packagist - adding fixtures for ACL and DocumentCategory +Branch add_dropzone +=================== + +- fix some missing translations on update / create document and "any document" in list + From 823aee2264808985980a8bcf88464e6edf5fbe54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 13 Sep 2018 20:55:38 +0200 Subject: [PATCH 22/58] Allow Document to receive null object Those null object will be checked later by validation --- Entity/Document.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Entity/Document.php b/Entity/Document.php index 67159ad7d..586d52035 100644 --- a/Entity/Document.php +++ b/Entity/Document.php @@ -162,7 +162,7 @@ class Document implements HasScopeInterface return $this->object; } - public function setObject(StoredObject $object) + public function setObject(StoredObject $object = null) { $this->object = $object; From e55d654675078ab2a9d739f5f7bef2c8c600dec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 13 Sep 2018 21:01:47 +0200 Subject: [PATCH 23/58] dropzone.js handle upload of document for a better UX --- CHANGELOG.md | 3 + .../public/module/async_upload/downloader.js | 25 +- .../public/module/async_upload/index.scss | 25 ++ .../public/module/async_upload/uploader.js | 273 ++++++++++++------ Resources/translations/messages.fr.yml | 11 +- Resources/views/Form/fields.html.twig | 14 +- Resources/views/Macro/macro.html.twig | 10 +- Resources/views/PersonDocument/edit.html.twig | 14 +- Resources/views/PersonDocument/new.html.twig | 4 + 9 files changed, 275 insertions(+), 104 deletions(-) create mode 100644 Resources/public/module/async_upload/index.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index 009097ad4..80e5dcd5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,4 +9,7 @@ Branch add_dropzone =================== - fix some missing translations on update / create document and "any document" in list +- use dropzone to upload a document with a better UI + +You must add `"dropzone": "^5.5.1"` to your dependencies in `packages.json`. diff --git a/Resources/public/module/async_upload/downloader.js b/Resources/public/module/async_upload/downloader.js index 10f03b6ad..cfeee5c37 100644 --- a/Resources/public/module/async_upload/downloader.js +++ b/Resources/public/module/async_upload/downloader.js @@ -29,6 +29,8 @@ var download = (button) => { labelReady = button.dataset.labelReady, mimeType = button.dataset.mimeType, extension = mime.extension(mimeType), + decryptError = "Error while decrypting file", + fetchError = "Error while fetching file", key, url ; @@ -44,14 +46,25 @@ var download = (button) => { }) .then(data => { url = data.url; - + return window.crypto.subtle.importKey('jwk', keyData, { name: algo, iv: iv}, false, ['decrypt']); }) + .catch(e => { + console.error("error while importing key"); + console.error(e); + button.appendChild(document.createTextNode(decryptError)); + }) .then(nKey => { key = nKey; return window.fetch(url); }) + .catch(e => { + console.error("error while fetching data"); + console.error(e); + button.textContent = ""; + button.appendChild(document.createTextNode(fetchError)); + }) .then(r => { if (r.ok) { return r.arrayBuffer(); @@ -62,6 +75,12 @@ var download = (button) => { .then(buffer => { return window.crypto.subtle.decrypt({ name: algo, iv: iv }, key, buffer); }) + .catch(e => { + console.error("error while importing key"); + console.error(e); + button.textContent = ""; + button.appendChild(document.createTextNode(decryptError)); + }) .then(decrypted => { var blob = new Blob([decrypted], { type: mimeType }), @@ -82,6 +101,8 @@ var download = (button) => { }) .catch(error => { console.log(error); + button.textContent = ""; + button.appendChild(document.createTextNode("error while handling decrypted file")); }) ; }; @@ -89,3 +110,5 @@ var download = (button) => { window.addEventListener('load', function(e) { initializeButtons(e.target); }); + +module.exports = initializeButtons; diff --git a/Resources/public/module/async_upload/index.scss b/Resources/public/module/async_upload/index.scss new file mode 100644 index 000000000..9d42d88d9 --- /dev/null +++ b/Resources/public/module/async_upload/index.scss @@ -0,0 +1,25 @@ +.dropzone { + margin-bottom: 0.5rem; + + .dz-preview { + display: initial; + margin-left: auto; + margin-right: auto; + + .dz-image { + margin-left: auto; + margin-right: auto; + } + + .dz-details, .dz-progress, .dz-success-mark, .dz-error-mark { + position: initial; + margin-left: auto; + margin-right: auto; + } + } +} + +.sc-button.dz-bt-below-dropzone { + width: 100%; +} + diff --git a/Resources/public/module/async_upload/uploader.js b/Resources/public/module/async_upload/uploader.js index c871152d3..7362a26ec 100644 --- a/Resources/public/module/async_upload/uploader.js +++ b/Resources/public/module/async_upload/uploader.js @@ -1,4 +1,15 @@ var algo = 'AES-CBC'; +var Dropzone = require('dropzone'); +var initializeDownload = require('./downloader.js'); + +// load css +//require('dropzone/dist/basic.css'); +require('dropzone/dist/dropzone.css'); +require('./index.scss'); +// + +// disable dropzone autodiscover +Dropzone.autoDiscover = false; var keyDefinition = { name: algo, @@ -13,111 +24,135 @@ var searchForZones = function(root) { } }; +var getUploadUrl = function(zoneData, files) { + var + generateTempUrlPost = zoneData.zone.querySelector('input[data-async-file-upload]').dataset.generateTempUrlPost, + oReq = new XMLHttpRequest() + ; + + // arg, dropzone, you cannot handle async upload... + oReq.open("GET", generateTempUrlPost, false); + oReq.send(); + + if (oReq.readyState !== XMLHttpRequest.DONE) { + throw new Error("Error while fetching url to upload"); + } + + zoneData.params = JSON.parse(oReq.responseText); + + return zoneData.params.url; +}; + +var encryptFile = function(originalFile, zoneData, done) { + var + iv = crypto.getRandomValues(new Uint8Array(16)), + reader = new FileReader(), + jsKey, rawKey + ; + + zoneData.originalType = originalFile.type; + + reader.onload = e => { + window.crypto.subtle.generateKey(keyDefinition, true, [ "encrypt", "decrypt" ]) + .then(key => { + jsKey = key; + + // we register the key somwhere + return window.crypto.subtle.exportKey('jwk', key); + }).then(exportedKey => { + rawKey = exportedKey; + + // we start encryption + return window.crypto.subtle.encrypt({ name: algo, iv: iv}, jsKey, e.target.result); + }) + .then(encrypted => { + zoneData.crypto = { + jsKey: jsKey, + rawKey: rawKey, + iv: iv + }; + + done(new File( [ encrypted ], zoneData.suffix)); + }); + }; + + reader.readAsArrayBuffer(originalFile); +}; + var initialize = function(zone) { var - dropZone = document.createElement('div'), - input = document.createElement('input') - ; + created = document.createElement('div'), + initMessage = document.createElement('div'), + initContent = zone.dataset.labelInitMessage, + zoneData = { zone: zone, suffix: createFilename() }, + dropzoneI; - input.type = 'file'; - input.addEventListener('change', function(e) { - handleInputFile(zone); + created.classList.add('dropzone'); + initMessage.classList.add('dz-message'); + initMessage.appendChild(document.createTextNode(initContent)); + + dropzoneI = new Dropzone(created, { + url: function(files) { + return getUploadUrl(zoneData, files); + }, + dictDefaultMessage: zone.dataset.dictDefaultMessage, + dictFileTooBig: zone.dataset.dictFileTooBig, + dictRemoveFile: zone.dataset.dictRemoveFile, + dictMaxFilesExceeded: zone.dataset.dictMaxFilesExceeded, + dictCancelUpload: zone.dataset.dictCancelUpload, + dictCancelUploadConfirm: zone.dataset.dictCancelUploadConfirm, + dictUploadCanceled: zone.dataset.dictUploadCanceled, + maxFiles: 1, + addRemoveLinks: true, + transformFile: function(file, done) { + encryptFile(file, zoneData, done); + }, + renameFile: function(file) { + return zoneData.suffix; + } + }); + + dropzoneI.on("sending", function(file, xhr, formData) { + formData.append("redirect", zoneData.params.redirect); + formData.append("max_file_size", zoneData.params.max_file_size); + formData.append("max_file_count", zoneData.params.max_file_count); + formData.append("expires", zoneData.params.expires); + formData.append("signature", zoneData.params.signature); }); - dropZone.classList.add('chill-doc__dropzone__drop'); + dropzoneI.on("success", function(file, response) { + zoneData.currentFile = file; + storeDataInForm(zone, zoneData); + }); - zone.insertBefore(input, zone.firstChild); - zone.insertBefore(dropZone, zone.firstChild); -}; + dropzoneI.on("addedfile", function(file) { + if (zoneData.hasOwnProperty('currentFile')) { + dropzoneI.removeFile(zoneData.currentFile); + } + }); + + dropzoneI.on("removedfile", function(file) { + removeDataInForm(zone, zoneData); + }); -var handleInputFile = function (zone) { - var - file = zone.querySelector('input[type="file"]').files[0], - type = file.type, - reader = new FileReader() - ; + zone.insertBefore(created, zone.firstChild); - reader.onload = e => { - transmitArrayBuffer(zone, e.target.result, type); - }; - - reader.readAsArrayBuffer(file); + insertDownloadButton(zone, zoneData); }; var createFilename = () => { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < 7; i++) - text += possible.charAt(Math.floor(Math.random() * possible.length)); + for (let i = 0; i < 7; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } return text; }; -var transmitArrayBuffer = (zone, data, type) => { - var - iv = crypto.getRandomValues(new Uint8Array(16)), - generateTempUrlPost = zone.querySelector('input[data-async-file-upload]').dataset.generateTempUrlPost, - suffix = createFilename(), - jsKey, rawKey, encryptedData, uploadData - ; - - window.crypto.subtle.generateKey(keyDefinition, true, [ "encrypt", "decrypt" ]) - .then(key => { - jsKey = key; - - // we register the key somwhere - return window.crypto.subtle.exportKey('jwk', key); - }).then(exportedKey => { - rawKey = exportedKey; - - // we start encryption - return window.crypto.subtle.encrypt({ name: algo, iv: iv}, jsKey, data); - }) - .then(encrypted => { - - encryptedData = encrypted; - - // we get the url and parameters to upload document - return window.fetch(generateTempUrlPost); - }) - .then(response => response.json()) - .then(data => { - var - formData = new FormData(); - - uploadData = data; - - formData.append("redirect", data.redirect); - formData.append("max_file_size", data.max_file_size); - formData.append("max_file_count", data.max_file_count); - formData.append("expires", data.expires); - formData.append("signature", data.signature); - formData.append("file", new Blob([ encryptedData ]), suffix); - - return window.fetch(data.url, { - method: 'POST', - mode: 'cors', - body: formData - }); - }) - .then(response => { - if (response.ok) { - storeDataInForm(zone, suffix, rawKey, iv, uploadData, type); - - } else { - throw new Error("error while sending data"); - } - }) - .catch(error => { - window.alert("Error while sending document."); - console.log(error); - }) - ; -}; - -var storeDataInForm = (zone, suffix, jskey, iv, uploaddata, type) => { +var storeDataInForm = (zone, zoneData) => { var inputKey = zone.querySelector('input[data-stored-object-key]'), inputIv = zone.querySelector('input[data-stored-object-iv]'), @@ -125,10 +160,68 @@ var storeDataInForm = (zone, suffix, jskey, iv, uploaddata, type) => { inputType = zone.querySelector('input[data-async-file-type]') ; - inputKey.value = JSON.stringify(jskey); - inputIv.value = JSON.stringify(iv); - inputType.value = type; - inputObject.value = uploaddata.prefix + suffix; + inputKey.value = JSON.stringify(zoneData.crypto.rawKey); + inputIv.value = JSON.stringify(Array.from(zoneData.crypto.iv)); + inputType.value = zoneData.originalType; + inputObject.value = zoneData.params.prefix + zoneData.suffix; + + insertDownloadButton(zone); +}; + +var removeDataInForm = (zone, zoneData) => { + var + inputKey = zone.querySelector('input[data-stored-object-key]'), + inputIv = zone.querySelector('input[data-stored-object-iv]'), + inputObject = zone.querySelector('input[data-async-file-upload]'), + inputType = zone.querySelector('input[data-async-file-type]') + ; + + inputKey.value = ""; + inputIv.value = ""; + inputType.value = ""; + inputObject.value = ""; + + insertDownloadButton(zone); +}; + +var insertDownloadButton = (zone) => { + var + existingButtons = zone.querySelectorAll('a[data-download-button]'), + newButton = document.createElement('a'), + inputKey = zone.querySelector('input[data-stored-object-key]'), + inputIv = zone.querySelector('input[data-stored-object-iv]'), + inputObject = zone.querySelector('input[data-async-file-upload]'), + inputType = zone.querySelector('input[data-async-file-type]'), + labelPreparing = zone.dataset.labelPreparing, + labelQuietButton = zone.dataset.labelQuietButton, + labelReady = zone.dataset.labelReady, + tempUrlGenerator = zone.dataset.tempUrlGenerator, + tempUrlGeneratorParams = new URLSearchParams() + ; + + // remove existing + existingButtons.forEach(function(b) { + b.remove(); + }); + + if (inputObject.value === '') { + return; + } + + tempUrlGeneratorParams.append('object_name', inputObject.value); + + newButton.dataset.downloadButton = true; + newButton.dataset.key = inputKey.value; + newButton.dataset.iv = inputIv.value; + newButton.dataset.mimeType = inputType.value; + newButton.dataset.labelPreparing = labelPreparing; + newButton.dataset.labelReady = labelReady; + newButton.dataset.tempUrlGetGenerator = tempUrlGenerator + '?' + tempUrlGeneratorParams.toString(); + newButton.classList.add('sc-button', 'bt-download', 'dz-bt-below-dropzone'); + newButton.textContent = labelQuietButton; + + zone.appendChild(newButton); + initializeDownload(zone); }; window.addEventListener('load', function(e) { diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index e35862872..d6bdf92f7 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -13,4 +13,13 @@ No document to download: Aucun document à télécharger 'Choose a document category': Choisissez une catégorie de document Any document found: Aucun document trouvé The document is successfully registered: Le document est enregistré -The document is successfully updated: Le document est mis à jour \ No newline at end of file +The document is successfully updated: Le document est mis à jour + +# dropzone upload +File too big: Fichier trop volumineux +Drop your file or click here: Cliquez ici ou faites glissez votre nouveau fichier dans cette zone +Remove file in order to upload a new one: Supprimer ce fichier pour en insérer un autre +Max files exceeded. Remove previous files: Nombre maximum de fichier atteint. Supprimez les précédents +Cancel upload: Annuler le téléversement +Are you sure you want to cancel this upload ?: Êtes-vous sûrs de vouloir annuler ce téléversement ? +Upload canceled: Téléversement annulé diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index ee21c0cb1..2be382f5d 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -1,5 +1,17 @@ {% block stored_object_widget %} -
        +
        {{ form_widget(form.filename) }} {{ form_widget(form.keyInfos, { 'attr': { 'data-stored-object-key': 1 } }) }} {{ form_widget(form.iv, { 'attr': { 'data-stored-object-iv': 1 } }) }} diff --git a/Resources/views/Macro/macro.html.twig b/Resources/views/Macro/macro.html.twig index 4579d4c1e..e42012a0b 100644 --- a/Resources/views/Macro/macro.html.twig +++ b/Resources/views/Macro/macro.html.twig @@ -2,6 +2,14 @@ {% if storedObject is null %} {% else %} - {{ 'Download'|trans }} + + {{ 'Download'|trans }} {% endif %} {% endmacro %} diff --git a/Resources/views/PersonDocument/edit.html.twig b/Resources/views/PersonDocument/edit.html.twig index 49cf1456d..6c18e8474 100644 --- a/Resources/views/PersonDocument/edit.html.twig +++ b/Resources/views/PersonDocument/edit.html.twig @@ -17,8 +17,6 @@ {% extends "ChillPersonBundle::layout.html.twig" %} -{% import "@ChillDocStore/Macro/macro.html.twig" as m %} - {% set activeRouteKey = '' %} {% block title %}{{ 'Editing document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} @@ -34,14 +32,6 @@ {{ form_row(form.category) }} {{ form_row(form.scope) }} {{ form_row(form.description) }} -
        -
        - -
        -
        - {{ m.download_button(document.object, document.title) }} -
        -
        {{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
          @@ -68,3 +58,7 @@ {% block js %} {% endblock %} + +{% block css %} + +{% endblock %} diff --git a/Resources/views/PersonDocument/new.html.twig b/Resources/views/PersonDocument/new.html.twig index 93974b80e..fe807f3b3 100644 --- a/Resources/views/PersonDocument/new.html.twig +++ b/Resources/views/PersonDocument/new.html.twig @@ -50,3 +50,7 @@ {% block js %} {% endblock %} + +{% block css %} + +{% endblock %} From 2d82e3114a4e1b1fa336a7ed04d6282b6e1baf12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 13 Sep 2018 21:04:35 +0200 Subject: [PATCH 24/58] update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80e5dcd5e..b5e560bf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ version 1.5.1 - adding .gitlab-ci to upgrade automatically packagist - adding fixtures for ACL and DocumentCategory -Branch add_dropzone -=================== +Branch master +============= - fix some missing translations on update / create document and "any document" in list - use dropzone to upload a document with a better UI From 28d903697c3e33de7700e937858db00431c8480b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 14 Sep 2018 14:02:37 +0200 Subject: [PATCH 25/58] set changelog for 1.5.2 --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e560bf9..4136b5f0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,15 @@ -version 1.5.1 +Version 1.5.1 ============= - adding .gitlab-ci to upgrade automatically packagist - adding fixtures for ACL and DocumentCategory -Branch master +Version 1.5.2 ============= - fix some missing translations on update / create document and "any document" in list - use dropzone to upload a document with a better UI -You must add `"dropzone": "^5.5.1"` to your dependencies in `packages.json`. +You must add `"dropzone": "^5.5.1"` to your dependencies in `packages.json` at the root project. From c9fddffd4bbcab964d5bec0eec7e5c27be23afdf Mon Sep 17 00:00:00 2001 From: Mat Date: Tue, 16 Oct 2018 10:47:50 +0200 Subject: [PATCH 26/58] privacyEvent, add event to index and show Actions --- Controller/DocumentPersonController.php | 31 ++++++++++++++++++++++-- Resources/config/services/controller.yml | 3 ++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php index 0ff91e853..81c505d4b 100644 --- a/Controller/DocumentPersonController.php +++ b/Controller/DocumentPersonController.php @@ -5,7 +5,9 @@ namespace Chill\DocStoreBundle\Controller; use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\DocStoreBundle\Form\PersonDocumentType; use Chill\DocStoreBundle\Repository\DocumentRepository; +use Chill\PersonBundle\Privacy\PrivacyEvent; use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -29,9 +31,21 @@ class DocumentPersonController extends Controller */ protected $translator; - public function __construct(TranslatorInterface $translator) + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + + /** + * DocumentPersonController constructor. + * + * @param TranslatorInterface $translator + * @param EventDispatcherInterface $eventDispatcher + */ + public function __construct(TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher) { $this->translator = $translator; + $this->eventDispatcher = $eventDispatcher; } /** @@ -59,6 +73,12 @@ class DocumentPersonController extends Controller array('date' => 'DESC') ); + $event = new PrivacyEvent($person, array( + 'element_class' => PersonDocument::class, + 'action' => 'index' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + return $this->render( 'ChillDocStoreBundle:PersonDocument:index.html.twig', [ @@ -119,7 +139,14 @@ class DocumentPersonController extends Controller { $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_SEE', $document); - + + $event = new PrivacyEvent($person, array( + 'element_class' => PersonDocument::class, + 'element_id' => $document->getId(), + 'action' => 'show' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + return $this->render( 'ChillDocStoreBundle:PersonDocument:show.html.twig', ['document' => $document, 'person' => $person]); diff --git a/Resources/config/services/controller.yml b/Resources/config/services/controller.yml index 379d36829..0a2798508 100644 --- a/Resources/config/services/controller.yml +++ b/Resources/config/services/controller.yml @@ -5,4 +5,5 @@ services: Chill\DocStoreBundle\Controller\DocumentPersonController: autowire: true - \ No newline at end of file + arguments: + $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' From c1da0f712ced095912769643f633ad32d8538850 Mon Sep 17 00:00:00 2001 From: Mat Date: Fri, 19 Oct 2018 13:29:37 +0200 Subject: [PATCH 27/58] privacyEvent, update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4136b5f0a..6337b66f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,3 +13,8 @@ Version 1.5.2 You must add `"dropzone": "^5.5.1"` to your dependencies in `packages.json` at the root project. +PrivacyEvent branch +=================== + +- add privacy events to document index / show + From 03ee738beeb4eaa6a73714ec90db712e3f1a267f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 19 Oct 2018 14:31:51 +0200 Subject: [PATCH 28/58] listen on collection events to allow usage of field on collection --- CHANGELOG.md | 4 ++++ Resources/public/module/async_upload/uploader.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4136b5f0a..bbc51c230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,3 +13,7 @@ Version 1.5.2 You must add `"dropzone": "^5.5.1"` to your dependencies in `packages.json` at the root project. +Master branch +============= + +- the javascript for uploading a file now works within collections, listening to collection events. diff --git a/Resources/public/module/async_upload/uploader.js b/Resources/public/module/async_upload/uploader.js index 7362a26ec..2f2b6f74e 100644 --- a/Resources/public/module/async_upload/uploader.js +++ b/Resources/public/module/async_upload/uploader.js @@ -227,3 +227,7 @@ var insertDownloadButton = (zone) => { window.addEventListener('load', function(e) { searchForZones(document); }); + +window.addEventListener('collection-add-entry', function(e) { + searchForZones(e.detail.entry); +}); From 8bc1b5f769d36a595a4bbbf9559552e4f6bd62ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 19 Oct 2018 14:33:56 +0200 Subject: [PATCH 29/58] prepare for 1.5.3 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbc51c230..3c37f9065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ Version 1.5.2 You must add `"dropzone": "^5.5.1"` to your dependencies in `packages.json` at the root project. -Master branch +Version 1.5.3 ============= - the javascript for uploading a file now works within collections, listening to collection events. From 493cdca479d577d61f77a3a55fe880d9d09fc7a5 Mon Sep 17 00:00:00 2001 From: Mat Date: Tue, 23 Oct 2018 10:07:06 +0200 Subject: [PATCH 30/58] add PrivacyEvent for documents edit and update --- CHANGELOG.md | 1 + Controller/DocumentPersonController.php | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 585ce8d2f..b60ee20b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,4 +22,5 @@ PrivacyEvent branch =================== - add privacy events to document index / show +- add privacy events to document edit / update diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php index 81c505d4b..f6f074610 100644 --- a/Controller/DocumentPersonController.php +++ b/Controller/DocumentPersonController.php @@ -174,14 +174,29 @@ class DocumentPersonController extends Controller $this->getDoctrine()->getManager()->flush(); $this->addFlash('success', $this->translator->trans("The document is successfully updated")); - + + $event = new PrivacyEvent($person, array( + 'element_class' => PersonDocument::class, + 'element_id' => $document->getId(), + 'action' => 'update' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + return $this->redirectToRoute( 'person_document_edit', ['id' => $document->getId(), 'person' => $person->getId()]); + } elseif ($form->isSubmitted() and !$form->isValid()) { $this->addFlash('error', $this->translator->trans("This form contains errors")); } - + + $event = new PrivacyEvent($person, array( + 'element_class' => PersonDocument::class, + 'element_id' => $document->getId(), + 'action' => 'edit' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + return $this->render( 'ChillDocStoreBundle:PersonDocument:edit.html.twig', [ From 927d7e6e854dee7e5e9f4eeb846bab4d1b4797cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 15 Jan 2019 12:15:04 +0100 Subject: [PATCH 31/58] replace default message on "download" button below dropzone --- CHANGELOG.md | 6 ++++++ Resources/translations/messages.fr.yml | 1 + Resources/views/Form/fields.html.twig | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c37f9065..08bbb8ed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,9 @@ Version 1.5.3 ============= - the javascript for uploading a file now works within collections, listening to collection events. + +`Master` branch +=============== + +- replace default message on download button below dropzone ; + diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index d6bdf92f7..adf017864 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -3,6 +3,7 @@ Documents for %name%: Documents de %name% Preparing: En préparation Ready to show: Prêt à être visualisé Download: Télécharger +Download existing file: Télécharger le fichier existant Create new document: Créer un nouveau document New document for %name%: Nouveau document pour %name% Editing document for %name%: Modification d'un document pour %name% diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index 2be382f5d..f9253c267 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -2,7 +2,7 @@
          Date: Tue, 15 Jan 2019 12:20:09 +0100 Subject: [PATCH 32/58] launch js event when initializing dropzone --- CHANGELOG.md | 1 + .../public/module/async_upload/uploader.js | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08bbb8ed8..d19c49413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,4 +22,5 @@ Version 1.5.3 =============== - replace default message on download button below dropzone ; +- launch event when dropzone is initialized, to allow to customize events on dropzone; diff --git a/Resources/public/module/async_upload/uploader.js b/Resources/public/module/async_upload/uploader.js index 2f2b6f74e..9ace4282c 100644 --- a/Resources/public/module/async_upload/uploader.js +++ b/Resources/public/module/async_upload/uploader.js @@ -2,6 +2,25 @@ var algo = 'AES-CBC'; var Dropzone = require('dropzone'); var initializeDownload = require('./downloader.js'); + +/** + * + * define a dropzone for chill usage + * + * An event is launched when dropzone is initialize, allowing to customize events + * on dropzone : + * + * ``` + * window.addEventListener("chill_dropzone_initialized", (e) => { + * // do something with dropzone: + * e.detail.dropzone.on("success", (e) => { + * // see https://www.dropzonejs.com/#event-success + * }); + * }); + * ``` + * + */ + // load css //require('dropzone/dist/basic.css'); require('dropzone/dist/dropzone.css'); @@ -139,6 +158,14 @@ var initialize = function(zone) { zone.insertBefore(created, zone.firstChild); insertDownloadButton(zone, zoneData); + + let event = new CustomEvent("chill_dropzone_initialized", { + detail: { + dropzone: dropzoneI, + zoneData: zoneData + } + }); + window.dispatchEvent(event); }; var createFilename = () => { From 0115a0bf72c546de231a785aba9b9b3376709821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 15 Jan 2019 12:21:23 +0100 Subject: [PATCH 33/58] bump to 1.5.4 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d19c49413..abe783a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,8 @@ Version 1.5.3 - the javascript for uploading a file now works within collections, listening to collection events. -`Master` branch -=============== +Version 1.5.4 +============= - replace default message on download button below dropzone ; - launch event when dropzone is initialized, to allow to customize events on dropzone; From a4c2b93e1c804835f4fe04b3bae975bd42a5301a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 3 Apr 2020 13:29:48 +0200 Subject: [PATCH 34/58] remove dump messages --- CHANGELOG.md | 3 ++- Object/ObjectToAsyncFileTransformer.php | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ad5d6b8c..6f9a4cd39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Master branch - replace default message on download button below dropzone ; - launch event when dropzone is initialized, to allow to customize events on dropzone; - - add privacy events to document index / show - add privacy events to document edit / update +- remove dump message + diff --git a/Object/ObjectToAsyncFileTransformer.php b/Object/ObjectToAsyncFileTransformer.php index 5501be6ce..c5542d667 100644 --- a/Object/ObjectToAsyncFileTransformer.php +++ b/Object/ObjectToAsyncFileTransformer.php @@ -30,8 +30,6 @@ class ObjectToAsyncFileTransformer implements AsyncFileTransformerInterface public function toAsyncFile($data) { - dump($data); - if ($data instanceof StoredObject) { return $data; } @@ -39,8 +37,6 @@ class ObjectToAsyncFileTransformer implements AsyncFileTransformerInterface public function toData(AsyncFileInterface $asyncFile) { - dump($asyncFile); - $object = $this->em ->getRepository(StoredObject::class) ->findByFilename($asyncFile->getObjectName()) From 48b1bec7eaae20c30d8d91f8a80226dd6fb2396b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 15 Jun 2020 15:18:19 +0200 Subject: [PATCH 35/58] Improve form behaviour to allow removing of document: * add button to remove document ; * fix error when document is removed ; --- CHANGELOG.md | 7 +- .../ChillDocStoreExtension.php | 1 + Form/StoredObjectType.php | 18 ++- Resources/config/services/form.yml | 6 + .../public/module/async_upload/index.scss | 17 ++- .../public/module/async_upload/uploader.js | 128 ++++++++++++++++-- Resources/translations/messages.fr.yml | 1 + Resources/views/Form/fields.html.twig | 2 + 8 files changed, 165 insertions(+), 15 deletions(-) create mode 100644 Resources/config/services/form.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f9a4cd39..3ad4ff222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ Version 1.5.3 - the javascript for uploading a file now works within collections, listening to collection events. -Master branch +Version 1.5.4 ============= - replace default message on download button below dropzone ; @@ -27,3 +27,8 @@ Master branch - add privacy events to document edit / update - remove dump message +Version 1.5.5 +============= + +- add button to remove existing document in form, and improve UI in this part +- fix error when document is removed in form diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index 44141741e..ed36f1845 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -30,6 +30,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $loader->load('services/controller.yml'); $loader->load('services/menu.yml'); $loader->load('services/fixtures.yml'); + $loader->load('services/form.yml'); } public function prepend(ContainerBuilder $container) diff --git a/Form/StoredObjectType.php b/Form/StoredObjectType.php index 824bd62ad..64cc32e83 100644 --- a/Form/StoredObjectType.php +++ b/Form/StoredObjectType.php @@ -10,14 +10,25 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Chill\DocStoreBundle\Entity\StoredObject; use Symfony\Component\Form\CallbackTransformer; +use Doctrine\ORM\EntityManagerInterface; /** - * + * Form type which allow to join a document * - * @author Julien Fastré */ class StoredObjectType extends AbstractType { + /** + * + * @var EntityManagerInterface + */ + protected $em; + + public function __construct(EntityManagerInterface $em) + { + $this->em = $em; + } + public function buildForm(FormBuilderInterface $builder, array $options) { $builder @@ -86,6 +97,9 @@ class StoredObjectType extends AbstractType } if (NULL === $object->getFilename()) { + // remove the original object + $this->em->remove($object); + return null; } diff --git a/Resources/config/services/form.yml b/Resources/config/services/form.yml new file mode 100644 index 000000000..c84507e51 --- /dev/null +++ b/Resources/config/services/form.yml @@ -0,0 +1,6 @@ +services: + Chill\DocStoreBundle\Form\StoredObjectType: + arguments: + $em: '@Doctrine\ORM\EntityManagerInterface' + tags: + - { name: form.type } diff --git a/Resources/public/module/async_upload/index.scss b/Resources/public/module/async_upload/index.scss index 9d42d88d9..54299efce 100644 --- a/Resources/public/module/async_upload/index.scss +++ b/Resources/public/module/async_upload/index.scss @@ -1,6 +1,7 @@ +// override dropzone from dropzoneJS .dropzone { margin-bottom: 0.5rem; - + .dz-preview { display: initial; margin-left: auto; @@ -19,7 +20,15 @@ } } -.sc-button.dz-bt-below-dropzone { - width: 100%; -} +.chill-dropzone__below-zone { + display: flex; + + & > *:not(:last-child) { + margin-right: 1rem; + } + + .sc-button.dz-bt-below-dropzone { + width: 100%; + } +} diff --git a/Resources/public/module/async_upload/uploader.js b/Resources/public/module/async_upload/uploader.js index 9ace4282c..9e96070bb 100644 --- a/Resources/public/module/async_upload/uploader.js +++ b/Resources/public/module/async_upload/uploader.js @@ -98,15 +98,26 @@ var encryptFile = function(originalFile, zoneData, done) { reader.readAsArrayBuffer(originalFile); }; +var addBelowButton = (btn, zone, zoneData) => { + let + belowZone = zone.querySelector('.chill-dropzone__below-zone'); + + if (belowZone === null) { + belowZone = document.createElement('div'); + belowZone.classList.add('chill-dropzone__below-zone'); + zone.appendChild(belowZone); + } + + belowZone.appendChild(btn); +}; -var initialize = function(zone) { +var createZone = (zone, zoneData) => { var created = document.createElement('div'), initMessage = document.createElement('div'), initContent = zone.dataset.labelInitMessage, - zoneData = { zone: zone, suffix: createFilename() }, dropzoneI; - + created.classList.add('dropzone'); initMessage.classList.add('dz-message'); initMessage.appendChild(document.createTextNode(initContent)); @@ -157,8 +168,6 @@ var initialize = function(zone) { zone.insertBefore(created, zone.firstChild); - insertDownloadButton(zone, zoneData); - let event = new CustomEvent("chill_dropzone_initialized", { detail: { dropzone: dropzoneI, @@ -168,6 +177,21 @@ var initialize = function(zone) { window.dispatchEvent(event); }; + +var initialize = function(zone) { + var + allowRemove = zone.dataset.allowRemove, + zoneData = { zone: zone, suffix: createFilename(), allowRemove: allowRemove, old: null } + ; + + if (hasDataInForm(zone, zoneData)) { + insertRemoveButton(zone, zoneData); + insertDownloadButton(zone, zoneData); + } else { + createZone(zone, zoneData); + } +}; + var createFilename = () => { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -195,6 +219,35 @@ var storeDataInForm = (zone, zoneData) => { insertDownloadButton(zone); }; +const restoreDataInForm = (zone, zoneData) => { + var + inputKey = zone.querySelector('input[data-stored-object-key]'), + inputIv = zone.querySelector('input[data-stored-object-iv]'), + inputObject = zone.querySelector('input[data-async-file-upload]'), + inputType = zone.querySelector('input[data-async-file-type]') + ; + + if (zoneData.old === null) { + console.log('should not have restored data'); + return; + } + + inputKey.value = zoneData.old.key; + inputIv.value = zoneData.old.iv; + inputType.value = zoneData.old.type; + inputObject.value = zoneData.old.obj; + + insertDownloadButton(zone); +}; + +const hasDataInForm = (zone, zoneData) => { + var + inputObject = zone.querySelector('input[data-async-file-upload]') + ; + + return inputObject.value.length > 0; +}; + var removeDataInForm = (zone, zoneData) => { var inputKey = zone.querySelector('input[data-stored-object-key]'), @@ -202,7 +255,15 @@ var removeDataInForm = (zone, zoneData) => { inputObject = zone.querySelector('input[data-async-file-upload]'), inputType = zone.querySelector('input[data-async-file-type]') ; - + + // store data for future usage + zoneData.old = { + key: inputKey.value, + iv: inputIv.value, + obj: inputObject.value, + type: inputType.value + }; + // set blank values inputKey.value = ""; inputIv.value = ""; inputType.value = ""; @@ -211,7 +272,57 @@ var removeDataInForm = (zone, zoneData) => { insertDownloadButton(zone); }; -var insertDownloadButton = (zone) => { +var insertRemoveButton = (zone, zoneData) => { + var + removeButton = document.createElement('a'), + cancelButton = document.createElement('a'), + labelRemove = zone.dataset.dictRemove, + labelCancel = 'Restaurer' + ; + + removeButton.classList.add('sc-button', 'bt-delete'); + removeButton.textContent = labelRemove; + + cancelButton.classList.add('sc-button'); + cancelButton.textContent = labelCancel; + + removeButton.addEventListener('click', (e) => { + e.preventDefault(); + if (zoneData.allowRemove === 'true') { + removeDataInForm(zone, zoneData); + cancelButton.addEventListener('click', (e) => { + e.preventDefault(); + + restoreDataInForm(zone, zoneData); + + cancelButton.remove(); + zone.querySelector('.dropzone').remove(); + + initialize(zone); + }); + } + addBelowButton(cancelButton, zone, zoneData); + //zone.appendChild(cancelButton); + removeButton.remove(); + createZone(zone, zoneData); + }); + + addBelowButton(removeButton, zone, zoneData); + // zone.appendChild(removeButton); +}; + +const removeDownloadButton = (zone, zoneData) => { + var + existingButtons = zone.querySelectorAll('a[data-download-button]') + ; + + // remove existing + existingButtons.forEach(function(b) { + b.remove(); + }); +}; + +var insertDownloadButton = (zone, zoneData) => { var existingButtons = zone.querySelectorAll('a[data-download-button]'), newButton = document.createElement('a'), @@ -247,7 +358,8 @@ var insertDownloadButton = (zone) => { newButton.classList.add('sc-button', 'bt-download', 'dz-bt-below-dropzone'); newButton.textContent = labelQuietButton; - zone.appendChild(newButton); + addBelowButton(newButton, zone, zoneData); + //zone.appendChild(newButton); initializeDownload(zone); }; diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index adf017864..5e46490a6 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -24,3 +24,4 @@ Max files exceeded. Remove previous files: Nombre maximum de fichier atteint. Su Cancel upload: Annuler le téléversement Are you sure you want to cancel this upload ?: Êtes-vous sûrs de vouloir annuler ce téléversement ? Upload canceled: Téléversement annulé +Remove existing file: Supprimer le document existant \ No newline at end of file diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index f9253c267..3ab0ff255 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -11,6 +11,8 @@ data-dict-cancel-upload="{{ 'Cancel upload'|trans|escape('html_attr') }}" data-dict-cancel-upload-confirm="{{ 'Are you sure you want to cancel this upload ?'|trans|escape('html_attr') }}" data-dict-upload-canceled="{{ 'Upload canceled'|trans|escape('html_attr') }}" + data-dict-remove="{{ 'Remove existing file'|trans|escape('html_attr') }}" + data-allow-remove="{% if required %}false{% else %}true{% endif %}" data-temp-url-generator="{{ path('async_upload.generate_url', { 'method': 'GET' })|escape('html_attr') }}"> {{ form_widget(form.filename) }} {{ form_widget(form.keyInfos, { 'attr': { 'data-stored-object-key': 1 } }) }} From 3b5cbd457bb2a90b1e71f8e1795f993bfe9d71dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 17 Jun 2020 13:56:14 +0200 Subject: [PATCH 36/58] open document in blank window --- Resources/public/module/async_upload/downloader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/public/module/async_upload/downloader.js b/Resources/public/module/async_upload/downloader.js index cfeee5c37..deeb2828f 100644 --- a/Resources/public/module/async_upload/downloader.js +++ b/Resources/public/module/async_upload/downloader.js @@ -87,7 +87,7 @@ var download = (button) => { url = window.URL.createObjectURL(blob) ; button.href = url; - button.target = '_parent'; + button.target = '_blank'; button.type = mimeType; button.textContent = labelReady; if (hasFilename) { From 21acbc7a06e128a83dc75f79e1355965d9fde3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 1 Jul 2020 17:35:16 +0200 Subject: [PATCH 37/58] fix capitalization of title on person document pages --- CHANGELOG.md | 5 +++++ Resources/translations/messages.fr.yml | 3 ++- Resources/views/PersonDocument/edit.html.twig | 2 +- Resources/views/PersonDocument/index.html.twig | 4 ++-- Resources/views/PersonDocument/new.html.twig | 4 ++-- Resources/views/PersonDocument/show.html.twig | 4 ++-- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ad4ff222..1d9c05143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,3 +32,8 @@ Version 1.5.5 - add button to remove existing document in form, and improve UI in this part - fix error when document is removed in form + +Master branch +============= + +- fix capitalization of person document pages diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 5e46490a6..3d69655d7 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -15,6 +15,7 @@ No document to download: Aucun document à télécharger Any document found: Aucun document trouvé The document is successfully registered: Le document est enregistré The document is successfully updated: Le document est mis à jour +Any description: Aucune description # dropzone upload File too big: Fichier trop volumineux @@ -24,4 +25,4 @@ Max files exceeded. Remove previous files: Nombre maximum de fichier atteint. Su Cancel upload: Annuler le téléversement Are you sure you want to cancel this upload ?: Êtes-vous sûrs de vouloir annuler ce téléversement ? Upload canceled: Téléversement annulé -Remove existing file: Supprimer le document existant \ No newline at end of file +Remove existing file: Supprimer le document existant diff --git a/Resources/views/PersonDocument/edit.html.twig b/Resources/views/PersonDocument/edit.html.twig index 6c18e8474..704031abb 100644 --- a/Resources/views/PersonDocument/edit.html.twig +++ b/Resources/views/PersonDocument/edit.html.twig @@ -19,7 +19,7 @@ {% set activeRouteKey = '' %} -{% block title %}{{ 'Editing document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} +{% block title %}{{ 'Editing document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %} {% block personcontent %}

          {{ 'Edit Document' | trans }}

          diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig index 34cb0e905..5f6f3632a 100644 --- a/Resources/views/PersonDocument/index.html.twig +++ b/Resources/views/PersonDocument/index.html.twig @@ -21,14 +21,14 @@ {% import "@ChillDocStore/Macro/macro.html.twig" as m %} -{% block title %}{{ 'Documents for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} +{% block title %}{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %} {% block js %} {% endblock %} {% block personcontent %} -

          {{ 'Documents for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}

          +

          {{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}

          diff --git a/Resources/views/PersonDocument/new.html.twig b/Resources/views/PersonDocument/new.html.twig index fe807f3b3..7a643b985 100644 --- a/Resources/views/PersonDocument/new.html.twig +++ b/Resources/views/PersonDocument/new.html.twig @@ -18,10 +18,10 @@ {% set activeRouteKey = '' %} -{% block title %}{{ 'New document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} +{% block title %}{{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %} {% block personcontent %} -

          {{ 'New document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}

          +

          {{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}

          {{ form_errors(form) }} diff --git a/Resources/views/PersonDocument/show.html.twig b/Resources/views/PersonDocument/show.html.twig index 989cd1a07..5a929d5ea 100644 --- a/Resources/views/PersonDocument/show.html.twig +++ b/Resources/views/PersonDocument/show.html.twig @@ -20,7 +20,7 @@ {% import "@ChillDocStore/Macro/macro.html.twig" as m %} -{% block title %}{{ 'Detail of document of %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} +{% block title %}{{ 'Detail of document of %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %} {% block js %} @@ -42,7 +42,7 @@
          {{ 'Description' | trans }}
          {% if document.description is empty %} - {{ 'Any description' }} + {{ 'Any description'|trans }} {% else %}
          {{ document.description }} From c5b1caefb6bff944d53bc3f2b29be797f8e91268 Mon Sep 17 00:00:00 2001 From: Tchama Date: Thu, 23 Jul 2020 12:51:07 +0200 Subject: [PATCH 38/58] fix sf4 deprecated: improve relying AuthorizationHelper service --- Controller/DocumentPersonController.php | 14 +++++++++++--- Resources/config/services/controller.yml | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php index f6f074610..688977de8 100644 --- a/Controller/DocumentPersonController.php +++ b/Controller/DocumentPersonController.php @@ -5,6 +5,7 @@ namespace Chill\DocStoreBundle\Controller; use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\DocStoreBundle\Form\PersonDocumentType; use Chill\DocStoreBundle\Repository\DocumentRepository; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\PersonBundle\Privacy\PrivacyEvent; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -36,16 +37,23 @@ class DocumentPersonController extends Controller */ protected $eventDispatcher; + /** + * @var AuthorizationHelper + */ + protected $authorizationHelper; + /** * DocumentPersonController constructor. - * + * @param TranslatorInterface $translator * @param EventDispatcherInterface $eventDispatcher + * @param AuthorizationHelper $authorizationHelper */ - public function __construct(TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher) + public function __construct(TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher, AuthorizationHelper $authorizationHelper) { $this->translator = $translator; $this->eventDispatcher = $eventDispatcher; + $this->authorizationHelper = $authorizationHelper; } /** @@ -61,7 +69,7 @@ class DocumentPersonController extends Controller $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); - $reachableScopes = $this->get('chill.main.security.authorization.helper') + $reachableScopes = $this->authorizationHelper ->getReachableScopes( $this->getUser(), new Role(PersonDocumentVoter::SEE), $person->getCenter()); diff --git a/Resources/config/services/controller.yml b/Resources/config/services/controller.yml index 0a2798508..ed2c55410 100644 --- a/Resources/config/services/controller.yml +++ b/Resources/config/services/controller.yml @@ -5,5 +5,7 @@ services: Chill\DocStoreBundle\Controller\DocumentPersonController: autowire: true + public: true # TODO sf4, check if service could be public arguments: $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' + $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' From d7cdeaa28e62ee5875c1e5da5d9e03fd495ea451 Mon Sep 17 00:00:00 2001 From: nobohan Date: Thu, 23 Jul 2020 14:55:44 +0200 Subject: [PATCH 39/58] sf4 deprecations: new supports and voteOnAttribute methods implemented in PersonDocumentVoter --- Resources/config/services.yml | 2 + .../Authorization/PersonDocumentVoter.php | 75 +++++++++++++++++-- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 4439c8dbb..79aa64ffa 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -18,7 +18,9 @@ services: Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter: class: Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter arguments: + - "@security.access.decision_manager" - "@chill.main.security.authorization.helper" + - "@logger" tags: - { name: security.voter } - { name: chill.role } diff --git a/Security/Authorization/PersonDocumentVoter.php b/Security/Authorization/PersonDocumentVoter.php index 47bfed38b..78429b439 100644 --- a/Security/Authorization/PersonDocumentVoter.php +++ b/Security/Authorization/PersonDocumentVoter.php @@ -24,6 +24,12 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\PersonBundle\Entity\Person; +use Chill\MainBundle\Entity\User; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Role\Role; +use Psr\Log\LoggerInterface; /** * @@ -37,16 +43,31 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE'; /** - * * @var AuthorizationHelper */ - protected $helper; + protected $authorizationHelper; - public function __construct(AuthorizationHelper $helper) + /** + * @var AccessDecisionManagerInterface + */ + protected $accessDecisionManager; + + /** + * @var LoggerInterface + */ + protected $logger; + + public function __construct( + AccessDecisionManagerInterface $accessDecisionManager, + AuthorizationHelper $authorizationHelper, + LoggerInterface $logger + ) { - $this->helper = $helper; + $this->accessDecisionManager = $accessDecisionManager; + $this->authorizationHelper = $authorizationHelper; + $this->logger = $logger; } - + public function getRoles() { return [ @@ -71,9 +92,51 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera return false; } + /** + * + * @param string $attribute + * @param PersonDocument $subject + * @param TokenInterface $token + * @return boolean + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + $this->logger->debug(sprintf("Voting from %s class", self::class)); + + if (!$token->getUser() instanceof User) { + return false; + } + + if ($subject instanceof PersonDocument) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + + } elseif ($subject instanceof Person) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + + } else { + + // subject is null. We check that at least one center is reachable + $centers = $this->authorizationHelper + ->getReachableCenters($token->getUser(), new Role($attribute)); + + return count($centers) > 0; + } + + if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { + return false; + } + + return $this->authorizationHelper->userHasAccess( + $token->getUser(), + $subject, + $attribute + ); + + } + protected function isGranted($attribute, $report, $user = null) { - if (! $user instanceof \Chill\MainBundle\Entity\User){ + if (! $user instanceof User){ return false; } From 96c598db4629d03d0ae11d9ff8cd6a1de7bfebb5 Mon Sep 17 00:00:00 2001 From: Tchama Date: Mon, 27 Jul 2020 19:43:43 +0200 Subject: [PATCH 40/58] sf4, fix section menu translations and add missing translations --- Resources/translations/messages.fr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 5e46490a6..d46a1d485 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -1,4 +1,5 @@ Document: Document +Documents: Documents Documents for %name%: Documents de %name% Preparing: En préparation Ready to show: Prêt à être visualisé From 4527ed35a38a0afc4ef366ec2eaf601e965d19cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 28 Jul 2020 13:36:27 +0200 Subject: [PATCH 41/58] mark all services as private --- Resources/config/services/controller.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Resources/config/services/controller.yml b/Resources/config/services/controller.yml index ed2c55410..bf87727e8 100644 --- a/Resources/config/services/controller.yml +++ b/Resources/config/services/controller.yml @@ -4,8 +4,6 @@ services: tags: ['controller.service_arguments'] Chill\DocStoreBundle\Controller\DocumentPersonController: - autowire: true - public: true # TODO sf4, check if service could be public arguments: $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' - $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' + $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' \ No newline at end of file From a4798e39b177bbccdfe2b6b2fa608c51b9c67218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 28 Jul 2020 13:41:20 +0200 Subject: [PATCH 42/58] fix person document controller definition --- Controller/DocumentPersonController.php | 7 +++++-- Resources/config/services/controller.yml | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php index 688977de8..350069ed9 100644 --- a/Controller/DocumentPersonController.php +++ b/Controller/DocumentPersonController.php @@ -49,8 +49,11 @@ class DocumentPersonController extends Controller * @param EventDispatcherInterface $eventDispatcher * @param AuthorizationHelper $authorizationHelper */ - public function __construct(TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher, AuthorizationHelper $authorizationHelper) - { + public function __construct( + TranslatorInterface $translator, + EventDispatcherInterface $eventDispatcher, + AuthorizationHelper $authorizationHelper + ) { $this->translator = $translator; $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; diff --git a/Resources/config/services/controller.yml b/Resources/config/services/controller.yml index bf87727e8..9108f293b 100644 --- a/Resources/config/services/controller.yml +++ b/Resources/config/services/controller.yml @@ -5,5 +5,7 @@ services: Chill\DocStoreBundle\Controller\DocumentPersonController: arguments: + $translator: '@Symfony\Component\Translation\TranslatorInterface' $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' - $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' \ No newline at end of file + $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' + tags: ['controller.service_arguments'] \ No newline at end of file From 651b528e8ef63a47d6978a70d0b98366a59c661d Mon Sep 17 00:00:00 2001 From: Tchama Date: Tue, 28 Jul 2020 16:44:36 +0200 Subject: [PATCH 43/58] upgrade to symfony4, reset all requires into modules --- composer.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/composer.json b/composer.json index 32cc7695d..384f6c093 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,6 @@ "psr-4": { "Chill\\DocStoreBundle\\" : "" } }, "require": { - "chill-project/person": "~1.5.0", - "champs-libres/async-uploader-bundle": "~1.0" }, "license": "AGPL-3.0" } From e082d35efbf582f3bb0cb0040c4ce60671d153dc Mon Sep 17 00:00:00 2001 From: Tchama Date: Thu, 30 Jul 2020 14:25:28 +0200 Subject: [PATCH 44/58] rename syntax for ChillMain twig template calls --- Resources/views/DocumentCategory/edit.html.twig | 2 +- Resources/views/DocumentCategory/index.html.twig | 2 +- Resources/views/DocumentCategory/new.html.twig | 2 +- Resources/views/DocumentCategory/show.html.twig | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/views/DocumentCategory/edit.html.twig b/Resources/views/DocumentCategory/edit.html.twig index 68c74a29d..cc4d8223b 100644 --- a/Resources/views/DocumentCategory/edit.html.twig +++ b/Resources/views/DocumentCategory/edit.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "@ChillMain/Admin/layout.html.twig" %} {% block title %}{{ 'Document category edit'|trans }}{% endblock title %} diff --git a/Resources/views/DocumentCategory/index.html.twig b/Resources/views/DocumentCategory/index.html.twig index 3aaa7fcf0..612afb2fb 100644 --- a/Resources/views/DocumentCategory/index.html.twig +++ b/Resources/views/DocumentCategory/index.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "@ChillMain/Admin/layout.html.twig" %} {% block title %}{{ 'Document category list' | trans }}{% endblock title %} diff --git a/Resources/views/DocumentCategory/new.html.twig b/Resources/views/DocumentCategory/new.html.twig index a87d42585..8b3f55182 100644 --- a/Resources/views/DocumentCategory/new.html.twig +++ b/Resources/views/DocumentCategory/new.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "@ChillMain/Admin/layout.html.twig" %} {% block title %}{{ 'Create new document category' | trans }}{% endblock title %} diff --git a/Resources/views/DocumentCategory/show.html.twig b/Resources/views/DocumentCategory/show.html.twig index cf323781d..2ba2a301b 100644 --- a/Resources/views/DocumentCategory/show.html.twig +++ b/Resources/views/DocumentCategory/show.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "@ChillMain/Admin/layout.html.twig" %} {% block title %}{{ 'Document category show'|trans }}{% endblock title %} From a709589229ce1c5e6fdd727e861ee9e3d51896fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 31 Jul 2020 15:52:06 +0200 Subject: [PATCH 45/58] adapt migrations files to flex --- .../migrations => migrations}/Version20180605102533.php | 6 +++--- .../migrations => migrations}/Version20180606133338.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) rename {Resources/migrations => migrations}/Version20180605102533.php (95%) rename {Resources/migrations => migrations}/Version20180606133338.php (93%) diff --git a/Resources/migrations/Version20180605102533.php b/migrations/Version20180605102533.php similarity index 95% rename from Resources/migrations/Version20180605102533.php rename to migrations/Version20180605102533.php index 5661277e2..5b9fe27c3 100644 --- a/Resources/migrations/Version20180605102533.php +++ b/migrations/Version20180605102533.php @@ -2,7 +2,7 @@ namespace Application\Migrations; -use Doctrine\DBAL\Migrations\AbstractMigration; +use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; /** @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; */ final class Version20180605102533 extends AbstractMigration { - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -29,7 +29,7 @@ final class Version20180605102533 extends AbstractMigration $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); diff --git a/Resources/migrations/Version20180606133338.php b/migrations/Version20180606133338.php similarity index 93% rename from Resources/migrations/Version20180606133338.php rename to migrations/Version20180606133338.php index 43dae7aa4..3902ad78b 100644 --- a/Resources/migrations/Version20180606133338.php +++ b/migrations/Version20180606133338.php @@ -2,7 +2,7 @@ namespace Application\Migrations; -use Doctrine\DBAL\Migrations\AbstractMigration; +use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; /** @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; */ final class Version20180606133338 extends AbstractMigration { - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -25,7 +25,7 @@ final class Version20180606133338 extends AbstractMigration $this->addSql('CREATE INDEX IDX_41DA53C232D562B ON chill_doc.person_document (object_id)'); } - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); From b2d3580e1153ce780e409b979f9b8156cee688ba Mon Sep 17 00:00:00 2001 From: Tchama Date: Mon, 3 Aug 2020 15:50:56 +0200 Subject: [PATCH 46/58] sf4, fix treebuilder depreciation --- DependencyInjection/Configuration.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 162f6ce99..6c4fa7477 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -17,8 +17,8 @@ class Configuration implements ConfigurationInterface */ public function getConfigTreeBuilder() { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('chill_doc_store'); + $treeBuilder = new TreeBuilder('chill_doc_store'); + $rootNode = $treeBuilder->getRootNode('chill_doc_store'); // Here you should define the parameters that are allowed to // configure your bundle. See the documentation linked above for From 5ad3c659ee8235d00f936555d76dc44db678e9c7 Mon Sep 17 00:00:00 2001 From: Tchama Date: Mon, 3 Aug 2020 16:43:47 +0200 Subject: [PATCH 47/58] sf4, fix errors for activity, doc-store and async-uploader bundles --- Resources/translations/messages.fr.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index d46a1d485..2e0c4ed15 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -10,7 +10,6 @@ New document for %name%: Nouveau document pour %name% Editing document for %name%: Modification d'un document pour %name% Edit Document: Modification d'un document Existing document: Document existant -The document is successfully updated: Le document est mis à jour No document to download: Aucun document à télécharger 'Choose a document category': Choisissez une catégorie de document Any document found: Aucun document trouvé From 98f0ac545ea60debc68be2b2b173f3faf7f9a345 Mon Sep 17 00:00:00 2001 From: Tchama Date: Mon, 3 Aug 2020 18:05:31 +0200 Subject: [PATCH 48/58] sf4, setting new path for all config yaml files, and replace 'controller' path syntax in routes definitions --- DependencyInjection/ChillDocStoreExtension.php | 18 +++++++++--------- .../config/routing.yml => config/routes.yaml | 0 .../services.yml => config/services.yaml | 0 .../services/controller.yaml | 2 +- .../services/fixtures.yaml | 2 +- .../form.yml => config/services/form.yaml | 0 .../media.yml => config/services/media.yaml | 0 .../menu.yml => config/services/menu.yaml | 0 8 files changed, 11 insertions(+), 11 deletions(-) rename Resources/config/routing.yml => config/routes.yaml (100%) rename Resources/config/services.yml => config/services.yaml (100%) rename Resources/config/services/controller.yml => config/services/controller.yaml (92%) rename Resources/config/services/fixtures.yml => config/services/fixtures.yaml (68%) rename Resources/config/services/form.yml => config/services/form.yaml (100%) rename Resources/config/services/media.yml => config/services/media.yaml (100%) rename Resources/config/services/menu.yml => config/services/menu.yaml (100%) diff --git a/DependencyInjection/ChillDocStoreExtension.php b/DependencyInjection/ChillDocStoreExtension.php index ed36f1845..63de15f8b 100644 --- a/DependencyInjection/ChillDocStoreExtension.php +++ b/DependencyInjection/ChillDocStoreExtension.php @@ -24,13 +24,13 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader->load('services.yml'); - $loader->load('services/media.yml'); - $loader->load('services/controller.yml'); - $loader->load('services/menu.yml'); - $loader->load('services/fixtures.yml'); - $loader->load('services/form.yml'); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader->load('services.yaml'); + $loader->load('services/media.yaml'); + $loader->load('services/controller.yaml'); + $loader->load('services/menu.yaml'); + $loader->load('services/fixtures.yaml'); + $loader->load('services/form.yaml'); } public function prepend(ContainerBuilder $container) @@ -46,8 +46,8 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $container->prependExtensionConfig('chill_main', array( 'routing' => array( 'resources' => array( - '@ChillDocStoreBundle/Resources/config/routing.yml', - '@ChampsLibresAsyncUploaderBundle/Resources/config/routing.yml' + '@ChillDocStoreBundle/config/routes.yaml', + '@ChampsLibresAsyncUploaderBundle/config/routes.yaml' ) ) )); diff --git a/Resources/config/routing.yml b/config/routes.yaml similarity index 100% rename from Resources/config/routing.yml rename to config/routes.yaml diff --git a/Resources/config/services.yml b/config/services.yaml similarity index 100% rename from Resources/config/services.yml rename to config/services.yaml diff --git a/Resources/config/services/controller.yml b/config/services/controller.yaml similarity index 92% rename from Resources/config/services/controller.yml rename to config/services/controller.yaml index 9108f293b..9899ffa2e 100644 --- a/Resources/config/services/controller.yml +++ b/config/services/controller.yaml @@ -1,6 +1,6 @@ services: Chill\DocStoreBundle\Controller\: - resource: '../../../Controller' + resource: '../../Controller' tags: ['controller.service_arguments'] Chill\DocStoreBundle\Controller\DocumentPersonController: diff --git a/Resources/config/services/fixtures.yml b/config/services/fixtures.yaml similarity index 68% rename from Resources/config/services/fixtures.yml rename to config/services/fixtures.yaml index c9bc451d6..8a5b299ba 100644 --- a/Resources/config/services/fixtures.yml +++ b/config/services/fixtures.yaml @@ -1,4 +1,4 @@ services: Chill\DocStoreBundle\DataFixtures\ORM\: - resource: ../../../DataFixtures/ORM + resource: ../../DataFixtures/ORM tags: [ 'doctrine.fixture.orm' ] diff --git a/Resources/config/services/form.yml b/config/services/form.yaml similarity index 100% rename from Resources/config/services/form.yml rename to config/services/form.yaml diff --git a/Resources/config/services/media.yml b/config/services/media.yaml similarity index 100% rename from Resources/config/services/media.yml rename to config/services/media.yaml diff --git a/Resources/config/services/menu.yml b/config/services/menu.yaml similarity index 100% rename from Resources/config/services/menu.yml rename to config/services/menu.yaml From b8bf9bebcd91e34fbaf82250f98272b322136bff Mon Sep 17 00:00:00 2001 From: Tchama Date: Tue, 4 Aug 2020 16:28:07 +0200 Subject: [PATCH 49/58] move files from Resources/translations/ to translations/ --- {Resources/translations => translations}/messages.fr.yml | 0 {Resources/translations => translations}/validators.fr.yml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {Resources/translations => translations}/messages.fr.yml (100%) rename {Resources/translations => translations}/validators.fr.yml (100%) diff --git a/Resources/translations/messages.fr.yml b/translations/messages.fr.yml similarity index 100% rename from Resources/translations/messages.fr.yml rename to translations/messages.fr.yml diff --git a/Resources/translations/validators.fr.yml b/translations/validators.fr.yml similarity index 100% rename from Resources/translations/validators.fr.yml rename to translations/validators.fr.yml From 8371487b2e0f5557a7c60ae92d5d1c800ee5fafa Mon Sep 17 00:00:00 2001 From: Tchama Date: Fri, 4 Sep 2020 20:35:32 +0200 Subject: [PATCH 50/58] fix deprecated ObjectManager path in data fixtures scripts --- DataFixtures/ORM/LoadDocumentACL.php | 2 +- DataFixtures/ORM/LoadDocumentCategory.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DataFixtures/ORM/LoadDocumentACL.php b/DataFixtures/ORM/LoadDocumentACL.php index c17e795e6..0f4577ffd 100644 --- a/DataFixtures/ORM/LoadDocumentACL.php +++ b/DataFixtures/ORM/LoadDocumentACL.php @@ -21,7 +21,7 @@ namespace Chill\DocStoreBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectManager; use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; use Chill\MainBundle\Entity\RoleScope; use Chill\MainBundle\DataFixtures\ORM\LoadScopes; diff --git a/DataFixtures/ORM/LoadDocumentCategory.php b/DataFixtures/ORM/LoadDocumentCategory.php index 37e55c5b7..2eb6e7181 100644 --- a/DataFixtures/ORM/LoadDocumentCategory.php +++ b/DataFixtures/ORM/LoadDocumentCategory.php @@ -19,7 +19,7 @@ namespace Chill\DocStoreBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectManager; use Chill\DocStoreBundle\Entity\DocumentCategory; /** From 3bc05ac2a61ae3f7b01a980efe3d43b4e92880ba Mon Sep 17 00:00:00 2001 From: Tchama Date: Sun, 6 Sep 2020 20:32:46 +0200 Subject: [PATCH 51/58] use '@foo/bar.html.twig' syntax in twig templates --- Resources/views/PersonDocument/edit.html.twig | 2 +- Resources/views/PersonDocument/index.html.twig | 2 +- Resources/views/PersonDocument/new.html.twig | 2 +- Resources/views/PersonDocument/show.html.twig | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/views/PersonDocument/edit.html.twig b/Resources/views/PersonDocument/edit.html.twig index 6c18e8474..2da94e141 100644 --- a/Resources/views/PersonDocument/edit.html.twig +++ b/Resources/views/PersonDocument/edit.html.twig @@ -15,7 +15,7 @@ * along with this program. If not, see . #} -{% extends "ChillPersonBundle::layout.html.twig" %} +{% extends "@ChillPerson/layout.html.twig" %} {% set activeRouteKey = '' %} diff --git a/Resources/views/PersonDocument/index.html.twig b/Resources/views/PersonDocument/index.html.twig index 34cb0e905..b36db985e 100644 --- a/Resources/views/PersonDocument/index.html.twig +++ b/Resources/views/PersonDocument/index.html.twig @@ -15,7 +15,7 @@ * along with this program. If not, see . #} -{% extends "ChillPersonBundle::layout.html.twig" %} +{% extends "@ChillPerson/layout.html.twig" %} {% set activeRouteKey = '' %} diff --git a/Resources/views/PersonDocument/new.html.twig b/Resources/views/PersonDocument/new.html.twig index fe807f3b3..0ea810576 100644 --- a/Resources/views/PersonDocument/new.html.twig +++ b/Resources/views/PersonDocument/new.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillPersonBundle::layout.html.twig" %} +{% extends "@ChillPerson/layout.html.twig" %} {% set activeRouteKey = '' %} diff --git a/Resources/views/PersonDocument/show.html.twig b/Resources/views/PersonDocument/show.html.twig index 989cd1a07..979c628cd 100644 --- a/Resources/views/PersonDocument/show.html.twig +++ b/Resources/views/PersonDocument/show.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillPersonBundle::layout.html.twig" %} +{% extends "@ChillPerson/layout.html.twig" %} {% set activeRouteKey = '' %} From bee6548d7843b1799478d62b4d65c34fc6ad125f Mon Sep 17 00:00:00 2001 From: Tchama Date: Tue, 8 Sep 2020 15:42:42 +0200 Subject: [PATCH 52/58] rename deprecated using path for ObjectManager --- Form/PersonDocumentType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Form/PersonDocumentType.php b/Form/PersonDocumentType.php index ffb494ec8..184bbbe33 100644 --- a/Form/PersonDocumentType.php +++ b/Form/PersonDocumentType.php @@ -15,7 +15,7 @@ use Doctrine\ORM\EntityRepository; use Chill\MainBundle\Form\Type\AppendScopeChoiceTypeTrait; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectManager; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ScopePickerType; From e01794db680b5821b4d8aaa6ea88eed9952b475d Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 26 Jan 2021 15:21:21 +0100 Subject: [PATCH 53/58] translating all roles in admin interface --- translations/messages.fr.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/translations/messages.fr.yml b/translations/messages.fr.yml index 44ef5e337..aef34ce00 100644 --- a/translations/messages.fr.yml +++ b/translations/messages.fr.yml @@ -26,3 +26,11 @@ Cancel upload: Annuler le téléversement Are you sure you want to cancel this upload ?: Êtes-vous sûrs de vouloir annuler ce téléversement ? Upload canceled: Téléversement annulé Remove existing file: Supprimer le document existant + +# ROLES +PersonDocument: Documents +CHILL_PERSON_DOCUMENT_CREATE: Ajouter un document +CHILL_PERSON_DOCUMENT_DELETE: Supprimer un document +CHILL_PERSON_DOCUMENT_SEE: Voir un document +CHILL_PERSON_DOCUMENT_SEE_DETAILS: Voir le détail d'un document +CHILL_PERSON_DOCUMENT_UPDATE: Modifier un document From 7ef534438e891f8f07318a639bef6259ea38248b Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 1 Feb 2021 18:17:33 +0100 Subject: [PATCH 54/58] Replace deprecated extends Controller by AbstractController --- Controller/DocumentCategoryController.php | 7 +++++-- Controller/DocumentPersonController.php | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Controller/DocumentCategoryController.php b/Controller/DocumentCategoryController.php index 2a4225eac..abbfbd1c0 100644 --- a/Controller/DocumentCategoryController.php +++ b/Controller/DocumentCategoryController.php @@ -5,15 +5,18 @@ namespace Chill\DocStoreBundle\Controller; use Chill\DocStoreBundle\Entity\DocumentCategory; use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\DocStoreBundle\Form\DocumentCategoryType; -use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; /** + * Class DocumentCategoryController + * + * @package Chill\DocStoreBundle\Controller * @Route("/{_locale}/admin/document/category") */ -class DocumentCategoryController extends Controller +class DocumentCategoryController extends AbstractController { /** * @Route("/", name="document_category_index", methods="GET") diff --git a/Controller/DocumentPersonController.php b/Controller/DocumentPersonController.php index 350069ed9..57ef81cbb 100644 --- a/Controller/DocumentPersonController.php +++ b/Controller/DocumentPersonController.php @@ -7,7 +7,7 @@ use Chill\DocStoreBundle\Form\PersonDocumentType; use Chill\DocStoreBundle\Repository\DocumentRepository; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\PersonBundle\Privacy\PrivacyEvent; -use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,11 +19,14 @@ use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; use Symfony\Component\Translation\TranslatorInterface; /** + * Class DocumentPersonController + * + * @package Chill\DocStoreBundle\Controller * @Route("/{_locale}/person/{person}/document") * * TODO faire un controller abstrait ? */ -class DocumentPersonController extends Controller +class DocumentPersonController extends AbstractController { /** From 6f80bd0d37a3e7fac407203f79f50cc5e73b445a Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Sat, 6 Feb 2021 13:51:46 +0100 Subject: [PATCH 55/58] improve ux in admin configuration interface --- Controller/AdminController.php | 30 ++++++++++++++++++ Controller/DocumentCategoryController.php | 2 +- Resources/views/Admin/layout.html.twig | 31 +++++++++++++++++++ Resources/views/Admin/menu.html.twig | 21 +++++++++++++ .../views/DocumentCategory/_form.html.twig | 2 +- .../views/DocumentCategory/edit.html.twig | 23 ++++++++++---- .../views/DocumentCategory/index.html.twig | 18 ++++++----- .../views/DocumentCategory/new.html.twig | 23 +++++++++++--- .../views/DocumentCategory/show.html.twig | 26 +++++++++------- config/routes.yaml | 29 +++++++++++++++++ translations/messages.fr.yml | 17 ++++++++++ 11 files changed, 190 insertions(+), 32 deletions(-) create mode 100644 Controller/AdminController.php create mode 100644 Resources/views/Admin/layout.html.twig create mode 100644 Resources/views/Admin/menu.html.twig diff --git a/Controller/AdminController.php b/Controller/AdminController.php new file mode 100644 index 000000000..3a24dfb99 --- /dev/null +++ b/Controller/AdminController.php @@ -0,0 +1,30 @@ +render('ChillDocStoreBundle:Admin:layout.html.twig'); + } + + /** + * @return \Symfony\Component\HttpFoundation\RedirectResponse + */ + public function redirectToAdminIndexAction() + { + return $this->redirectToRoute('chill_main_admin_central'); + } + +} \ No newline at end of file diff --git a/Controller/DocumentCategoryController.php b/Controller/DocumentCategoryController.php index abbfbd1c0..4d2d3246e 100644 --- a/Controller/DocumentCategoryController.php +++ b/Controller/DocumentCategoryController.php @@ -100,7 +100,7 @@ class DocumentCategoryController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { $this->getDoctrine()->getManager()->flush(); - return $this->redirectToRoute('document_category_edit', [ + return $this->redirectToRoute('document_category_index', [ 'bundleId' => $documentCategory->getBundleId(), 'idInsideBundle' => $documentCategory->getIdInsideBundle(),]); } diff --git a/Resources/views/Admin/layout.html.twig b/Resources/views/Admin/layout.html.twig new file mode 100644 index 000000000..eecfb1751 --- /dev/null +++ b/Resources/views/Admin/layout.html.twig @@ -0,0 +1,31 @@ +{# + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + / + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} + +{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %} + +{% block vertical_menu_content %} + {{ chill_menu('admin_docstore', { + 'layout': '@ChillDocStore/Admin/menu.html.twig', + }) }} +{% endblock %} + +{% block layout_wvm_content %} + {% block admin_content %} +

          {{ 'Documents configuration' |trans }}

          + {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/Resources/views/Admin/menu.html.twig b/Resources/views/Admin/menu.html.twig new file mode 100644 index 000000000..319abc6f1 --- /dev/null +++ b/Resources/views/Admin/menu.html.twig @@ -0,0 +1,21 @@ +{# + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + / + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} + +{% extends "@ChillMain/Menu/verticalMenu.html.twig" %} +{% block v_menu_title %}{{ 'Documents configuration'|trans }}{% endblock %} + diff --git a/Resources/views/DocumentCategory/_form.html.twig b/Resources/views/DocumentCategory/_form.html.twig index e2a0a004d..d6e513458 100644 --- a/Resources/views/DocumentCategory/_form.html.twig +++ b/Resources/views/DocumentCategory/_form.html.twig @@ -16,5 +16,5 @@ #} {{ form_start(form) }} {{ form_widget(form) }} - + {{ form_end(form) }} diff --git a/Resources/views/DocumentCategory/edit.html.twig b/Resources/views/DocumentCategory/edit.html.twig index cc4d8223b..2b0556244 100644 --- a/Resources/views/DocumentCategory/edit.html.twig +++ b/Resources/views/DocumentCategory/edit.html.twig @@ -14,18 +14,29 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "@ChillMain/Admin/layout.html.twig" %} +{% extends "ChillDocStoreBundle:Admin:layout.html.twig" %} {% block title %}{{ 'Document category edit'|trans }}{% endblock title %} {% block admin_content %}

          {{ 'Document category edit'|trans }}

          - {{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig', {'button_label': 'Update'}) }} + {# DISABLED + {{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig', {'button_label': 'Update'}) }} + #} - - {{ 'Back to the category list' | trans }} - + {{ form_start(form) }} + {{ form_widget(form) }} + + {{ form_end(form) }} - {{ include('ChillDocStoreBundle:DocumentCategory:_delete_form.html.twig') }} {% endblock %} diff --git a/Resources/views/DocumentCategory/index.html.twig b/Resources/views/DocumentCategory/index.html.twig index 612afb2fb..48512eff6 100644 --- a/Resources/views/DocumentCategory/index.html.twig +++ b/Resources/views/DocumentCategory/index.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "@ChillMain/Admin/layout.html.twig" %} +{% extends "ChillDocStoreBundle:Admin:layout.html.twig" %} {% block title %}{{ 'Document category list' | trans }}{% endblock title %} @@ -40,12 +40,10 @@
          {% else %} @@ -56,5 +54,9 @@
          {{ document_category.name | localize_translatable_string}} - - {{ 'show' | trans }} - - - {{ 'edit' | trans }} - + +
          - {{ 'Create new' | trans }} + {% endblock %} diff --git a/Resources/views/DocumentCategory/new.html.twig b/Resources/views/DocumentCategory/new.html.twig index 8b3f55182..addf9922f 100644 --- a/Resources/views/DocumentCategory/new.html.twig +++ b/Resources/views/DocumentCategory/new.html.twig @@ -14,16 +14,29 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "@ChillMain/Admin/layout.html.twig" %} +{% extends "ChillDocStoreBundle:Admin:layout.html.twig" %} {% block title %}{{ 'Create new document category' | trans }}{% endblock title %} {% block admin_content %}

          {{ 'Create new DocumentCategory' | trans }}

          - {{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig') }} + {# DISABLED + {{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig') }} + #} + + {{ form_start(form) }} + {{ form_widget(form) }} + + {{ form_end(form) }} - - {{ 'Back to the category list' | trans }} - {% endblock %} diff --git a/Resources/views/DocumentCategory/show.html.twig b/Resources/views/DocumentCategory/show.html.twig index 2ba2a301b..3e3470f12 100644 --- a/Resources/views/DocumentCategory/show.html.twig +++ b/Resources/views/DocumentCategory/show.html.twig @@ -14,12 +14,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "@ChillMain/Admin/layout.html.twig" %} +{% extends "ChillDocStoreBundle:Admin:layout.html.twig" %} {% block title %}{{ 'Document category show'|trans }}{% endblock title %} {% block admin_content %} -

          Document category

          +

          {{ 'Document category show'|trans }}

          @@ -42,13 +42,17 @@
          - - {{ 'Back to the category list' | trans }} - - - - {{ 'Edit' | trans }} - - - {{ include('ChillDocStoreBundle:DocumentCategory:_delete_form.html.twig') }} + {% endblock %} diff --git a/config/routes.yaml b/config/routes.yaml index c02dc76ab..5821aafa5 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -1,3 +1,32 @@ app: resource: "@ChillDocStoreBundle/Controller/" type: annotation + +## ADMIN SECTION +chill_docstore_admin: + path: /{_locale}/admin/document + controller: Chill\DocStoreBundle\Controller\AdminController::indexAction + options: + menus: + admin_section: + order: 2200 + label: "Documents configuration menu" + icons: ['calendar'] + +chill_docstore_admin_redirect_to_admin_index: + path: /{_locale}/admin/document_redirect_to_main + controller: Chill\DocStoreBundle\Controller\AdminController::redirectToAdminIndexAction + options: + menus: + admin_docstore: + order: 0 + label: Main admin menu + +chill_docstore_category_admin: + path: /{_locale}/admin/document/category + controller: Chill\DocStoreBundle\Controller\DocumentCategoryController::indexAction + options: + menus: + admin_docstore: + order: 90 + label: "Documents categories" \ No newline at end of file diff --git a/translations/messages.fr.yml b/translations/messages.fr.yml index aef34ce00..947471531 100644 --- a/translations/messages.fr.yml +++ b/translations/messages.fr.yml @@ -34,3 +34,20 @@ CHILL_PERSON_DOCUMENT_DELETE: Supprimer un document CHILL_PERSON_DOCUMENT_SEE: Voir un document CHILL_PERSON_DOCUMENT_SEE_DETAILS: Voir le détail d'un document CHILL_PERSON_DOCUMENT_UPDATE: Modifier un document + +# Admin +Documents configuration: Configuration des documents +Documents configuration menu: Documents +Documents categories: Catégories de documents + +Document category list: Catégories de documents +Document category show: Voir la catégorie de documents +Document category edit: Modifier la catégorie de documents +Creator bundle id: Module +Bundle id: Module +Internal id inside creator bundle: Identifiant +Id inside bundle: Identifiant +Document class: Classe de document +no records found: +Create new category: Créer une nouvelle catégorie +Back to the category list: Retour à la liste \ No newline at end of file From 3b6750951c526ef1ada8ac28641aa75650801322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 2 Mar 2021 17:15:40 +0100 Subject: [PATCH 56/58] change migration namespace --- migrations/Version20180605102533.php | 2 +- migrations/Version20180606133338.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/migrations/Version20180605102533.php b/migrations/Version20180605102533.php index 5b9fe27c3..8dbc86473 100644 --- a/migrations/Version20180605102533.php +++ b/migrations/Version20180605102533.php @@ -1,6 +1,6 @@ Date: Sat, 6 Mar 2021 14:59:21 +0100 Subject: [PATCH 57/58] minor, cfr MR sf4_cked sur standard, main, person --- chill.webpack.config.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/chill.webpack.config.js b/chill.webpack.config.js index e98df7a23..14f94cd53 100644 --- a/chill.webpack.config.js +++ b/chill.webpack.config.js @@ -1,5 +1,3 @@ module.exports = function(encore) { - let file = __dirname + '/Resources/public/module/async_upload/index.js'; - - encore.addEntry('async_upload', file); + encore.addEntry('async_upload', __dirname + '/Resources/public/module/async_upload/index.js'); }; From e2d341f0bdc6df0894bc295a45c40dc280dacff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 18 Mar 2021 12:46:40 +0100 Subject: [PATCH 58/58] Prepare for moving into monorepo --- .gitignore => src/Bundle/ChillDocStore/.gitignore | 0 .gitlab-ci.yml => src/Bundle/ChillDocStore/.gitlab-ci.yml | 0 CHANGELOG.md => src/Bundle/ChillDocStore/CHANGELOG.md | 0 .../Bundle/ChillDocStore/ChillDocStoreBundle.php | 0 .../Bundle/ChillDocStore/Controller}/AdminController.php | 0 .../ChillDocStore/Controller}/DocumentCategoryController.php | 0 .../Bundle/ChillDocStore/Controller}/DocumentPersonController.php | 0 .../Bundle/ChillDocStore/DataFixtures}/ORM/LoadDocumentACL.php | 0 .../ChillDocStore/DataFixtures}/ORM/LoadDocumentCategory.php | 0 .../ChillDocStore/DependencyInjection}/ChillDocStoreExtension.php | 0 .../Bundle/ChillDocStore/DependencyInjection}/Configuration.php | 0 {Entity => src/Bundle/ChillDocStore/Entity}/Document.php | 0 {Entity => src/Bundle/ChillDocStore/Entity}/DocumentCategory.php | 0 {Entity => src/Bundle/ChillDocStore/Entity}/PersonDocument.php | 0 {Entity => src/Bundle/ChillDocStore/Entity}/StoredObject.php | 0 .../EntityRepository}/DocumentCategoryRepository.php | 0 {Form => src/Bundle/ChillDocStore/Form}/DocumentCategoryType.php | 0 {Form => src/Bundle/ChillDocStore/Form}/PersonDocumentType.php | 0 {Form => src/Bundle/ChillDocStore/Form}/StoredObjectType.php | 0 {Menu => src/Bundle/ChillDocStore/Menu}/MenuBuilder.php | 0 .../Bundle/ChillDocStore/Object}/ObjectToAsyncFileTransformer.php | 0 .../Bundle/ChillDocStore/Object}/PersistenceChecker.php | 0 .../Resources}/public/module/async_upload/downloader.js | 0 .../ChillDocStore/Resources}/public/module/async_upload/index.js | 0 .../Resources}/public/module/async_upload/index.scss | 0 .../Resources}/public/module/async_upload/uploader.js | 0 .../Bundle/ChillDocStore/Resources}/views/Admin/layout.html.twig | 0 .../Bundle/ChillDocStore/Resources}/views/Admin/menu.html.twig | 0 .../Resources}/views/DocumentCategory/_delete_form.html.twig | 0 .../Resources}/views/DocumentCategory/_form.html.twig | 0 .../Resources}/views/DocumentCategory/edit.html.twig | 0 .../Resources}/views/DocumentCategory/index.html.twig | 0 .../ChillDocStore/Resources}/views/DocumentCategory/new.html.twig | 0 .../Resources}/views/DocumentCategory/show.html.twig | 0 .../Bundle/ChillDocStore/Resources}/views/Form/fields.html.twig | 0 .../Bundle/ChillDocStore/Resources}/views/Macro/macro.html.twig | 0 .../Resources}/views/PersonDocument/_delete_form.html.twig | 0 .../ChillDocStore/Resources}/views/PersonDocument/edit.html.twig | 0 .../ChillDocStore/Resources}/views/PersonDocument/index.html.twig | 0 .../ChillDocStore/Resources}/views/PersonDocument/new.html.twig | 0 .../ChillDocStore/Resources}/views/PersonDocument/show.html.twig | 0 .../ChillDocStore/Security}/Authorization/PersonDocumentVoter.php | 0 .../Bundle/ChillDocStore/chill.webpack.config.js | 0 composer.json => src/Bundle/ChillDocStore/composer.json | 0 {config => src/Bundle/ChillDocStore/config}/routes.yaml | 0 {config => src/Bundle/ChillDocStore/config}/services.yaml | 0 .../Bundle/ChillDocStore/config}/services/controller.yaml | 0 .../Bundle/ChillDocStore/config}/services/fixtures.yaml | 0 {config => src/Bundle/ChillDocStore/config}/services/form.yaml | 0 {config => src/Bundle/ChillDocStore/config}/services/media.yaml | 0 {config => src/Bundle/ChillDocStore/config}/services/menu.yaml | 0 .../Bundle/ChillDocStore/migrations}/Version20180605102533.php | 0 .../Bundle/ChillDocStore/migrations}/Version20180606133338.php | 0 .../Bundle/ChillDocStore/translations}/messages.fr.yml | 0 .../Bundle/ChillDocStore/translations}/validators.fr.yml | 0 55 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => src/Bundle/ChillDocStore/.gitignore (100%) rename .gitlab-ci.yml => src/Bundle/ChillDocStore/.gitlab-ci.yml (100%) rename CHANGELOG.md => src/Bundle/ChillDocStore/CHANGELOG.md (100%) rename ChillDocStoreBundle.php => src/Bundle/ChillDocStore/ChillDocStoreBundle.php (100%) rename {Controller => src/Bundle/ChillDocStore/Controller}/AdminController.php (100%) rename {Controller => src/Bundle/ChillDocStore/Controller}/DocumentCategoryController.php (100%) rename {Controller => src/Bundle/ChillDocStore/Controller}/DocumentPersonController.php (100%) rename {DataFixtures => src/Bundle/ChillDocStore/DataFixtures}/ORM/LoadDocumentACL.php (100%) rename {DataFixtures => src/Bundle/ChillDocStore/DataFixtures}/ORM/LoadDocumentCategory.php (100%) rename {DependencyInjection => src/Bundle/ChillDocStore/DependencyInjection}/ChillDocStoreExtension.php (100%) rename {DependencyInjection => src/Bundle/ChillDocStore/DependencyInjection}/Configuration.php (100%) rename {Entity => src/Bundle/ChillDocStore/Entity}/Document.php (100%) rename {Entity => src/Bundle/ChillDocStore/Entity}/DocumentCategory.php (100%) rename {Entity => src/Bundle/ChillDocStore/Entity}/PersonDocument.php (100%) rename {Entity => src/Bundle/ChillDocStore/Entity}/StoredObject.php (100%) rename {EntityRepository => src/Bundle/ChillDocStore/EntityRepository}/DocumentCategoryRepository.php (100%) rename {Form => src/Bundle/ChillDocStore/Form}/DocumentCategoryType.php (100%) rename {Form => src/Bundle/ChillDocStore/Form}/PersonDocumentType.php (100%) rename {Form => src/Bundle/ChillDocStore/Form}/StoredObjectType.php (100%) rename {Menu => src/Bundle/ChillDocStore/Menu}/MenuBuilder.php (100%) rename {Object => src/Bundle/ChillDocStore/Object}/ObjectToAsyncFileTransformer.php (100%) rename {Object => src/Bundle/ChillDocStore/Object}/PersistenceChecker.php (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/public/module/async_upload/downloader.js (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/public/module/async_upload/index.js (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/public/module/async_upload/index.scss (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/public/module/async_upload/uploader.js (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/Admin/layout.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/Admin/menu.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/DocumentCategory/_delete_form.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/DocumentCategory/_form.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/DocumentCategory/edit.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/DocumentCategory/index.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/DocumentCategory/new.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/DocumentCategory/show.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/Form/fields.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/Macro/macro.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/PersonDocument/_delete_form.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/PersonDocument/edit.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/PersonDocument/index.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/PersonDocument/new.html.twig (100%) rename {Resources => src/Bundle/ChillDocStore/Resources}/views/PersonDocument/show.html.twig (100%) rename {Security => src/Bundle/ChillDocStore/Security}/Authorization/PersonDocumentVoter.php (100%) rename chill.webpack.config.js => src/Bundle/ChillDocStore/chill.webpack.config.js (100%) rename composer.json => src/Bundle/ChillDocStore/composer.json (100%) rename {config => src/Bundle/ChillDocStore/config}/routes.yaml (100%) rename {config => src/Bundle/ChillDocStore/config}/services.yaml (100%) rename {config => src/Bundle/ChillDocStore/config}/services/controller.yaml (100%) rename {config => src/Bundle/ChillDocStore/config}/services/fixtures.yaml (100%) rename {config => src/Bundle/ChillDocStore/config}/services/form.yaml (100%) rename {config => src/Bundle/ChillDocStore/config}/services/media.yaml (100%) rename {config => src/Bundle/ChillDocStore/config}/services/menu.yaml (100%) rename {migrations => src/Bundle/ChillDocStore/migrations}/Version20180605102533.php (100%) rename {migrations => src/Bundle/ChillDocStore/migrations}/Version20180606133338.php (100%) rename {translations => src/Bundle/ChillDocStore/translations}/messages.fr.yml (100%) rename {translations => src/Bundle/ChillDocStore/translations}/validators.fr.yml (100%) diff --git a/.gitignore b/src/Bundle/ChillDocStore/.gitignore similarity index 100% rename from .gitignore rename to src/Bundle/ChillDocStore/.gitignore diff --git a/.gitlab-ci.yml b/src/Bundle/ChillDocStore/.gitlab-ci.yml similarity index 100% rename from .gitlab-ci.yml rename to src/Bundle/ChillDocStore/.gitlab-ci.yml diff --git a/CHANGELOG.md b/src/Bundle/ChillDocStore/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to src/Bundle/ChillDocStore/CHANGELOG.md diff --git a/ChillDocStoreBundle.php b/src/Bundle/ChillDocStore/ChillDocStoreBundle.php similarity index 100% rename from ChillDocStoreBundle.php rename to src/Bundle/ChillDocStore/ChillDocStoreBundle.php diff --git a/Controller/AdminController.php b/src/Bundle/ChillDocStore/Controller/AdminController.php similarity index 100% rename from Controller/AdminController.php rename to src/Bundle/ChillDocStore/Controller/AdminController.php diff --git a/Controller/DocumentCategoryController.php b/src/Bundle/ChillDocStore/Controller/DocumentCategoryController.php similarity index 100% rename from Controller/DocumentCategoryController.php rename to src/Bundle/ChillDocStore/Controller/DocumentCategoryController.php diff --git a/Controller/DocumentPersonController.php b/src/Bundle/ChillDocStore/Controller/DocumentPersonController.php similarity index 100% rename from Controller/DocumentPersonController.php rename to src/Bundle/ChillDocStore/Controller/DocumentPersonController.php diff --git a/DataFixtures/ORM/LoadDocumentACL.php b/src/Bundle/ChillDocStore/DataFixtures/ORM/LoadDocumentACL.php similarity index 100% rename from DataFixtures/ORM/LoadDocumentACL.php rename to src/Bundle/ChillDocStore/DataFixtures/ORM/LoadDocumentACL.php diff --git a/DataFixtures/ORM/LoadDocumentCategory.php b/src/Bundle/ChillDocStore/DataFixtures/ORM/LoadDocumentCategory.php similarity index 100% rename from DataFixtures/ORM/LoadDocumentCategory.php rename to src/Bundle/ChillDocStore/DataFixtures/ORM/LoadDocumentCategory.php diff --git a/DependencyInjection/ChillDocStoreExtension.php b/src/Bundle/ChillDocStore/DependencyInjection/ChillDocStoreExtension.php similarity index 100% rename from DependencyInjection/ChillDocStoreExtension.php rename to src/Bundle/ChillDocStore/DependencyInjection/ChillDocStoreExtension.php diff --git a/DependencyInjection/Configuration.php b/src/Bundle/ChillDocStore/DependencyInjection/Configuration.php similarity index 100% rename from DependencyInjection/Configuration.php rename to src/Bundle/ChillDocStore/DependencyInjection/Configuration.php diff --git a/Entity/Document.php b/src/Bundle/ChillDocStore/Entity/Document.php similarity index 100% rename from Entity/Document.php rename to src/Bundle/ChillDocStore/Entity/Document.php diff --git a/Entity/DocumentCategory.php b/src/Bundle/ChillDocStore/Entity/DocumentCategory.php similarity index 100% rename from Entity/DocumentCategory.php rename to src/Bundle/ChillDocStore/Entity/DocumentCategory.php diff --git a/Entity/PersonDocument.php b/src/Bundle/ChillDocStore/Entity/PersonDocument.php similarity index 100% rename from Entity/PersonDocument.php rename to src/Bundle/ChillDocStore/Entity/PersonDocument.php diff --git a/Entity/StoredObject.php b/src/Bundle/ChillDocStore/Entity/StoredObject.php similarity index 100% rename from Entity/StoredObject.php rename to src/Bundle/ChillDocStore/Entity/StoredObject.php diff --git a/EntityRepository/DocumentCategoryRepository.php b/src/Bundle/ChillDocStore/EntityRepository/DocumentCategoryRepository.php similarity index 100% rename from EntityRepository/DocumentCategoryRepository.php rename to src/Bundle/ChillDocStore/EntityRepository/DocumentCategoryRepository.php diff --git a/Form/DocumentCategoryType.php b/src/Bundle/ChillDocStore/Form/DocumentCategoryType.php similarity index 100% rename from Form/DocumentCategoryType.php rename to src/Bundle/ChillDocStore/Form/DocumentCategoryType.php diff --git a/Form/PersonDocumentType.php b/src/Bundle/ChillDocStore/Form/PersonDocumentType.php similarity index 100% rename from Form/PersonDocumentType.php rename to src/Bundle/ChillDocStore/Form/PersonDocumentType.php diff --git a/Form/StoredObjectType.php b/src/Bundle/ChillDocStore/Form/StoredObjectType.php similarity index 100% rename from Form/StoredObjectType.php rename to src/Bundle/ChillDocStore/Form/StoredObjectType.php diff --git a/Menu/MenuBuilder.php b/src/Bundle/ChillDocStore/Menu/MenuBuilder.php similarity index 100% rename from Menu/MenuBuilder.php rename to src/Bundle/ChillDocStore/Menu/MenuBuilder.php diff --git a/Object/ObjectToAsyncFileTransformer.php b/src/Bundle/ChillDocStore/Object/ObjectToAsyncFileTransformer.php similarity index 100% rename from Object/ObjectToAsyncFileTransformer.php rename to src/Bundle/ChillDocStore/Object/ObjectToAsyncFileTransformer.php diff --git a/Object/PersistenceChecker.php b/src/Bundle/ChillDocStore/Object/PersistenceChecker.php similarity index 100% rename from Object/PersistenceChecker.php rename to src/Bundle/ChillDocStore/Object/PersistenceChecker.php diff --git a/Resources/public/module/async_upload/downloader.js b/src/Bundle/ChillDocStore/Resources/public/module/async_upload/downloader.js similarity index 100% rename from Resources/public/module/async_upload/downloader.js rename to src/Bundle/ChillDocStore/Resources/public/module/async_upload/downloader.js diff --git a/Resources/public/module/async_upload/index.js b/src/Bundle/ChillDocStore/Resources/public/module/async_upload/index.js similarity index 100% rename from Resources/public/module/async_upload/index.js rename to src/Bundle/ChillDocStore/Resources/public/module/async_upload/index.js diff --git a/Resources/public/module/async_upload/index.scss b/src/Bundle/ChillDocStore/Resources/public/module/async_upload/index.scss similarity index 100% rename from Resources/public/module/async_upload/index.scss rename to src/Bundle/ChillDocStore/Resources/public/module/async_upload/index.scss diff --git a/Resources/public/module/async_upload/uploader.js b/src/Bundle/ChillDocStore/Resources/public/module/async_upload/uploader.js similarity index 100% rename from Resources/public/module/async_upload/uploader.js rename to src/Bundle/ChillDocStore/Resources/public/module/async_upload/uploader.js diff --git a/Resources/views/Admin/layout.html.twig b/src/Bundle/ChillDocStore/Resources/views/Admin/layout.html.twig similarity index 100% rename from Resources/views/Admin/layout.html.twig rename to src/Bundle/ChillDocStore/Resources/views/Admin/layout.html.twig diff --git a/Resources/views/Admin/menu.html.twig b/src/Bundle/ChillDocStore/Resources/views/Admin/menu.html.twig similarity index 100% rename from Resources/views/Admin/menu.html.twig rename to src/Bundle/ChillDocStore/Resources/views/Admin/menu.html.twig diff --git a/Resources/views/DocumentCategory/_delete_form.html.twig b/src/Bundle/ChillDocStore/Resources/views/DocumentCategory/_delete_form.html.twig similarity index 100% rename from Resources/views/DocumentCategory/_delete_form.html.twig rename to src/Bundle/ChillDocStore/Resources/views/DocumentCategory/_delete_form.html.twig diff --git a/Resources/views/DocumentCategory/_form.html.twig b/src/Bundle/ChillDocStore/Resources/views/DocumentCategory/_form.html.twig similarity index 100% rename from Resources/views/DocumentCategory/_form.html.twig rename to src/Bundle/ChillDocStore/Resources/views/DocumentCategory/_form.html.twig diff --git a/Resources/views/DocumentCategory/edit.html.twig b/src/Bundle/ChillDocStore/Resources/views/DocumentCategory/edit.html.twig similarity index 100% rename from Resources/views/DocumentCategory/edit.html.twig rename to src/Bundle/ChillDocStore/Resources/views/DocumentCategory/edit.html.twig diff --git a/Resources/views/DocumentCategory/index.html.twig b/src/Bundle/ChillDocStore/Resources/views/DocumentCategory/index.html.twig similarity index 100% rename from Resources/views/DocumentCategory/index.html.twig rename to src/Bundle/ChillDocStore/Resources/views/DocumentCategory/index.html.twig diff --git a/Resources/views/DocumentCategory/new.html.twig b/src/Bundle/ChillDocStore/Resources/views/DocumentCategory/new.html.twig similarity index 100% rename from Resources/views/DocumentCategory/new.html.twig rename to src/Bundle/ChillDocStore/Resources/views/DocumentCategory/new.html.twig diff --git a/Resources/views/DocumentCategory/show.html.twig b/src/Bundle/ChillDocStore/Resources/views/DocumentCategory/show.html.twig similarity index 100% rename from Resources/views/DocumentCategory/show.html.twig rename to src/Bundle/ChillDocStore/Resources/views/DocumentCategory/show.html.twig diff --git a/Resources/views/Form/fields.html.twig b/src/Bundle/ChillDocStore/Resources/views/Form/fields.html.twig similarity index 100% rename from Resources/views/Form/fields.html.twig rename to src/Bundle/ChillDocStore/Resources/views/Form/fields.html.twig diff --git a/Resources/views/Macro/macro.html.twig b/src/Bundle/ChillDocStore/Resources/views/Macro/macro.html.twig similarity index 100% rename from Resources/views/Macro/macro.html.twig rename to src/Bundle/ChillDocStore/Resources/views/Macro/macro.html.twig diff --git a/Resources/views/PersonDocument/_delete_form.html.twig b/src/Bundle/ChillDocStore/Resources/views/PersonDocument/_delete_form.html.twig similarity index 100% rename from Resources/views/PersonDocument/_delete_form.html.twig rename to src/Bundle/ChillDocStore/Resources/views/PersonDocument/_delete_form.html.twig diff --git a/Resources/views/PersonDocument/edit.html.twig b/src/Bundle/ChillDocStore/Resources/views/PersonDocument/edit.html.twig similarity index 100% rename from Resources/views/PersonDocument/edit.html.twig rename to src/Bundle/ChillDocStore/Resources/views/PersonDocument/edit.html.twig diff --git a/Resources/views/PersonDocument/index.html.twig b/src/Bundle/ChillDocStore/Resources/views/PersonDocument/index.html.twig similarity index 100% rename from Resources/views/PersonDocument/index.html.twig rename to src/Bundle/ChillDocStore/Resources/views/PersonDocument/index.html.twig diff --git a/Resources/views/PersonDocument/new.html.twig b/src/Bundle/ChillDocStore/Resources/views/PersonDocument/new.html.twig similarity index 100% rename from Resources/views/PersonDocument/new.html.twig rename to src/Bundle/ChillDocStore/Resources/views/PersonDocument/new.html.twig diff --git a/Resources/views/PersonDocument/show.html.twig b/src/Bundle/ChillDocStore/Resources/views/PersonDocument/show.html.twig similarity index 100% rename from Resources/views/PersonDocument/show.html.twig rename to src/Bundle/ChillDocStore/Resources/views/PersonDocument/show.html.twig diff --git a/Security/Authorization/PersonDocumentVoter.php b/src/Bundle/ChillDocStore/Security/Authorization/PersonDocumentVoter.php similarity index 100% rename from Security/Authorization/PersonDocumentVoter.php rename to src/Bundle/ChillDocStore/Security/Authorization/PersonDocumentVoter.php diff --git a/chill.webpack.config.js b/src/Bundle/ChillDocStore/chill.webpack.config.js similarity index 100% rename from chill.webpack.config.js rename to src/Bundle/ChillDocStore/chill.webpack.config.js diff --git a/composer.json b/src/Bundle/ChillDocStore/composer.json similarity index 100% rename from composer.json rename to src/Bundle/ChillDocStore/composer.json diff --git a/config/routes.yaml b/src/Bundle/ChillDocStore/config/routes.yaml similarity index 100% rename from config/routes.yaml rename to src/Bundle/ChillDocStore/config/routes.yaml diff --git a/config/services.yaml b/src/Bundle/ChillDocStore/config/services.yaml similarity index 100% rename from config/services.yaml rename to src/Bundle/ChillDocStore/config/services.yaml diff --git a/config/services/controller.yaml b/src/Bundle/ChillDocStore/config/services/controller.yaml similarity index 100% rename from config/services/controller.yaml rename to src/Bundle/ChillDocStore/config/services/controller.yaml diff --git a/config/services/fixtures.yaml b/src/Bundle/ChillDocStore/config/services/fixtures.yaml similarity index 100% rename from config/services/fixtures.yaml rename to src/Bundle/ChillDocStore/config/services/fixtures.yaml diff --git a/config/services/form.yaml b/src/Bundle/ChillDocStore/config/services/form.yaml similarity index 100% rename from config/services/form.yaml rename to src/Bundle/ChillDocStore/config/services/form.yaml diff --git a/config/services/media.yaml b/src/Bundle/ChillDocStore/config/services/media.yaml similarity index 100% rename from config/services/media.yaml rename to src/Bundle/ChillDocStore/config/services/media.yaml diff --git a/config/services/menu.yaml b/src/Bundle/ChillDocStore/config/services/menu.yaml similarity index 100% rename from config/services/menu.yaml rename to src/Bundle/ChillDocStore/config/services/menu.yaml diff --git a/migrations/Version20180605102533.php b/src/Bundle/ChillDocStore/migrations/Version20180605102533.php similarity index 100% rename from migrations/Version20180605102533.php rename to src/Bundle/ChillDocStore/migrations/Version20180605102533.php diff --git a/migrations/Version20180606133338.php b/src/Bundle/ChillDocStore/migrations/Version20180606133338.php similarity index 100% rename from migrations/Version20180606133338.php rename to src/Bundle/ChillDocStore/migrations/Version20180606133338.php diff --git a/translations/messages.fr.yml b/src/Bundle/ChillDocStore/translations/messages.fr.yml similarity index 100% rename from translations/messages.fr.yml rename to src/Bundle/ChillDocStore/translations/messages.fr.yml diff --git a/translations/validators.fr.yml b/src/Bundle/ChillDocStore/translations/validators.fr.yml similarity index 100% rename from translations/validators.fr.yml rename to src/Bundle/ChillDocStore/translations/validators.fr.yml