diff --git a/assets/styles/app.scss b/assets/styles/app.scss index a35eb1cd9ccfe7afe7b691c2d6d0c2c53a2c4191..f1349795614fa1f72aa9dded9d17d5c9946574c1 100644 --- a/assets/styles/app.scss +++ b/assets/styles/app.scss @@ -151,4 +151,8 @@ button[type=submit]{ text-decoration: none; text-transform: uppercase; font-size: 18px; +} + +.remove-link { + font-size: 0.9rem; } \ No newline at end of file diff --git a/src/Controller/CapsuleEditorController.php b/src/Controller/CapsuleEditorController.php index 39af5fe0d9eed11481ea796bcce07d88f0320f19..ea8d32aaa65079d827bf91794f4e36e0ac9d2764 100644 --- a/src/Controller/CapsuleEditorController.php +++ b/src/Controller/CapsuleEditorController.php @@ -3,15 +3,14 @@ namespace App\Controller; use App\Entity\Capsule; -use App\Entity\CapsuleEditor; -use App\Entity\CapsulePendingEditor; +use App\Entity\PendingEditorInvitation; use App\Entity\User; use App\Form\CapsuleEditorsFormType; -use App\Repository\CapsulePendingEditorRepository; +use App\Form\RemoveEditorFormType; use App\Repository\CapsuleRepository; +use App\Repository\PendingEditorInvitationRepository; use App\Repository\UserRepository; use Doctrine\ORM\EntityManagerInterface; -use http\Env; use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; @@ -26,22 +25,28 @@ class CapsuleEditorController extends AbstractController { private TranslatorInterface $translator; private MailerInterface $mailer; - private CapsulePendingEditorRepository $capsule_pending_editor_repository; + private PendingEditorInvitationRepository $capsule_pending_editor_invitation_repository; private EntityManagerInterface $entity_manager; private UrlGeneratorInterface $urlGenerator; + private CapsuleRepository $capsule_repository; + private UserRepository $user_repository; public function __construct( MailerInterface $mailer, TranslatorInterface $translator, - CapsulePendingEditorRepository $capsule_pending_editor_repository, + PendingEditorInvitationRepository $capsule_pending_editor_invitation_repository, EntityManagerInterface $entity_manager, - UrlGeneratorInterface $urlGenerator + UrlGeneratorInterface $urlGenerator, + CapsuleRepository $capsule_repository, + UserRepository $user_repository ) { $this->mailer = $mailer; $this->translator = $translator; - $this->capsule_pending_editor_repository = $capsule_pending_editor_repository; + $this->capsule_pending_editor_invitation_repository = $capsule_pending_editor_invitation_repository; $this->entity_manager = $entity_manager; $this->urlGenerator = $urlGenerator; + $this->capsule_repository = $capsule_repository; + $this->user_repository = $user_repository; } /** @@ -49,16 +54,14 @@ class CapsuleEditorController extends AbstractController */ public function editCapsuleEditors( Request $request, - int $capsule_id, - CapsuleRepository $capsule_repository, - UserRepository $user_repository + int $capsule_id ): Response { $current_user = $this->getUser(); if (! $current_user instanceof User) { return $this->redirectToRoute('app_logout'); } - $capsule = $capsule_repository->find($capsule_id); + $capsule = $this->capsule_repository->find($capsule_id); if (! $capsule) { throw $this->createNotFoundException( 'No capsule found for id ' . $capsule_id @@ -67,7 +70,6 @@ class CapsuleEditorController extends AbstractController $current_capsule_editors_users = $capsule->getEditors()->toArray(); if (! $capsule->getEditors()->contains($current_user)) { -// in_array($current_user, $current_capsule_editors_users)) { $this->addFlash( 'warning', $this->translator->trans( @@ -86,7 +88,7 @@ class CapsuleEditorController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { $editor_email = $form->get('email')->getData(); - $user_associated_with_email_address = $user_repository + $user_associated_with_email_address = $this->user_repository ->findOneBy(['email' => $editor_email]); if (! $user_associated_with_email_address instanceof User) { @@ -106,19 +108,21 @@ class CapsuleEditorController extends AbstractController ]); } - $pending_editors = $this->capsule_pending_editor_repository->findBy(['capsule_id' => $capsule_id]); + $pending_editors = $this->capsule_pending_editor_invitation_repository->findBy(['capsule_id' => $capsule_id]); return $this->render('capsule/editors/list_editors.html.twig', [ 'userPermissionsCapsuleForm' => $form->createView(), - 'capsule_name' => $capsule->getName(), + 'capsule' => $capsule, 'editors' => $current_capsule_editors_users, - 'pending_editors' => $pending_editors + 'pending_editors' => $pending_editors, + 'current_user' => $current_user ]); } private function addPendingEditor(string $editor_email, Capsule $capsule, User $current_user): void { - $pending_editors_emails = $this->capsule_pending_editor_repository->getPendingEditorsEmails($capsule->getId()); + $pending_editors_emails = $this->capsule_pending_editor_invitation_repository + ->getPendingEditorsEmails($capsule->getId()); if (in_array($editor_email, $pending_editors_emails)) { $this->addFlash( @@ -133,10 +137,10 @@ class CapsuleEditorController extends AbstractController return; } - $pending_editor = new CapsulePendingEditor(); - $pending_editor->setCapsuleId($capsule->getId()); - $pending_editor->setEmail($editor_email); - $this->entity_manager->persist($pending_editor); + $pending_editor_invitation = new PendingEditorInvitation(); + $pending_editor_invitation->setCapsuleId($capsule->getId()); + $pending_editor_invitation->setEmail($editor_email); + $this->entity_manager->persist($pending_editor_invitation); $this->entity_manager->flush(); $email = (new TemplatedEmail()) @@ -216,4 +220,136 @@ class CapsuleEditorController extends AbstractController ) ); } + + /** + * @Route("/capsule/{capsule_id}/editors/{editor_id}/remove", name="remove_editor") + */ + public function removeEditor( + int $capsule_id, + int $editor_id, + Request $request + ): Response { + $form = $this->createForm(RemoveEditorFormType::class); + $form->handleRequest($request); + + $capsule = $this->capsule_repository->findOneBy(['id' => $capsule_id]); + if (! $capsule instanceof Capsule) { + throw new \Exception('The retrieved capsule is not an instance of Capsule.'); + } + + $editor = $this->user_repository->findOneBy(['id' => $editor_id]); + if (! $editor instanceof User) { + throw new \Exception('The retrieved user is not an instance of User.'); + } + + $current_user = $this->getUser(); + if (! $current_user instanceof User) { + return $this->redirectToRoute('app_logout'); + } + + if ($editor === $current_user) { + $this->addFlash( + 'warning', + $this->translator->trans( + 'editors.remove.editor.error', + [ + 'editor_email' => $editor->getEmail(), + 'capsule_name' => $capsule->getName() + ] + ) + ); + + return $this->redirectToRoute('edit_capsule_editors', [ + 'capsule_id' => $capsule->getId() + ]); + } + + if ($form->isSubmitted() && $form->isValid()) { + $capsule->removeEditor($editor); + $this->entity_manager->flush(); + + $this->addFlash( + 'success', + $this->translator->trans( + 'editors.remove.editor.success', + [ + 'editor_email' => $editor->getEmail(), + 'capsule_name' => $capsule->getName() + ] + ) + ); + + return $this->redirectToRoute('edit_capsule_editors', [ + 'capsule_id' => $capsule->getId() + ]); + } + + return $this->render('capsule/editors/remove_editor.html.twig', [ + 'removeEditorForm' => $form->createView(), + 'editor_email' => $editor->getEmail(), + 'capsule_id' => $capsule_id + ]); + } + + /** + * @Route("/capsule/{capsule_id}/pending_editor/{pending_editor_invitation_id}/remove", name="remove_pending_editor") + */ + public function removePendingEditor( + int $pending_editor_invitation_id, + int $capsule_id, + request $request + ): Response { + $form = $this->createForm(RemoveEditorFormType::class); + $form->handleRequest($request); + + $capsule = $this->capsule_repository->findOneBy(['id' => $capsule_id]); + if (! $capsule instanceof Capsule) { + throw new \Exception('The retrieved capsule is not an instance of Capsule.'); + } + + $pending_editor_invitation = $this->capsule_pending_editor_invitation_repository + ->findOneBy(['id' => $pending_editor_invitation_id]); + + if (! $pending_editor_invitation instanceof PendingEditorInvitation) { + $this->addFlash( + 'warning', + $this->translator->trans( + 'editors.remove.pending_editor.error', + [ + 'capsule_name' => $capsule->getName() + ] + ) + ); + + return $this->redirectToRoute('edit_capsule_editors', [ + 'capsule_id' => $capsule_id + ]); + } + + if ($form->isSubmitted() && $form->isValid()) { + $this->entity_manager->remove($pending_editor_invitation); + $this->entity_manager->flush(); + + $this->addFlash( + 'success', + $this->translator->trans( + 'editors.remove.pending_editor.success', + [ + 'pending_editor_email' => $pending_editor_invitation->getEmail(), + 'capsule_name' => $capsule->getName() + ] + ) + ); + + return $this->redirectToRoute('edit_capsule_editors', [ + 'capsule_id' => $capsule_id + ]); + } + + return $this->render('capsule/editors/remove_pending_editor.html.twig', [ + 'removeEditorForm' => $form->createView(), + 'editor_email' => $pending_editor_invitation->getEmail(), + 'capsule_id' => $capsule_id + ]); + } } diff --git a/src/Entity/CapsulePendingEditor.php b/src/Entity/CapsulePendingEditor.php deleted file mode 100644 index 6dd010a96f837a03da48c7a80119c096cfd35d9e..0000000000000000000000000000000000000000 --- a/src/Entity/CapsulePendingEditor.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php - -namespace App\Entity; - -use App\Repository\CapsulePendingEditorRepository; -use Doctrine\ORM\Mapping as ORM; - -/** - * @ORM\Table(name="invitation_editeur_capsule") - * @ORM\Entity(repositoryClass=CapsulePendingEditorRepository::class) - */ -class CapsulePendingEditor -{ - /** - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - */ - private int $id; - - /** - * @ORM\Column(type="integer") - * @ORM\Column(name="capsule_id", type="integer", nullable=false) - * @ORM\ManyToOne(targetEntity="App\Entity\Capsule", inversedBy="id") - * @ORM\JoinColumn(name="capsule_id", referencedColumnName="id") - */ - private int $capsule_id; - - /** - * @ORM\Column(name="email", type="string", length=255, nullable=false) - */ - private string $email; - - public function getId(): int - { - return $this->id; - } - - public function getCapsuleId(): int - { - return $this->capsule_id; - } - - public function setCapsuleId(int $capsule_id): self - { - $this->capsule_id = $capsule_id; - - return $this; - } - - public function getEmail(): string - { - return $this->email; - } - - public function setEmail(string $email): self - { - $this->email = $email; - - return $this; - } -} diff --git a/src/Form/RemoveEditorFormType.php b/src/Form/RemoveEditorFormType.php new file mode 100644 index 0000000000000000000000000000000000000000..e82285fe4680115cfee1e70d9d028f15d5ad2e1b --- /dev/null +++ b/src/Form/RemoveEditorFormType.php @@ -0,0 +1,34 @@ +<?php + +namespace App\Form; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ButtonType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class RemoveEditorFormType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add( + 'cancel', + ButtonType::class, + ['label' => 'general.cancel_button', + 'attr' => ['class' => 'button-cancel'] + ] + ) + ->add( + 'remove', + SubmitType::class, + ['label' => 'editors.remove.button'] + ); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([]); + } +} diff --git a/src/Repository/CapsulePendingEditorRepository.php b/src/Repository/CapsulePendingEditorRepository.php deleted file mode 100644 index 1504d2e8f9065246a327cfc2069f9abf50a34080..0000000000000000000000000000000000000000 --- a/src/Repository/CapsulePendingEditorRepository.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php - -namespace App\Repository; - -use App\Entity\CapsulePendingEditor; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -use Doctrine\Persistence\ManagerRegistry; - -/** - * @method CapsulePendingEditor|null find($id, $lockMode = null, $lockVersion = null) - * @method CapsulePendingEditor|null findOneBy(array $criteria, array $orderBy = null) - * @method CapsulePendingEditor[] findAll() - * @method CapsulePendingEditor[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -class CapsulePendingEditorRepository extends ServiceEntityRepository -{ - public function __construct(ManagerRegistry $registry) - { - parent::__construct($registry, CapsulePendingEditor::class); - } - - /** - * @return array<string> - */ - public function getPendingEditorsEmails(int $capsule_id): array - { - $editors_emails_result = $this->createQueryBuilder('c') - ->select('c.email') - ->andWhere('c.capsule_id = :val') - ->setParameter('val', $capsule_id) - ->getQuery() - ->getResult() - ; - - $editors_emails = []; - - foreach ($editors_emails_result as $editor_email_result) { - $editors_emails[] = $editor_email_result['email']; - } - - return $editors_emails; - } -} diff --git a/src/Repository/PendingEditorInvitationRepository.php b/src/Repository/PendingEditorInvitationRepository.php index e891144dd03e5b31229c3707ea86c82f6bca48a8..fcfe7281c1580be5c2f8760bf65a398bbe39383b 100644 --- a/src/Repository/PendingEditorInvitationRepository.php +++ b/src/Repository/PendingEditorInvitationRepository.php @@ -19,6 +19,28 @@ class PendingEditorInvitationRepository extends ServiceEntityRepository parent::__construct($registry, PendingEditorInvitation::class); } + /** + * @return array<string> + */ + public function getPendingEditorsEmails(int $capsule_id): array + { + $editors_emails_result = $this->createQueryBuilder('c') + ->select('c.email') + ->andWhere('c.capsule_id = :val') + ->setParameter('val', $capsule_id) + ->getQuery() + ->getResult() + ; + + $editors_emails = []; + + foreach ($editors_emails_result as $editor_email_result) { + $editors_emails[] = $editor_email_result['email']; + } + + return $editors_emails; + } + /** * @return array<PendingEditorInvitation> */ diff --git a/templates/capsule/editors/list_editors.html.twig b/templates/capsule/editors/list_editors.html.twig index 31e7e6627efd798d1b19c863bac93ea06d7584cd..de7ba00e0000f6e181ec74c4773fbd4eea8f12b3 100644 --- a/templates/capsule/editors/list_editors.html.twig +++ b/templates/capsule/editors/list_editors.html.twig @@ -12,7 +12,7 @@ <div class="row w-100 gx-0"> <div class="row-title-box"> <h3 class="row-title"> - {{ 'editors.title_name'|trans({'%capsule_name%': capsule_name}) }} + {{ 'editors.title_name'|trans({'%capsule_name%': capsule.getName()}) }} </h3> </div> </div> @@ -46,6 +46,12 @@ {% for editor in editors %} <li class="text-capitalize text-secondary list-unstyled p-1"> {{ editor.getFirstName() }} {{ editor.getLastName() }} + {% if editor is not same as current_user %} + - + <a href="/capsule/{{ capsule.getId() }}/editors/{{ editor.getId() }}/remove" class="remove-link"> + {{ 'editors.remove.editor.link'|trans }} + </a> + {% endif %} </li> {% endfor %} </ul> @@ -56,6 +62,9 @@ {% for pending_editor in pending_editors %} <li class="text-secondary list-unstyled p-1"> {{ pending_editor.getEmail() }} + <a href="/capsule/{{ capsule.getId() }}/pending_editor/{{ pending_editor.getId() }}/remove" class="remove-link"> + {{ 'editors.remove.pending_editor.link'|trans }} + </a> </li> {% endfor %} </ul> diff --git a/templates/capsule/editors/remove_editor.html.twig b/templates/capsule/editors/remove_editor.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..ddfd703f8eebfc2dde4012ad8d5bffafd9b9b4e5 --- /dev/null +++ b/templates/capsule/editors/remove_editor.html.twig @@ -0,0 +1,34 @@ +{% extends 'layout.html.twig' %} + +{% block title %} + {{ 'editors.remove.editor.title'|trans }} +{% endblock %} + +{% block body %} + + <div> + <div class="row w-100 gx-0"> + <div class="row-title-box"> + <h3 class="row-title"> + {{ 'editors.remove.editor.title'|trans }} + </h3> + </div> + </div> + + <div class="d-flex flex-column justify-content-center align-items-center"> + + <p class="text-secondary fs-5 mb-5"> + {{ 'editors.remove.editor.text'|trans({'%editor_email%': editor_email}) }} + </p> + + {{ form_start(removeEditorForm, {'attr': {novalidate: 'novalidate', 'class': 'd-flex flex-row justify-content-center'}}) }} + {{ form_row(removeEditorForm.remove, {'row_attr': {'class' : 'm-auto mb-2 me-3'}}) }} + <a href="/capsule/{{ capsule_id }}/editors"> + {{ form_row(removeEditorForm.cancel, {'row_attr': {'class' : 'm-auto mb-2 bg-secondary rounded ms-3'}}) }} + </a> + {{ form_end(removeEditorForm) }} + </div> + + </div> + +{% endblock %} \ No newline at end of file diff --git a/templates/capsule/editors/remove_pending_editor.html.twig b/templates/capsule/editors/remove_pending_editor.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..bd96a9193560995c33445dad36946b2de7114512 --- /dev/null +++ b/templates/capsule/editors/remove_pending_editor.html.twig @@ -0,0 +1,34 @@ +{% extends 'layout.html.twig' %} + +{% block title %} + {{ 'editors.remove.pending_editor.title'|trans }} +{% endblock %} + +{% block body %} + + <div> + <div class="row w-100 gx-0"> + <div class="row-title-box"> + <h3 class="row-title"> + {{ 'editors.remove.pending_editor.title'|trans }} + </h3> + </div> + </div> + + <div class="d-flex flex-column justify-content-center align-items-center"> + + <p class="text-secondary fs-5 mb-5"> + {{ 'editors.remove.pending_editor.text'|trans({'%editor_email%': editor_email}) }} + </p> + + {{ form_start(removeEditorForm, {'attr': {novalidate: 'novalidate', 'class': 'd-flex flex-row justify-content-center'}}) }} + {{ form_row(removeEditorForm.remove, {'row_attr': {'class' : 'm-auto mb-2 me-3'}}) }} + <a href="/capsule/{{ capsule_id }}/editors"> + {{ form_row(removeEditorForm.cancel, {'row_attr': {'class' : 'm-auto mb-2 bg-secondary rounded ms-3'}}) }} + </a> + {{ form_end(removeEditorForm) }} + </div> + + </div> + +{% endblock %} \ No newline at end of file diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index 7e70101b17d492bd2f9a35ec93529ef8a64f811c..5c341f9ebaeda8d1dd704b2a6575a0d88952e46d 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -136,3 +136,18 @@ editors: text: You have been add by %user_name% as editor of the capsule "%capsule_name%". You can now access and edit it. You will find the capsule in your capsule list. link: Go to capsule edition page + remove: + button: Remove + pending_editor: + title: Remove pending editor + text: Do you really want to delete pending editor %editor_email%? + link: Remove pending editor + error: The email address has already been removed from pending editors of the capsule capsule_name + success: The email address pending_editor_email has been successfully removed from pending editors of the capsule capsule_name + editor: + title: Remove editor + text: Do you really want to delete editor %editor_email%? + link: Remove editor + success: User editor_email is no longer and editor of the capsule capsule_name + error: You can't remove yourself as editor of your own capsule. + If you want to remove the capsule from your list, go to the capsule list page and click on "delete capsule" \ No newline at end of file diff --git a/translations/messages.fr.yaml b/translations/messages.fr.yaml index 3745a308579bd51b55da0808b7aa80e92e1c7468..6342e3e9b901aa7b811755b7f530523a3684cf93 100644 --- a/translations/messages.fr.yaml +++ b/translations/messages.fr.yaml @@ -133,4 +133,19 @@ editors: title: Nouvelle capsule dans votre liste text: Vous avez été ajouté par %user_name% en tant qu'éditeur de la capsule "%capsule_name%". Vous pouvez maintenant y accéder et l'éditer. Vous la retrouverez dans la liste de vos capsules. - link: Se rendre sur la page d'édition de la capsule \ No newline at end of file + link: Se rendre sur la page d'édition de la capsule + remove: + button: Supprimer + pending_editor: + title: Supprimer l'éditeur en attente + text: Souhaitez-vous vraiment supprimer l'éditeur en attente %editor_email% ? + link: Supprimer l'éditeur en attente + error: L'adresse email pending_editor_email a déjà été supprimée de la liste des éditeurs en attente de la capsule capsule_name + success: L'adresse email pending_editor_email a bien été supprimée de la liste des éditeurs en attente de la capsule capsule_name + editor: + title: Supprimer l'éditeur + text: Souhaitez-vous vraiment supprimer l'éditeur %editor_email% ? + link: Supprimer l'éditeur + success: L'utilisateur editor_email ne peut plus éditer la capsule capsule_name + error: You can't remove yourself as editor of your own capsule. + If you want to remove the capsule from your list, go to the capsule list page and click on "delete capsule" \ No newline at end of file