diff --git a/migrations/Version20230404215108.php b/migrations/Version20230404215108.php new file mode 100644 index 0000000..3e1aae2 --- /dev/null +++ b/migrations/Version20230404215108.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE snip ADD public TINYINT(1) NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE snip DROP public'); + } +} diff --git a/src/Controller/SnipController.php b/src/Controller/SnipController.php index e716654..26a7a6b 100644 --- a/src/Controller/SnipController.php +++ b/src/Controller/SnipController.php @@ -5,6 +5,7 @@ namespace App\Controller; use App\Entity\Snip; use App\Form\SnipType; use App\Repository\SnipRepository; +use App\Security\Voter\SnipVoter; use App\Service\SnipServiceFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -33,6 +34,8 @@ class SnipController extends AbstractController #[Route('/single/{snip}', name: '_single')] public function single(Snip $snip): Response { + $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); + return $this->render('snip/single.html.twig', [ 'snip' => $snip, 'content' => $this->snipServiceFactory->create($snip)->get(), @@ -42,6 +45,8 @@ class SnipController extends AbstractController #[Route('/raw/{snip}', name: '_raw')] public function raw(Snip $snip, Request $request): Response { + $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); + $response = new Response( $this->snipServiceFactory->create($snip)->get(), Response::HTTP_OK, @@ -67,6 +72,8 @@ class SnipController extends AbstractController #[Route('/edit/{snip}', name: '_edit')] public function edit(Snip $snip, Request $request): Response { + $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); + $form = $this->createForm(SnipType::class, $snip); $form->add('Save', SubmitType::class); if ($snip->getId()) { diff --git a/src/Entity/Snip.php b/src/Entity/Snip.php index 82805a4..405ff3d 100644 --- a/src/Entity/Snip.php +++ b/src/Entity/Snip.php @@ -19,6 +19,9 @@ class Snip #[ORM\Column(length: 255)] private ?string $name = null; + #[ORM\Column] + private ?bool $public = null; + public function __toString(): string { return $this->name ?? ''; @@ -40,4 +43,16 @@ class Snip return $this; } + + public function isPublic(): ?bool + { + return $this->public; + } + + public function setPublic(bool $public): self + { + $this->public = $public; + + return $this; + } } diff --git a/src/Form/SnipType.php b/src/Form/SnipType.php index 7deb35d..28b3e65 100644 --- a/src/Form/SnipType.php +++ b/src/Form/SnipType.php @@ -18,6 +18,7 @@ class SnipType extends AbstractType 'attr' => ['rows' => 20], 'mapped' => false, ]) + ->add('public') ; } diff --git a/src/Security/Voter/SnipVoter.php b/src/Security/Voter/SnipVoter.php new file mode 100644 index 0000000..7aefe01 --- /dev/null +++ b/src/Security/Voter/SnipVoter.php @@ -0,0 +1,47 @@ +getUser(); + // if the user is anonymous, do not grant access + if (!$user instanceof UserInterface) { + return false; + } + + // ... (check conditions and return true to grant permission) ... + switch ($attribute) { + case self::VIEW: + if ($subject->isPublic()) { + return true; + } + case self::EDIT: + if ($subject->getCreatedBy() === $user) { + return true; + } + break; + } + + return false; + } +} diff --git a/templates/snip/badge.html.twig b/templates/snip/badge.html.twig new file mode 100644 index 0000000..6c4226b --- /dev/null +++ b/templates/snip/badge.html.twig @@ -0,0 +1,9 @@ +{% if snip.public %} + + + +{% else %} + + + +{% endif %} \ No newline at end of file diff --git a/templates/snip/index.html.twig b/templates/snip/index.html.twig index 59bbc98..0a6d7dd 100644 --- a/templates/snip/index.html.twig +++ b/templates/snip/index.html.twig @@ -6,7 +6,7 @@
{% for snip in snips %} - {{ snip }} + {{ include('snip/badge.html.twig', {snip: snip}) }} {{ snip }} {% endfor %}
diff --git a/templates/snip/single.html.twig b/templates/snip/single.html.twig index cd126b9..be69858 100644 --- a/templates/snip/single.html.twig +++ b/templates/snip/single.html.twig @@ -3,9 +3,12 @@ {% block body %}

- - - + {% if is_granted('edit', snip) %} + + + + {% endif %} + {{ include('snip/badge.html.twig', {snip: snip}) }} {{ snip }}