From aedeb0fc425058efa81b060e9dfc20011c1f89d0 Mon Sep 17 00:00:00 2001 From: Laurent Constantin Date: Fri, 31 May 2024 17:35:45 +0200 Subject: [PATCH] feat(kobo): KoboDevice admin is accessible to all users --- src/Controller/Kobo/KoboAdminController.php | 81 -------------- src/Controller/Kobo/KoboDeviceController.php | 108 +++++++++++++++++++ src/Form/KoboType.php | 28 +++-- src/Menu/MenuBuilder.php | 2 +- src/Security/Voter/KoboDeviceVoter.php | 45 ++++++++ templates/kobo_admin/_delete_form.html.twig | 4 +- templates/kobo_admin/edit.html.twig | 2 +- templates/kobo_admin/index.html.twig | 10 +- templates/kobo_admin/new.html.twig | 2 +- templates/kobo_admin/show.html.twig | 4 +- 10 files changed, 186 insertions(+), 100 deletions(-) delete mode 100644 src/Controller/Kobo/KoboAdminController.php create mode 100644 src/Controller/Kobo/KoboDeviceController.php create mode 100644 src/Security/Voter/KoboDeviceVoter.php diff --git a/src/Controller/Kobo/KoboAdminController.php b/src/Controller/Kobo/KoboAdminController.php deleted file mode 100644 index 4b48c6fa..00000000 --- a/src/Controller/Kobo/KoboAdminController.php +++ /dev/null @@ -1,81 +0,0 @@ -render('kobo_admin/index.html.twig', [ - 'kobos' => $koboDeviceRepository->findAll(), - ]); - } - - #[Route('/new', name: 'app_kobo_admin_new', methods: ['GET', 'POST'])] - public function new(Request $request, EntityManagerInterface $entityManager): Response - { - $koboDevice = new KoboDevice(); - $form = $this->createForm(KoboType::class, $koboDevice); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $entityManager->persist($koboDevice); - $entityManager->flush(); - - return $this->redirectToRoute('app_kobo_admin_index', [], Response::HTTP_SEE_OTHER); - } - - return $this->render('kobo_admin/new.html.twig', [ - 'kobo' => $koboDevice, - 'form' => $form, - ]); - } - - #[Route('/{id}', name: 'app_kobo_admin_show', methods: ['GET'])] - public function show(KoboDevice $kobo): Response - { - return $this->render('kobo_admin/show.html.twig', [ - 'kobo' => $kobo, - ]); - } - - #[Route('/{id}/edit', name: 'app_kobo_admin_edit', methods: ['GET', 'POST'])] - public function edit(Request $request, KoboDevice $kobo, EntityManagerInterface $entityManager): Response - { - $form = $this->createForm(KoboType::class, $kobo); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $entityManager->flush(); - - return $this->redirectToRoute('app_kobo_admin_index', [], Response::HTTP_SEE_OTHER); - } - - return $this->render('kobo_admin/edit.html.twig', [ - 'kobo' => $kobo, - 'form' => $form, - ]); - } - - #[Route('/{id}', name: 'app_kobo_admin_delete', methods: ['POST'])] - public function delete(Request $request, KoboDevice $kobo, EntityManagerInterface $entityManager): Response - { - if ($this->isCsrfTokenValid('delete'.$kobo->getId(), (string) $request->request->get('_token'))) { - $entityManager->remove($kobo); - $entityManager->flush(); - } - - return $this->redirectToRoute('app_kobo_admin_index', [], Response::HTTP_SEE_OTHER); - } -} diff --git a/src/Controller/Kobo/KoboDeviceController.php b/src/Controller/Kobo/KoboDeviceController.php new file mode 100644 index 00000000..2f046ffa --- /dev/null +++ b/src/Controller/Kobo/KoboDeviceController.php @@ -0,0 +1,108 @@ +getUser() === null) { + throw $this->createAccessDeniedException(); + } + + return $this->render('kobo_admin/index.html.twig', [ + 'kobos' => $koboDeviceRepository->findAllByUser($this->getUser()), + ]); + } + + #[Route('/new', name: 'app_kobo_setting_new', methods: ['GET', 'POST'])] + public function new(Request $request, EntityManagerInterface $entityManager): Response + { + $user = $this->getUser(); + if (!$user instanceof User) { + throw $this->createAccessDeniedException(); + } + $koboDevice = new KoboDevice(); + $koboDevice->setUser($user); + + if (!$this->isGranted('CREATE', $koboDevice)) { + throw $this->createAccessDeniedException(); + } + + $form = $this->createForm(KoboType::class, $koboDevice); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $entityManager->persist($koboDevice); + $entityManager->flush(); + + return $this->redirectToRoute('app_kobo_setting_index', [], Response::HTTP_SEE_OTHER); + } + + return $this->render('kobo_admin/new.html.twig', [ + 'kobo' => $koboDevice, + 'form' => $form, + ]); + } + + #[Route('/{id}', name: 'app_kobo_setting_show', methods: ['GET'])] + public function show(KoboDevice $koboDevice): Response + { + if (!$this->isGranted('VIEW', $koboDevice)) { + throw $this->createAccessDeniedException(); + } + + return $this->render('kobo_admin/show.html.twig', [ + 'kobo' => $koboDevice, + ]); + } + + #[Route('/{id}/edit', name: 'app_kobo_setting_edit', methods: ['GET', 'POST'])] + public function edit(Request $request, KoboDevice $koboDevice, EntityManagerInterface $entityManager): Response + { + if (!$this->isGranted('EDIT', $koboDevice)) { + throw $this->createAccessDeniedException('You don\'t have permission to edit this koboDevice'); + } + + $form = $this->createForm(KoboType::class, $koboDevice); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $entityManager->flush(); + + return $this->redirectToRoute('app_kobo_setting_index', [], Response::HTTP_SEE_OTHER); + } + + return $this->render('kobo_admin/edit.html.twig', [ + 'kobo' => $koboDevice, + 'form' => $form, + ]); + } + + #[Route('/{id}', name: 'app_kobo_setting_delete', methods: ['POST'])] + public function delete(Request $request, KoboDevice $koboDevice, EntityManagerInterface $entityManager): Response + { + if (!$this->isGranted('DELETE', $koboDevice)) { + throw $this->createAccessDeniedException(); + } + + if ($this->isCsrfTokenValid('delete'.$koboDevice->getId(), (string) $request->request->get('_token'))) { + $entityManager->remove($koboDevice); + $entityManager->flush(); + } + + return $this->redirectToRoute('app_kobo_setting_index', [], Response::HTTP_SEE_OTHER); + } +} diff --git a/src/Form/KoboType.php b/src/Form/KoboType.php index 47a3cc04..c20feebd 100644 --- a/src/Form/KoboType.php +++ b/src/Form/KoboType.php @@ -6,12 +6,17 @@ use App\Entity\Shelf; use App\Entity\User; use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class KoboType extends AbstractType { + public function __construct(protected Security $security) + { + } + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder @@ -20,18 +25,21 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ->add('forceSync', null, [ 'label' => 'Force Sync', 'required' => false, - ]) - ->add('user', EntityType::class, [ + ]); + if (false && $this->security->isGranted('ROLE_ADMIN', $options['user'])) { + $builder-> + add('user', EntityType::class, [ 'class' => User::class, 'choice_label' => 'username', - ]) - ->add('shelves', EntityType::class, [ - 'label' => 'Sync with Shelves', - 'class' => Shelf::class, - 'choice_label' => 'name', - 'multiple' => true, - 'expanded' => true, - ]) + ]); + } + $builder->add('shelves', EntityType::class, [ + 'label' => 'Sync with Shelves', + 'class' => Shelf::class, + 'choice_label' => 'name', + 'multiple' => true, + 'expanded' => true, + ]) ; } diff --git a/src/Menu/MenuBuilder.php b/src/Menu/MenuBuilder.php index b931b710..7839868a 100644 --- a/src/Menu/MenuBuilder.php +++ b/src/Menu/MenuBuilder.php @@ -77,7 +77,6 @@ public function createMainMenu(array $options): ItemInterface if ($this->security->isGranted('ROLE_ADMIN')) { $menu->addChild('admin_divider', ['label' => 'Admin'])->setExtra('divider', true); $menu->addChild('Admin', ['route' => 'app_user_index', ...$this->defaultAttr])->setExtra('icon', 'gear-fill'); - $menu->addChild('Kobos', ['route' => 'app_kobo_admin_index', ...$this->defaultAttr])->setExtra('icon', 'gear-fill'); $menu->addChild('Add Books', ['route' => 'app_book_consume', ...$this->defaultAttr])->setExtra('icon', 'bookmark-plus-fill'); $params = $this->filteredBookUrlGenerator->getParametersArray(['verified' => 'unverified', 'orderBy' => 'serieIndex-asc']); @@ -85,6 +84,7 @@ public function createMainMenu(array $options): ItemInterface } $menu->addChild('profile_divider', ['label' => 'profile'])->setExtra('divider', true); + $menu->addChild('Kobos Devices', ['route' => 'app_kobo_setting_index', ...$this->defaultAttr])->setExtra('icon', 'gear-fill'); $menu->addChild('My profile', ['route' => 'app_user_profile', ...$this->defaultAttr])->setExtra('icon', 'person-circle'); $menu->addChild('Logout', ['route' => 'app_logout', ...$this->defaultAttr])->setExtra('icon', 'door-closed'); diff --git a/src/Security/Voter/KoboDeviceVoter.php b/src/Security/Voter/KoboDeviceVoter.php new file mode 100644 index 00000000..482f2d64 --- /dev/null +++ b/src/Security/Voter/KoboDeviceVoter.php @@ -0,0 +1,45 @@ +getUser(); + // if the user is anonymous, do not grant access + if (!$user instanceof UserInterface) { + return false; + } + + if (!$subject instanceof KoboDevice) { + return false; + } + + if ($subject->getUser() === $user) { + return true; + } + + if (in_array('ROLE_ADMIN', $user->getRoles(), true)) { + return true; + } + + return false; + } +} diff --git a/templates/kobo_admin/_delete_form.html.twig b/templates/kobo_admin/_delete_form.html.twig index f1d33e82..93ff09f7 100644 --- a/templates/kobo_admin/_delete_form.html.twig +++ b/templates/kobo_admin/_delete_form.html.twig @@ -1,4 +1,6 @@ -
+{% if is_granted("DELETE", kobo) %} +
+{% endif %} \ No newline at end of file diff --git a/templates/kobo_admin/edit.html.twig b/templates/kobo_admin/edit.html.twig index 086ce23d..22ba8f16 100644 --- a/templates/kobo_admin/edit.html.twig +++ b/templates/kobo_admin/edit.html.twig @@ -5,7 +5,7 @@ {% block body %} {{ include('kobo_admin/_form.html.twig', {'button_label': 'Update'}) }} - back to list + back to list
{{ include('kobo_admin/_delete_form.html.twig') }} diff --git a/templates/kobo_admin/index.html.twig b/templates/kobo_admin/index.html.twig index 3c9f1adb..2cffed81 100644 --- a/templates/kobo_admin/index.html.twig +++ b/templates/kobo_admin/index.html.twig @@ -19,8 +19,12 @@ {{ kobo.name }} {{ kobo.accessKey }} - show - edit + {% if is_granted('VIEW', kobo) %} + show + {% endif %} + {% if is_granted('EDIT', kobo) %} + edit + {% endif %} {% else %} @@ -31,7 +35,7 @@ - Create new + Create new {{ include('kobo_admin/instructions.html.twig') }} diff --git a/templates/kobo_admin/new.html.twig b/templates/kobo_admin/new.html.twig index 121e1055..8dbb3203 100644 --- a/templates/kobo_admin/new.html.twig +++ b/templates/kobo_admin/new.html.twig @@ -7,7 +7,7 @@ {{ include('kobo_admin/_form.html.twig') }}
- back to list + back to list
{{ include('kobo_admin/instructions.html.twig') }} diff --git a/templates/kobo_admin/show.html.twig b/templates/kobo_admin/show.html.twig index feca1366..546c6102 100644 --- a/templates/kobo_admin/show.html.twig +++ b/templates/kobo_admin/show.html.twig @@ -21,9 +21,9 @@ - back to list + back to list - edit + edit {{ include('kobo_admin/_delete_form.html.twig') }}