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 Jul 14, 2024
1 parent 5cad680 commit a129dbe
Show file tree
Hide file tree
Showing 15 changed files with 219 additions and 133 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('/user/kobo')]
class KoboDeviceController extends AbstractController
{
#[Route('/', name: 'app_kobodevice_user_index', methods: ['GET'])]
public function index(KoboDeviceRepository $koboDeviceRepository): Response
{
if ($this->getUser() === null) {
throw $this->createAccessDeniedException();
}

return $this->render('kobodevice_user/index.html.twig', [
'kobos' => $koboDeviceRepository->findAllByUser($this->getUser()),
]);
}

#[Route('/new', name: 'app_kobodevice_user_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_kobodevice_user_index', [], Response::HTTP_SEE_OTHER);
}

return $this->render('kobodevice_user/new.html.twig', [
'kobo' => $koboDevice,
'form' => $form,
]);
}

#[Route('/{id}', name: 'app_kobodevice_user_show', methods: ['GET'])]
public function show(KoboDevice $koboDevice): Response
{
if (!$this->isGranted('VIEW', $koboDevice)) {
throw $this->createAccessDeniedException();
}

return $this->render('kobodevice_user/show.html.twig', [
'kobo' => $koboDevice,
]);
}

#[Route('/{id}/edit', name: 'app_kobodevice_user_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_kobodevice_user_index', [], Response::HTTP_SEE_OTHER);
}

return $this->render('kobodevice_user/edit.html.twig', [
'kobo' => $koboDevice,
'form' => $form,
]);
}

#[Route('/{id}', name: 'app_kobodevice_user_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_kobodevice_user_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
1 change: 1 addition & 0 deletions src/Menu/MenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public function createMainMenu(array $options): ItemInterface
}

$menu->addChild('profile_divider', ['label' => $user->getUsername()])->setExtra('divider', true);
$menu->addChild('Kobo Devices', ['route' => 'app_kobodevice_user_index', ...$this->defaultAttr])->setExtra('icon', 'gear-fill');
$menu->addChild('My profile', ['route' => 'app_user_profile', ...$this->defaultAttr])->setExtra('icon', 'person-circle');
$menu->addChild('My shelves', ['route' => 'app_shelf_crud_index', ...$this->defaultAttr])->setExtra('icon', 'bookshelf');
if ($user->isDisplayTimeline()) {
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: 0 additions & 4 deletions templates/kobo_admin/_delete_form.html.twig

This file was deleted.

16 changes: 0 additions & 16 deletions templates/kobo_admin/edit.html.twig

This file was deleted.

14 changes: 0 additions & 14 deletions templates/kobo_admin/new.html.twig

This file was deleted.

6 changes: 6 additions & 0 deletions templates/kobodevice_user/_delete_form.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% if is_granted("DELETE", kobo) %}
<form method="post" action="{{ path('app_kobodevice_user_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 %}
File renamed without changes.
16 changes: 16 additions & 0 deletions templates/kobodevice_user/edit.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% extends 'base.html.twig' %}

{% block title %}Edit Kobo{% endblock %}

{% block body %}
{{ include('kobodevice_user/_form.html.twig', {'button_label': 'Update'}) }}

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

<div class="mt-3">
{{ include('kobodevice_user/_delete_form.html.twig') }}
</div>

{{ include('kobodevice_user/instructions.html.twig') }}

{% endblock %}
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_kobodevice_user_show', {'id': kobo.id}) }}">show</a>
{% endif %}
{% if is_granted('EDIT', kobo) %}
<a href="{{ path('app_kobodevice_user_edit', {'id': kobo.id}) }}">edit</a>
{% endif %}
</td>
</tr>
{% else %}
Expand All @@ -31,8 +35,8 @@
</tbody>
</table>

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


{{ include('kobo_admin/instructions.html.twig') }}
{{ include('kobodevice_user/instructions.html.twig') }}
{% endblock %}
File renamed without changes.
14 changes: 14 additions & 0 deletions templates/kobodevice_user/new.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends 'base.html.twig' %}

{% block title %}Create new Kobo{% endblock %}

{% block body %}

{{ include('kobodevice_user/_form.html.twig') }}

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

{{ include('kobodevice_user/instructions.html.twig') }}
{% endblock %}
Loading

0 comments on commit a129dbe

Please sign in to comment.