added invoice voter (#316)
This commit is contained in:
@@ -77,6 +77,7 @@ class InvoiceController extends AbstractController
|
||||
|
||||
/**
|
||||
* @Route(path="/", name="invoice", methods={"GET"})
|
||||
* @Security("is_granted('view', 'invoice')")
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
@@ -110,6 +111,7 @@ class InvoiceController extends AbstractController
|
||||
|
||||
/**
|
||||
* @Route(path="/print", name="invoice_print", methods={"GET"})
|
||||
* @Security("is_granted('create', 'invoice')")
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
@@ -209,8 +211,7 @@ class InvoiceController extends AbstractController
|
||||
/**
|
||||
* @Route(path="/template", defaults={"page": 1}, name="admin_invoice_template", methods={"GET", "POST"})
|
||||
* @Route(path="/template/page/{page}", requirements={"page": "[1-9]\d*"}, name="admin_invoice_template_paginated", methods={"GET", "POST"})
|
||||
*
|
||||
* TODO permission
|
||||
* @Security("is_granted('view', 'invoice_template')")
|
||||
*
|
||||
* @param $page
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
@@ -227,8 +228,7 @@ class InvoiceController extends AbstractController
|
||||
|
||||
/**
|
||||
* @Route(path="/template/{id}/edit", name="admin_invoice_template_edit", methods={"GET", "POST"})
|
||||
*
|
||||
* TODO permission
|
||||
* @Security("is_granted('edit', template)")
|
||||
*
|
||||
* @param InvoiceTemplate $template
|
||||
* @param Request $request
|
||||
@@ -242,8 +242,7 @@ class InvoiceController extends AbstractController
|
||||
|
||||
/**
|
||||
* @Route(path="/template/create", name="admin_invoice_template_create", methods={"GET", "POST"})
|
||||
*
|
||||
* TODO permission
|
||||
* @Security("is_granted('create', 'invoice_template')")
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
@@ -261,9 +260,8 @@ class InvoiceController extends AbstractController
|
||||
/**
|
||||
* The route to delete an existing template.
|
||||
*
|
||||
* TODO permission
|
||||
*
|
||||
* @Route(path="/template/{id}/delete", name="admin_invoice_template_delete", methods={"GET", "POST"})
|
||||
* @Security("is_granted('delete', template)")
|
||||
*
|
||||
* @param InvoiceTemplate $template
|
||||
* @param Request $request
|
||||
|
||||
61
src/Security/AclDecisionManager.php
Normal file
61
src/Security/AclDecisionManager.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
|
||||
class AclDecisionManager
|
||||
{
|
||||
/**
|
||||
* @var AccessDecisionManagerInterface
|
||||
*/
|
||||
protected $decisionManager;
|
||||
|
||||
/**
|
||||
* AbstractVoter constructor.
|
||||
* @param AccessDecisionManagerInterface $decisionManager
|
||||
*/
|
||||
public function __construct(AccessDecisionManagerInterface $decisionManager)
|
||||
{
|
||||
$this->decisionManager = $decisionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TokenInterface $token
|
||||
* @return bool
|
||||
*/
|
||||
public function isFullyAuthenticated(TokenInterface $token)
|
||||
{
|
||||
if ($this->decisionManager->decide($token, ['IS_AUTHENTICATED_FULLY'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TokenInterface $token
|
||||
* @param string|array $roles
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRole(TokenInterface $token, $roles)
|
||||
{
|
||||
if (!is_array($roles)) {
|
||||
$roles = [$roles];
|
||||
}
|
||||
|
||||
if ($this->decisionManager->decide($token, $roles)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
namespace App\Voter;
|
||||
|
||||
use App\Security\AclDecisionManager;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
|
||||
/**
|
||||
@@ -19,15 +19,15 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
abstract class AbstractVoter extends Voter
|
||||
{
|
||||
/**
|
||||
* @var AccessDecisionManagerInterface
|
||||
* @var AclDecisionManager
|
||||
*/
|
||||
protected $decisionManager;
|
||||
|
||||
/**
|
||||
* AbstractVoter constructor.
|
||||
* @param AccessDecisionManagerInterface $decisionManager
|
||||
* @param AclDecisionManager $decisionManager
|
||||
*/
|
||||
public function __construct(AccessDecisionManagerInterface $decisionManager)
|
||||
public function __construct(AclDecisionManager $decisionManager)
|
||||
{
|
||||
$this->decisionManager = $decisionManager;
|
||||
}
|
||||
@@ -38,11 +38,7 @@ abstract class AbstractVoter extends Voter
|
||||
*/
|
||||
protected function isFullyAuthenticated(TokenInterface $token)
|
||||
{
|
||||
if ($this->decisionManager->decide($token, ['IS_AUTHENTICATED_FULLY'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return $this->decisionManager->isFullyAuthenticated($token);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,10 +48,6 @@ abstract class AbstractVoter extends Voter
|
||||
*/
|
||||
protected function hasRole($role, TokenInterface $token)
|
||||
{
|
||||
if ($this->decisionManager->decide($token, [$role])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return $this->decisionManager->hasRole($token, [$role]);
|
||||
}
|
||||
}
|
||||
|
||||
136
src/Voter/InvoiceVoter.php
Normal file
136
src/Voter/InvoiceVoter.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Voter;
|
||||
|
||||
use App\Entity\InvoiceTemplate;
|
||||
use App\Entity\User;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
|
||||
/**
|
||||
* A voter to check permissions on Invoices.
|
||||
*/
|
||||
class InvoiceVoter extends AbstractVoter
|
||||
{
|
||||
public const VIEW = 'view';
|
||||
public const EDIT = 'edit';
|
||||
public const CREATE = 'create';
|
||||
public const DELETE = 'delete';
|
||||
|
||||
public const ALLOWED_ATTRIBUTES = [
|
||||
self::VIEW,
|
||||
self::CREATE,
|
||||
self::EDIT,
|
||||
self::DELETE
|
||||
];
|
||||
|
||||
public const ALLOWED_SUBJECTS = [
|
||||
'invoice',
|
||||
'invoice_template'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param mixed $subject
|
||||
* @return bool
|
||||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if (!in_array($attribute, self::ALLOWED_ATTRIBUTES)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$subject instanceof InvoiceTemplate) {
|
||||
if (!is_string($subject) || !in_array($subject, self::ALLOWED_SUBJECTS)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param string|InvoiceTemplate $subject
|
||||
* @param TokenInterface $token
|
||||
* @return bool
|
||||
*/
|
||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
|
||||
{
|
||||
$user = $token->getUser();
|
||||
|
||||
if (!$user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($attribute) {
|
||||
case self::VIEW:
|
||||
return $this->canView($user, $token);
|
||||
case self::CREATE:
|
||||
return $this->canCreate($user, $token);
|
||||
case self::EDIT:
|
||||
return $this->canEdit($user, $token);
|
||||
case self::DELETE:
|
||||
return $this->canDelete($token);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param TokenInterface $token
|
||||
* @return bool
|
||||
*/
|
||||
protected function canView(User $user, TokenInterface $token)
|
||||
{
|
||||
if ($this->canEdit($user, $token)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param TokenInterface $token
|
||||
* @return bool
|
||||
*/
|
||||
protected function canCreate(User $user, TokenInterface $token)
|
||||
{
|
||||
if ($this->canDelete($token)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param TokenInterface $token
|
||||
* @return bool
|
||||
*/
|
||||
protected function canEdit(User $user, TokenInterface $token)
|
||||
{
|
||||
if ($this->canDelete($token)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TokenInterface $token
|
||||
* @return bool
|
||||
*/
|
||||
protected function canDelete(TokenInterface $token)
|
||||
{
|
||||
return $this->isFullyAuthenticated($token) && $this->hasRole('ROLE_TEAMLEAD', $token);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user