Skip to content

Commit

Permalink
feat(kobo): KoboDevice admin is accessible to all users
Browse files Browse the repository at this point in the history
  • Loading branch information
ragusa87 committed May 31, 2024
1 parent 22557cf commit 5a7cdc2
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 100 deletions.
81 changes: 0 additions & 81 deletions src/Controller/Kobo/KoboAdminController.php

This file was deleted.

108 changes: 108 additions & 0 deletions src/Controller/Kobo/KoboDeviceController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace App\Controller\Kobo;

use App\Entity\KoboDevice;
use App\Entity\User;
use App\Form\KoboType;
use App\Repository\KoboDeviceRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

#[Route('/settings/kobo')]
class KoboDeviceController extends AbstractController
{
#[Route('/', name: 'app_kobo_setting_index', methods: ['GET'])]
public function index(KoboDeviceRepository $koboDeviceRepository): Response
{
if ($this->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);
}
}
27 changes: 17 additions & 10 deletions src/Form/KoboType.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,18 +25,20 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
->add('forceSync', null, [
'label' => 'Force Sync',
'required' => false,
])
->add('user', EntityType::class, [
]);
if ($this->security->isGranted('ROLE_ADMIN')) {
$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,
])
;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Menu/MenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ 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']);
$menu->addChild('Not verified', ['route' => 'app_allbooks', ...$this->defaultAttr, 'routeParameters' => $params])->setExtra('icon', 'question-circle-fill');
}

$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');

Expand Down
45 changes: 45 additions & 0 deletions src/Security/Voter/KoboDeviceVoter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace App\Security\Voter;

use App\Entity\KoboDevice;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;

class KoboDeviceVoter extends Voter
{
public const EDIT = 'EDIT';
public const VIEW = 'VIEW';
public const CREATE = 'CREATE';
public const DELETE = 'DELETE';

protected function supports(string $attribute, mixed $subject): bool
{
return in_array($attribute, [self::EDIT, self::VIEW, self::CREATE, self::DELETE], true)
&& $subject instanceof KoboDevice;
}

protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->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;
}
}
4 changes: 3 additions & 1 deletion templates/kobo_admin/_delete_form.html.twig
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<form method="post" action="{{ path('app_kobo_admin_delete', {'id': kobo.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
{% if is_granted("DELETE", kobo) %}
<form method="post" action="{{ path('app_kobo_setting_delete', {'id': kobo.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ kobo.id) }}">
<button class="btn btn-danger">Delete</button>
</form>
{% endif %}
2 changes: 1 addition & 1 deletion templates/kobo_admin/edit.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{% block body %}
{{ include('kobo_admin/_form.html.twig', {'button_label': 'Update'}) }}

<a href="{{ path('app_kobo_admin_index') }}">back to list</a>
<a href="{{ path('app_kobo_setting_index') }}">back to list</a>

<div class="mt-3">
{{ include('kobo_admin/_delete_form.html.twig') }}
Expand Down
10 changes: 7 additions & 3 deletions templates/kobo_admin/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@
<td>{{ kobo.name }}</td>
<td>{{ kobo.accessKey }}</td>
<td>
<a href="{{ path('app_kobo_admin_show', {'id': kobo.id}) }}">show</a>
<a href="{{ path('app_kobo_admin_edit', {'id': kobo.id}) }}">edit</a>
{% if is_granted('VIEW', kobo) %}
<a href="{{ path('app_kobo_setting_show', {'id': kobo.id}) }}">show</a>
{% endif %}
{% if is_granted('EDIT', kobo) %}
<a href="{{ path('app_kobo_setting_edit', {'id': kobo.id}) }}">edit</a>
{% endif %}
</td>
</tr>
{% else %}
Expand All @@ -31,7 +35,7 @@
</tbody>
</table>

<a href="{{ path('app_kobo_admin_new') }}">Create new</a>
<a href="{{ path('app_kobo_setting_new') }}">Create new</a>


{{ include('kobo_admin/instructions.html.twig') }}
Expand Down
2 changes: 1 addition & 1 deletion templates/kobo_admin/new.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{{ include('kobo_admin/_form.html.twig') }}

<div>
<a href="{{ path('app_kobo_admin_index') }}">back to list</a>
<a href="{{ path('app_kobo_setting_index') }}">back to list</a>
</div>

{{ include('kobo_admin/instructions.html.twig') }}
Expand Down
4 changes: 2 additions & 2 deletions templates/kobo_admin/show.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
</tbody>
</table>

<a href="{{ path('app_kobo_admin_index') }}">back to list</a>
<a href="{{ path('app_kobo_setting_index') }}">back to list</a>

<a href="{{ path('app_kobo_admin_edit', {'id': kobo.id}) }}">edit</a>
<a href="{{ path('app_kobo_setting_edit', {'id': kobo.id}) }}">edit</a>

{{ include('kobo_admin/_delete_form.html.twig') }}

Expand Down

0 comments on commit 5a7cdc2

Please sign in to comment.