diff --git a/legacy/62b16d26-aee1-4dc3-8dd7-83c57063e8e1project.xml b/legacy/62b16d26-aee1-4dc3-8dd7-83c57063e8e1project.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bf60377233412d6d502479ed89fb1f0d3c584e0 --- /dev/null +++ b/legacy/62b16d26-aee1-4dc3-8dd7-83c57063e8e1project.xml @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<!DOCTYPE rekall> +<project> + <video url="https://youtu.be/Ssm_mm8zyS0"/> + <document key="marker-1f10323d5f4a1c119e777e59c2f00dcc650e750d"> + <meta ctg="Rekall->Author" cnt=""/> + <meta ctg="Rekall->Date/Time" cnt="2015:08:31 18:06:16"/> + <meta ctg="Rekall->Import Date" cnt="2015:08:31 18:06:16"/> + <meta ctg="Rekall User Infos->User Name" cnt=""/> + <meta ctg="Rekall->Location Name" cnt="48.867359621322265, 2.3618561655447228"/> + <meta ctg="Rekall->Location GPS" cnt="48.867359621322265, 2.3618561655447228"/> + <meta ctg="Rekall User Infos->User IP" cnt="127.0.0.1"/> + <meta ctg="Rekall->Comments" cnt=""/> + <meta ctg="Rekall->Keywords" cnt=""/> + <meta ctg="Rekall->Group" cnt=""/> + <meta ctg="Rekall->Visibility" cnt=""/> + <meta ctg="Rekall->Type" cnt="rekall/marker"/> + <meta ctg="Rekall->Flag" cnt="Marker"/> + <meta ctg="Rekall->Name" cnt="New note"/> + </document> + <tag key="marker-1f10323d5f4a1c119e777e59c2f00dcc650e750d" timeStart="0" timeEnd="10" version="0"/> +</project> diff --git a/src/Controller/CapsuleController.php b/src/Controller/CapsuleController.php index 6cc1a15a128f578d3a569eba2781d2f2219b1fc8..8265e81e2e21f7a7676e65df5bb7d90a17cc9e1a 100644 --- a/src/Controller/CapsuleController.php +++ b/src/Controller/CapsuleController.php @@ -5,12 +5,15 @@ namespace App\Controller; use App\Entity\Capsule; use App\Entity\User; use App\Form\DeleteCapsuleFormType; +use App\Form\DuplicateCapsuleFormType; use App\Helper\StringHelper; use App\Repository\CapsuleRepository; use App\Builder\CapsuleBuilder; use App\Form\CreateCapsuleFormType; use Knp\Component\Pager\PaginatorInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -62,25 +65,9 @@ class CapsuleController extends AbstractController } if ($form->isSubmitted() && $form->isValid()) { - $new_date_time = new \DateTime(); - $capsule_name = $form->get('name')->getData(); $video_url = htmlspecialchars($form->get('video_url')->getData()); - $password = StringHelper::generateRandomHashedString(); - $preview_link = Uuid::v4(); - - $entityManager = $this->getDoctrine()->getManager(); - $capsule_builder = new CapsuleBuilder(); - $capsule = $capsule_builder - ->withName($capsule_name) - ->withCreationAuthor($current_user) - ->withCreationDate($new_date_time) - ->withLinkPath($preview_link) - ->withUpdateDate($new_date_time) - ->withPassword($password) - ->createCapsule(); - - $entityManager->persist($capsule); - $entityManager->flush(); + + $capsule = $this->createCapsuleInDB($form, $current_user); return $this->forward('App\Controller\ProjectController::create', [ 'capsule' => $capsule, @@ -189,4 +176,83 @@ class CapsuleController extends AbstractController 'capsule_name' => $capsule_name ]); } + + /** + * @Route("/capsule/duplicate/{id}", name="duplicate_capsule") + */ + public function duplicate( + int $id, + Request $request, + Filesystem $file_system, + TranslatorInterface $translator + ): Response { + $form = $this->createForm(DuplicateCapsuleFormType::class); + $form->handleRequest($request); + $current_user = $this->getUser(); + + if (! $current_user instanceof User) { + return $this->redirectToRoute('app_logout'); + } + + $entityManager = $this->getDoctrine()->getManager(); + $parent_capsule = $entityManager->getRepository(Capsule::class)->find($id); + + if (! $parent_capsule instanceof Capsule) { + throw new \Exception('The retrieved capsule is not an instance of Caspule.'); + } + + $parent_directory_name = $parent_capsule->getLinkPath(); + $parent_directory_exists = $file_system->exists('../legacy/' . $parent_directory_name); + if (! $parent_directory_exists) { + $this->addFlash( + 'project_does_not_exist', + $translator->trans( + 'project.not_exist', + [ + 'capsule_name' => $parent_capsule->getName() + ] + ) + ); + + return $this->redirectToRoute('capsule_list'); + } + + if ($form->isSubmitted() && $form->isValid()) { + $capsule = $this->createCapsuleInDB($form, $current_user); + + return $this->forward('App\Controller\ProjectController::duplicate', [ + 'capsule' => $capsule, + 'parent_directory' => $parent_directory_name + ]); + } + + return $this->render('capsule/duplicate.html.twig', [ + 'duplicateCapsuleForm' => $form->createView(), + 'capsule_name' => $parent_capsule->getName() + ]); + } + + private function createCapsuleInDB(FormInterface $form, User $current_user): Capsule + { + $new_date_time = new \DateTime(); + $capsule_name = $form->get('name')->getData(); + $password = StringHelper::generateRandomHashedString(); + $preview_link = Uuid::v4(); + + $entityManager = $this->getDoctrine()->getManager(); + $capsule_builder = new CapsuleBuilder(); + $capsule = $capsule_builder + ->withName($capsule_name) + ->withCreationAuthor($current_user) + ->withCreationDate($new_date_time) + ->withLinkPath($preview_link) + ->withUpdateDate($new_date_time) + ->withPassword($password) + ->createCapsule(); + + $entityManager->persist($capsule); + $entityManager->flush(); + + return $capsule; + } } diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index e386f3936f420add02bc1d06041eeaaf0f27a6d3..e335abef682ceab323e277b15f7016f154e58e23 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -7,6 +7,7 @@ use App\Exception\ZipArchiveNotOpeningException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Config\Util\Exception\XmlParsingException; use Symfony\Component\Filesystem\Exception\FileNotFoundException; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -62,6 +63,52 @@ class ProjectController extends AbstractController return $this->redirectToRoute('capsule_list'); } + /** + * @Route("/project/duplicate", name="duplicate_project", methods={"POST"}) + * @throws ZipArchiveNotOpeningException + */ + public function duplicate( + TranslatorInterface $translator, + Capsule $capsule, + string $parent_directory, + Filesystem $file_system + ): Response { + chdir('../legacy/'); + + $capsule_name = $capsule->getName(); + $capsule_directory = $capsule->getLinkPath(); + + if (file_exists($capsule_directory)) { + $this->addFlash( + 'project_already_exists', + $translator->trans( + 'project.already_exists', + [ + 'capsule_name' => $capsule_name + ] + ) + ); + + return $this->redirectToRoute('capsule_list'); + } + + $this->extractZipArchiveInNewCapsuleDirectory($capsule_directory); + $this->replaceTheWholeFileDirectoryWithParentOne($file_system, $parent_directory, $capsule_directory); + $this->createOrUpdatePasswordFile($capsule_directory, $capsule->getPassword()); + + $this->addFlash( + 'capsule_duplicated_success', + $translator->trans( + 'capsule.duplicate.success', + [ + 'capsule_name' => $capsule_name + ] + ) + ); + + return $this->redirectToRoute('capsule_list'); + } + /** * @throws ZipArchiveNotOpeningException The archive file doesn't exist. */ @@ -101,4 +148,18 @@ class ProjectController extends AbstractController $project_password_file = $capsule_directory . "/file/projectPassword.txt"; file_put_contents($project_password_file, $password); } + + private function replaceTheWholeFileDirectoryWithParentOne( + FileSystem $file_system, + string $parent_directory, + string $child_directory + ): void { + $file_directory_path = '/file/'; + $file_system->mirror( + $parent_directory . $file_directory_path, + $child_directory . $file_directory_path, + null, + ['override' => true] + ); + } } diff --git a/src/Form/DuplicateCapsuleFormType.php b/src/Form/DuplicateCapsuleFormType.php new file mode 100644 index 0000000000000000000000000000000000000000..997db2aad40ba0868d92fa45180d535f87109dfc --- /dev/null +++ b/src/Form/DuplicateCapsuleFormType.php @@ -0,0 +1,32 @@ +<?php + +namespace App\Form; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class DuplicateCapsuleFormType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add( + 'name', + TextType::class, + ['label' => 'capsule.duplicate.new_name'] + ) + ->add( + 'validate', + SubmitType::class, + ['label' => 'general.validate'] + ); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([]); + } +} diff --git a/templates/capsule/duplicate.html.twig b/templates/capsule/duplicate.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..48222f3a010a821510dabac90970f8493776688a --- /dev/null +++ b/templates/capsule/duplicate.html.twig @@ -0,0 +1,30 @@ +{% extends 'layout.html.twig' %} + +{% block title %} + {{ 'capsule.duplicate.title'|trans }} + - + {{ parent() }} +{% endblock %} + +{% block body %} + + <div> + <div class="row w-100 gx-0"> + <div class="row-title-box"> + <h3 class="row-title"> + {{ 'capsule.duplicate.title_name'|trans({'%capsule_name%': capsule_name}) }} + </h3> + </div> + </div> + +{# <div class="d-flex flex-column justify-content-center align-items-center">#} + + {{ form_start(duplicateCapsuleForm, {'attr': {novalidate: 'novalidate', 'class': 'd-flex flex-column justify-content-center'}}) }} + {{ form_row(duplicateCapsuleForm.name, {'row_attr': {'class' : 'm-auto mb-4 col-6'}}) }} + {{ form_row(duplicateCapsuleForm.validate, {'row_attr': {'class' : 'm-auto mb-5 col-2'}}) }} + {{ form_end(duplicateCapsuleForm) }} +{# </div>#} + + </div> + +{% endblock %} \ No newline at end of file diff --git a/templates/capsule/index.html.twig b/templates/capsule/index.html.twig index e99a2dacc7dc0aa74482fd24276964f5187e3387..5109ea8f9311d2372a628eae7bc43153e691cb1e 100644 --- a/templates/capsule/index.html.twig +++ b/templates/capsule/index.html.twig @@ -40,6 +40,18 @@ {{ flashSuccess }} </div> {% endfor %} + + {% for flashWarning in app.flashes('project_does_not_exist') %} + <div class="text-center alert alert-warning col-5 mx-auto my-5" role="alert"> + {{ flashWarning }} + </div> + {% endfor %} + + {% for flashSuccess in app.flashes('capsule_duplicated_success') %} + <div class="text-center alert alert-success col-5 mx-auto my-5" role="alert"> + {{ flashSuccess }} + </div> + {% endfor %} </div> <div class="capsules-list d-flex flex-column m-6"> @@ -75,7 +87,7 @@ </a> </div> <div class="list-item text-nowrap"> - <a href="" class="links text-decoration-none"> + <a href="/capsule/duplicate/{{ capsule.getId() }}" class="links text-decoration-none"> <i class="far fa-clone m-2"></i> {{ 'capsule.duplicate.link'|trans }} </a> diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index 54613c726b86293981af8c8fd55550921ed8ac97..5b937d184021a13cbe2e0061874bf60bdc184073 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -7,6 +7,7 @@ general: cancel_button: Cancel link_expire: This link will expire in %expirationDuration% greeting: Cheers! + validate: Validate login: account_disabled_feedback: Your user account is disabled. Please click on the link your receive by email to validate your registration. @@ -70,6 +71,10 @@ capsule: link: Edit capsule duplicate: link: Duplicate capsule + title: Duplicate capsule + title_name: Duplicate capsule %capsule_name% + new_name: Enter the name of the new capsule + success: The capsule has been successfully duplicated into capsule_name. You can see it at the end of your list. delete: link: Delete capsule button: Delete @@ -79,6 +84,7 @@ capsule: project: already_exists: Project capsule_name already exists so the capsule could not be created + not_exist: The project to duplicate does not exist preview: loading: Project loading diff --git a/translations/messages.fr.yaml b/translations/messages.fr.yaml index 527684ea05abe05593a5f057d58f6a5cd536513a..60343d6031bd5fd141bbeedce307060fa8749190 100644 --- a/translations/messages.fr.yaml +++ b/translations/messages.fr.yaml @@ -7,6 +7,7 @@ general: greeting: Salutation ! go_back_to_home_page: Page d'accueil cancel_button: Annuler + validate: Valider login: account_disabled_feedback: Le compte utilisateur a été désactivé. Veuillez cliquer sur le lien pour recevoir un courriel de validation @@ -67,6 +68,10 @@ capsule: link: Modifier la capsule duplicate: link: Dupliquer la capsule + title: Dupliquer la capsule + title_name: Dupliquer la capsule %capsule_name% + new_name: Saisissez le nom de la nouvelle capsule + success: La capsule a bien été dupliquée en capsule_name. Vous la retrouverez à la suite des capsules. delete: link: Supprimer la capsule not_found: Le projet n'existe pas @@ -77,6 +82,7 @@ capsule: project: already_exists: Le projet capsule_name existe déjà. La capsule n'a pas pu être créée + not_exist: Le projet a dupliquer n'existe pas preview: loading: Projet en cours de chargement