Skip to content
Snippets Groups Projects
Commit c0fa2081 authored by Sebastien's avatar Sebastien
Browse files

Merge branch 'tuleap-82-remove-access-right-to-an-invited-user' into 'main'

tuleap-82-remove-access-right-to-an-invited-user

See merge request !47
parents 7815fc9e b4d25cfb
No related branches found
No related tags found
1 merge request!47tuleap-82-remove-access-right-to-an-invited-user
Pipeline #779 passed
...@@ -152,3 +152,7 @@ button[type=submit]{ ...@@ -152,3 +152,7 @@ button[type=submit]{
text-transform: uppercase; text-transform: uppercase;
font-size: 18px; font-size: 18px;
} }
.remove-link {
font-size: 0.9rem;
}
\ No newline at end of file
...@@ -3,15 +3,14 @@ ...@@ -3,15 +3,14 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Capsule; use App\Entity\Capsule;
use App\Entity\CapsuleEditor; use App\Entity\PendingEditorInvitation;
use App\Entity\CapsulePendingEditor;
use App\Entity\User; use App\Entity\User;
use App\Form\CapsuleEditorsFormType; use App\Form\CapsuleEditorsFormType;
use App\Repository\CapsulePendingEditorRepository; use App\Form\RemoveEditorFormType;
use App\Repository\CapsuleRepository; use App\Repository\CapsuleRepository;
use App\Repository\PendingEditorInvitationRepository;
use App\Repository\UserRepository; use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use http\Env;
use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
...@@ -26,22 +25,28 @@ class CapsuleEditorController extends AbstractController ...@@ -26,22 +25,28 @@ class CapsuleEditorController extends AbstractController
{ {
private TranslatorInterface $translator; private TranslatorInterface $translator;
private MailerInterface $mailer; private MailerInterface $mailer;
private CapsulePendingEditorRepository $capsule_pending_editor_repository; private PendingEditorInvitationRepository $capsule_pending_editor_invitation_repository;
private EntityManagerInterface $entity_manager; private EntityManagerInterface $entity_manager;
private UrlGeneratorInterface $urlGenerator; private UrlGeneratorInterface $urlGenerator;
private CapsuleRepository $capsule_repository;
private UserRepository $user_repository;
public function __construct( public function __construct(
MailerInterface $mailer, MailerInterface $mailer,
TranslatorInterface $translator, TranslatorInterface $translator,
CapsulePendingEditorRepository $capsule_pending_editor_repository, PendingEditorInvitationRepository $capsule_pending_editor_invitation_repository,
EntityManagerInterface $entity_manager, EntityManagerInterface $entity_manager,
UrlGeneratorInterface $urlGenerator UrlGeneratorInterface $urlGenerator,
CapsuleRepository $capsule_repository,
UserRepository $user_repository
) { ) {
$this->mailer = $mailer; $this->mailer = $mailer;
$this->translator = $translator; $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->entity_manager = $entity_manager;
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
$this->capsule_repository = $capsule_repository;
$this->user_repository = $user_repository;
} }
/** /**
...@@ -49,16 +54,14 @@ class CapsuleEditorController extends AbstractController ...@@ -49,16 +54,14 @@ class CapsuleEditorController extends AbstractController
*/ */
public function editCapsuleEditors( public function editCapsuleEditors(
Request $request, Request $request,
int $capsule_id, int $capsule_id
CapsuleRepository $capsule_repository,
UserRepository $user_repository
): Response { ): Response {
$current_user = $this->getUser(); $current_user = $this->getUser();
if (! $current_user instanceof User) { if (! $current_user instanceof User) {
return $this->redirectToRoute('app_logout'); return $this->redirectToRoute('app_logout');
} }
$capsule = $capsule_repository->find($capsule_id); $capsule = $this->capsule_repository->find($capsule_id);
if (! $capsule) { if (! $capsule) {
throw $this->createNotFoundException( throw $this->createNotFoundException(
'No capsule found for id ' . $capsule_id 'No capsule found for id ' . $capsule_id
...@@ -67,7 +70,6 @@ class CapsuleEditorController extends AbstractController ...@@ -67,7 +70,6 @@ class CapsuleEditorController extends AbstractController
$current_capsule_editors_users = $capsule->getEditors()->toArray(); $current_capsule_editors_users = $capsule->getEditors()->toArray();
if (! $capsule->getEditors()->contains($current_user)) { if (! $capsule->getEditors()->contains($current_user)) {
// in_array($current_user, $current_capsule_editors_users)) {
$this->addFlash( $this->addFlash(
'warning', 'warning',
$this->translator->trans( $this->translator->trans(
...@@ -86,7 +88,7 @@ class CapsuleEditorController extends AbstractController ...@@ -86,7 +88,7 @@ class CapsuleEditorController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$editor_email = $form->get('email')->getData(); $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]); ->findOneBy(['email' => $editor_email]);
if (! $user_associated_with_email_address instanceof User) { if (! $user_associated_with_email_address instanceof User) {
...@@ -106,19 +108,21 @@ class CapsuleEditorController extends AbstractController ...@@ -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', [ return $this->render('capsule/editors/list_editors.html.twig', [
'userPermissionsCapsuleForm' => $form->createView(), 'userPermissionsCapsuleForm' => $form->createView(),
'capsule_name' => $capsule->getName(), 'capsule' => $capsule,
'editors' => $current_capsule_editors_users, '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 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)) { if (in_array($editor_email, $pending_editors_emails)) {
$this->addFlash( $this->addFlash(
...@@ -133,10 +137,10 @@ class CapsuleEditorController extends AbstractController ...@@ -133,10 +137,10 @@ class CapsuleEditorController extends AbstractController
return; return;
} }
$pending_editor = new CapsulePendingEditor(); $pending_editor_invitation = new PendingEditorInvitation();
$pending_editor->setCapsuleId($capsule->getId()); $pending_editor_invitation->setCapsuleId($capsule->getId());
$pending_editor->setEmail($editor_email); $pending_editor_invitation->setEmail($editor_email);
$this->entity_manager->persist($pending_editor); $this->entity_manager->persist($pending_editor_invitation);
$this->entity_manager->flush(); $this->entity_manager->flush();
$email = (new TemplatedEmail()) $email = (new TemplatedEmail())
...@@ -216,4 +220,136 @@ class CapsuleEditorController extends AbstractController ...@@ -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
]);
}
} }
<?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;
}
}
<?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([]);
}
}
<?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;
}
}
...@@ -19,6 +19,28 @@ class PendingEditorInvitationRepository extends ServiceEntityRepository ...@@ -19,6 +19,28 @@ class PendingEditorInvitationRepository extends ServiceEntityRepository
parent::__construct($registry, PendingEditorInvitation::class); 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> * @return array<PendingEditorInvitation>
*/ */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<div class="row w-100 gx-0"> <div class="row w-100 gx-0">
<div class="row-title-box"> <div class="row-title-box">
<h3 class="row-title"> <h3 class="row-title">
{{ 'editors.title_name'|trans({'%capsule_name%': capsule_name}) }} {{ 'editors.title_name'|trans({'%capsule_name%': capsule.getName()}) }}
</h3> </h3>
</div> </div>
</div> </div>
...@@ -46,6 +46,12 @@ ...@@ -46,6 +46,12 @@
{% for editor in editors %} {% for editor in editors %}
<li class="text-capitalize text-secondary list-unstyled p-1"> <li class="text-capitalize text-secondary list-unstyled p-1">
{{ editor.getFirstName() }} {{ editor.getLastName() }} {{ 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> </li>
{% endfor %} {% endfor %}
</ul> </ul>
...@@ -56,6 +62,9 @@ ...@@ -56,6 +62,9 @@
{% for pending_editor in pending_editors %} {% for pending_editor in pending_editors %}
<li class="text-secondary list-unstyled p-1"> <li class="text-secondary list-unstyled p-1">
{{ pending_editor.getEmail() }} {{ 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> </li>
{% endfor %} {% endfor %}
</ul> </ul>
......
{% 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
{% 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
...@@ -136,3 +136,18 @@ editors: ...@@ -136,3 +136,18 @@ editors:
text: You have been add by %user_name% as editor of the capsule "%capsule_name%". 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. You can now access and edit it. You will find the capsule in your capsule list.
link: Go to capsule edition page 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
...@@ -134,3 +134,18 @@ editors: ...@@ -134,3 +134,18 @@ editors:
text: Vous avez été ajouté par %user_name% en tant qu'éditeur de la capsule "%capsule_name%". 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. 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 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment