diff --git a/assets/controllers/delete_record_controller.js b/assets/controllers/delete_record_controller.js index 9b504b9..82ef548 100644 --- a/assets/controllers/delete_record_controller.js +++ b/assets/controllers/delete_record_controller.js @@ -33,4 +33,3 @@ export default class extends Controller { location.href = delPath; } } - diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 0dfcebb..59cdd56 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -40,6 +40,7 @@ security: - { path: ^/bibliography, roles: ROLE_USER } - { path: ^/collection, roles: ROLE_USER } - { path: ^/collector, roles: ROLE_USER } + - { path: ^/document, roles: ROLE_USER } - { path: ^/object, roles: ROLE_USER } - { path: ^/site, roles: ROLE_USER } diff --git a/src/Controller/BibliographyController.php b/src/Controller/BibliographyController.php index d924407..e95e7d0 100644 --- a/src/Controller/BibliographyController.php +++ b/src/Controller/BibliographyController.php @@ -6,19 +6,19 @@ use App\Entity\Bibliography; use App\Entity\Collection; use App\Entity\Collector; use App\Form\BibliographyType; -//use App\Security\Voter\VocabVoter; +use App\Security\Voter\RecordVoter; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -//use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; class BibliographyController extends AbstractController { #[Route('/bibliography/{id<\d+>}', name: 'app_bibliography')] public function index(Bibliography $bibliography, EntityManagerInterface $em): Response { + $repo = $em->getRepository(Collection::class); $collections = $repo->findAllByBibliography($bibliography->getId()); $repo = $em->getRepository(Collector::class); @@ -71,15 +71,23 @@ class BibliographyController extends AbstractController ]); } /** - * @todo Permissions! + * @todo Permissions! Return JSON with 403 when AJAX */ #[Route('/bibliography/delete/{id<\d+>}', name: 'app_bibliography_del')] public function delete(Bibliography $bibliography, EntityManagerInterface $em): Response { + try { + $this->denyAccessUnlessGranted(RecordVoter::DELETE, $bibliography); + } + catch (AccessDeniedException) { + $this->addFlash('warning', 'You are not authorized to delete this record'); + return $this->redirectToRoute('app_home'); + } + $em->remove($bibliography); $em->flush(); - $this->addFlash('notice', 'Term deleted successfully'); + $this->addFlash('notice', 'Record deleted successfully'); return $this->redirectToRoute('app_bibliography_landing'); } diff --git a/src/Controller/CollectionController.php b/src/Controller/CollectionController.php index 8fa44b5..2d99403 100644 --- a/src/Controller/CollectionController.php +++ b/src/Controller/CollectionController.php @@ -4,10 +4,12 @@ namespace App\Controller; use App\Entity\Collection; use App\Entity\Bibliography; +use App\Security\Voter\RecordVoter; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; class CollectionController extends AbstractController { @@ -40,4 +42,23 @@ class CollectionController extends AbstractController 'count' => $count, ]); } + + #[Route('/collection/delete/{id<\d+>}', name: 'app_collection_del')] + public function delete(Collection $collection, EntityManagerInterface $em): Response + { + try { + $this->denyAccessUnlessGranted(RecordVoter::DELETE, $collection); + } + catch (AccessDeniedException) { + $this->addFlash('warning', 'You are not authorized to delete this record'); + return $this->redirectToRoute('app_home'); + } + + $em->remove($collection); + $em->flush(); + + $this->addFlash('notice', 'Record deleted successfully'); + + return $this->redirectToRoute('app_collection_landing'); + } } diff --git a/src/Controller/CollectorController.php b/src/Controller/CollectorController.php index 62a4864..ebaacc5 100644 --- a/src/Controller/CollectorController.php +++ b/src/Controller/CollectorController.php @@ -5,10 +5,12 @@ namespace App\Controller; use App\Entity\Collector; use App\Entity\Collection; use App\Entity\Bibliography; +use App\Security\Voter\RecordVoter; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; class CollectorController extends AbstractController { @@ -40,4 +42,23 @@ class CollectorController extends AbstractController 'count' => $count, ]); } + + #[Route('/collector/delete/{id<\d+>}', name: 'app_collector_del')] + public function delete(Collector $collector, EntityManagerInterface $em): Response + { + try { + $this->denyAccessUnlessGranted(RecordVoter::DELETE, $collector); + } + catch (AccessDeniedException) { + $this->addFlash('warning', 'You are not authorized to delete this record'); + return $this->redirectToRoute('app_home'); + } + + $em->remove($collector); + $em->flush(); + + $this->addFlash('notice', 'Record deleted successfully'); + + return $this->redirectToRoute('app_collector_landing'); + } } diff --git a/src/Entity/Bibliography.php b/src/Entity/Bibliography.php index 5b04f29..9341f3f 100644 --- a/src/Entity/Bibliography.php +++ b/src/Entity/Bibliography.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\RecordInterface; use App\Repository\BibliographyRepository; use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; @@ -11,7 +12,7 @@ use Doctrine\Common\Collections\Collection as DoctrineCollection; #[ORM\Entity(repositoryClass: BibliographyRepository::class)] #[ORM\Table(name: 'bibliography')] -class Bibliography +class Bibliography implements RecordInterface { #[ORM\Id] #[ORM\GeneratedValue] diff --git a/src/Entity/Collection.php b/src/Entity/Collection.php index 9a9727b..41106a9 100644 --- a/src/Entity/Collection.php +++ b/src/Entity/Collection.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\RecordInterface; use App\Repository\CollectionRepository; use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; @@ -11,7 +12,7 @@ use Doctrine\Common\Collections\Collection as DoctrineCollection; #[ORM\Entity(repositoryClass: CollectionRepository::class)] #[ORM\Table(name: 'collection')] -class Collection +class Collection implements RecordInterface { #[ORM\Id] #[ORM\GeneratedValue] diff --git a/src/Entity/Collector.php b/src/Entity/Collector.php index 8c58dfe..ae2c316 100644 --- a/src/Entity/Collector.php +++ b/src/Entity/Collector.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\RecordInterface; use App\Repository\CollectorRepository; use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; @@ -11,7 +12,7 @@ use Doctrine\Common\Collections\Collection as DoctrineCollection; #[ORM\Entity(repositoryClass: CollectorRepository::class)] #[ORM\Table(name: 'collector')] -class Collector +class Collector implements RecordInterface { #[ORM\Id] #[ORM\GeneratedValue] diff --git a/src/RecordInterface.php b/src/RecordInterface.php new file mode 100644 index 0000000..619f5da --- /dev/null +++ b/src/RecordInterface.php @@ -0,0 +1,7 @@ +getUser(); + + // if the user is anonymous, do not grant access + if (!$user instanceof UserInterface) { + return false; + } + + $roles = $user->getRoles(); + + // TODO: Better way to check roles? + switch ($attribute) { + case self::EDIT: + case self::DELETE: + return in_array('ROLE_ADMIN', $roles) + || in_array('ROLE_REVISOR', $roles); + break; + + case self::VIEW: + return ! in_array('ROLE_READER', $roles); + break; + } + + return false; + } +} + diff --git a/src/Security/Voter/VocabVoter.php b/src/Security/Voter/VocabVoter.php index 3fa3537..58c4b97 100644 --- a/src/Security/Voter/VocabVoter.php +++ b/src/Security/Voter/VocabVoter.php @@ -35,8 +35,8 @@ final class VocabVoter extends Voter switch ($attribute) { case self::EDIT: case self::DELETE: - return in_array('ROLE_ADMIN', $roles) - || in_array('ROLE_REVISOR', $roles); + return in_array('ROLE_ADMIN', $roles) + || in_array('ROLE_REVISOR', $roles); break; case self::VIEW: diff --git a/templates/bibliography/landing.html.twig b/templates/bibliography/landing.html.twig index a79f02a..33c8c3b 100644 --- a/templates/bibliography/landing.html.twig +++ b/templates/bibliography/landing.html.twig @@ -3,7 +3,7 @@ {% block title %}Bibliography | ArCOA{% endblock %} {% block rightpanel %} -
Delete record?
+ +This record will be permanently deleted. Proceed?
+