mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-07-14 12:24:33 +02:00
Check permissions for time travel and element undo.
This commit is contained in:
parent
254d4e6c69
commit
8a61b465d0
23 changed files with 370 additions and 90 deletions
|
@ -89,9 +89,9 @@ abstract class BaseAdminController extends AbstractController
|
|||
protected $dataTableFactory;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, UserPasswordEncoderInterface $passwordEncoder,
|
||||
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler,
|
||||
EventCommentHelper $commentHelper, HistoryHelper $historyHelper, TimeTravel $timeTravel,
|
||||
DataTableFactory $dataTableFactory)
|
||||
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler,
|
||||
EventCommentHelper $commentHelper, HistoryHelper $historyHelper, TimeTravel $timeTravel,
|
||||
DataTableFactory $dataTableFactory)
|
||||
{
|
||||
if ('' === $this->entity_class || '' === $this->form_class || '' === $this->twig_template || '' === $this->route_base) {
|
||||
throw new InvalidArgumentException('You have to override the $entity_class, $form_class, $route_base and $twig_template value in your subclasss!');
|
||||
|
@ -119,6 +119,8 @@ abstract class BaseAdminController extends AbstractController
|
|||
|
||||
$timeTravel_timestamp = null;
|
||||
if ($timestamp !== null) {
|
||||
$this->denyAccessUnlessGranted('@tools.timeTravel');
|
||||
$this->denyAccessUnlessGranted('show_history', $part);
|
||||
//If the timestamp only contains numbers interpret it as unix timestamp
|
||||
if (ctype_digit($timestamp)) {
|
||||
$timeTravel_timestamp = new \DateTime();
|
||||
|
@ -129,14 +131,22 @@ abstract class BaseAdminController extends AbstractController
|
|||
$this->timeTravel->revertEntityToTimestamp($entity, $timeTravel_timestamp);
|
||||
}
|
||||
|
||||
$table = $this->dataTableFactory->createFromType(LogDataTable::class, [
|
||||
'filter_elements' => $this->historyHelper->getAssociatedElements($entity),
|
||||
'mode' => 'element_history'
|
||||
], ['pageLength' => 10])
|
||||
->handleRequest($request);
|
||||
if ($this->isGranted('show_history', $entity) ) {
|
||||
$table = $this->dataTableFactory->createFromType(
|
||||
LogDataTable::class,
|
||||
[
|
||||
'filter_elements' => $this->historyHelper->getAssociatedElements($entity),
|
||||
'mode' => 'element_history'
|
||||
],
|
||||
['pageLength' => 10]
|
||||
)
|
||||
->handleRequest($request);
|
||||
|
||||
if ($table->isCallback()) {
|
||||
return $table->getResponse();
|
||||
if ($table->isCallback()) {
|
||||
return $table->getResponse();
|
||||
}
|
||||
} else {
|
||||
$table = null;
|
||||
}
|
||||
|
||||
$form = $this->createForm($this->form_class, $entity, [
|
||||
|
|
|
@ -86,13 +86,21 @@ class HomepageController extends AbstractController
|
|||
*/
|
||||
public function homepage(Request $request, GitVersionInfo $versionInfo): Response
|
||||
{
|
||||
$table = $this->dataTable->createFromType(LogDataTable::class, [
|
||||
'mode' => 'last_activity'
|
||||
], ['pageLength' => 10])
|
||||
->handleRequest($request);
|
||||
if ($this->isGranted("@tools.lastActivity")) {
|
||||
$table = $this->dataTable->createFromType(
|
||||
LogDataTable::class,
|
||||
[
|
||||
'mode' => 'last_activity'
|
||||
],
|
||||
['pageLength' => 10]
|
||||
)
|
||||
->handleRequest($request);
|
||||
|
||||
if ($table->isCallback()) {
|
||||
return $table->getResponse();
|
||||
if ($table->isCallback()) {
|
||||
return $table->getResponse();
|
||||
}
|
||||
} else {
|
||||
$table = null;
|
||||
}
|
||||
|
||||
return $this->render('homepage.html.twig', [
|
||||
|
|
|
@ -121,6 +121,8 @@ class LogController extends AbstractController
|
|||
throw new \InvalidArgumentException('No log entry with the given ID is existing!');
|
||||
}
|
||||
|
||||
$this->denyAccessUnlessGranted('revert_element', $log_element->getTargetClass());
|
||||
|
||||
$eventUndoHelper->setMode($mode);
|
||||
$eventUndoHelper->setUndoneEvent($log_element);
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ class PartController extends AbstractController
|
|||
|
||||
$timeTravel_timestamp = null;
|
||||
if ($timestamp !== null) {
|
||||
$this->denyAccessUnlessGranted('@tools.timeTravel');
|
||||
$this->denyAccessUnlessGranted('show_history', $part);
|
||||
//If the timestamp only contains numbers interpret it as unix timestamp
|
||||
if (ctype_digit($timestamp)) {
|
||||
$timeTravel_timestamp = new \DateTime();
|
||||
|
@ -108,14 +110,18 @@ class PartController extends AbstractController
|
|||
$timeTravel->revertEntityToTimestamp($part, $timeTravel_timestamp);
|
||||
}
|
||||
|
||||
$table = $dataTable->createFromType(LogDataTable::class, [
|
||||
'filter_elements' => $historyHelper->getAssociatedElements($part),
|
||||
'mode' => 'element_history'
|
||||
], ['pageLength' => 10])
|
||||
->handleRequest($request);
|
||||
if ($this->isGranted('show_history', $part) ) {
|
||||
$table = $dataTable->createFromType(LogDataTable::class, [
|
||||
'filter_elements' => $historyHelper->getAssociatedElements($part),
|
||||
'mode' => 'element_history'
|
||||
], ['pageLength' => 10])
|
||||
->handleRequest($request);
|
||||
|
||||
if ($table->isCallback()) {
|
||||
return $table->getResponse();
|
||||
if ($table->isCallback()) {
|
||||
return $table->getResponse();
|
||||
}
|
||||
} else {
|
||||
$table = null;
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
|
|
|
@ -42,11 +42,13 @@ class IconLinkColumn extends AbstractColumn
|
|||
'icon' => 'fas fa-fw fa-edit',
|
||||
'title' => null,
|
||||
'href' => null,
|
||||
'disabled' => false,
|
||||
]);
|
||||
|
||||
$resolver->setAllowedTypes('title', ['null', 'string', 'callable']);
|
||||
$resolver->setAllowedTypes('icon', ['null', 'string', 'callable']);
|
||||
$resolver->setAllowedTypes('href', ['null', 'string', 'callable']);
|
||||
$resolver->setAllowedTypes('disabled', ['bool', 'callable']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -56,10 +58,12 @@ class IconLinkColumn extends AbstractColumn
|
|||
$href = $this->getHref($value, $context);
|
||||
$icon = $this->getIcon($value, $context);
|
||||
$title = $this->getTitle($value, $context);
|
||||
$disabled = $this->getDisabled($value, $context);
|
||||
|
||||
if ($href !== null) {
|
||||
return sprintf(
|
||||
'<a class="btn btn-primary btn-sm" href="%s" title="%s"><i class="%s"></i></a>',
|
||||
'<a class="btn btn-primary btn-sm %s" href="%s" title="%s"><i class="%s"></i></a>',
|
||||
$disabled ? 'disabled' : '',
|
||||
$href,
|
||||
$title,
|
||||
$icon
|
||||
|
@ -69,6 +73,18 @@ class IconLinkColumn extends AbstractColumn
|
|||
return "";
|
||||
}
|
||||
|
||||
protected function getDisabled($value, $context): bool
|
||||
{
|
||||
$provider = $this->options['disabled'];
|
||||
if (is_bool($provider)) {
|
||||
return $provider;
|
||||
}
|
||||
if (is_callable($provider)) {
|
||||
return call_user_func($provider, $value, $context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getHref($value, $context): ?string
|
||||
{
|
||||
$provider = $this->options['href'];
|
||||
|
|
|
@ -27,15 +27,18 @@ use App\Entity\LogSystem\ElementCreatedLogEntry;
|
|||
use App\Entity\LogSystem\ElementDeletedLogEntry;
|
||||
use App\Entity\LogSystem\ElementEditedLogEntry;
|
||||
use Omines\DataTablesBundle\Column\AbstractColumn;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class RevertLogColumn extends AbstractColumn
|
||||
{
|
||||
protected $translator;
|
||||
protected $security;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
public function __construct(TranslatorInterface $translator, Security $security)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,17 +68,21 @@ class RevertLogColumn extends AbstractColumn
|
|||
return '';
|
||||
}
|
||||
|
||||
$disabled = !$this->security->isGranted('revert_element', $context->getTargetClass());
|
||||
|
||||
$tmp = '<div class="btn-group btn-group-sm">';
|
||||
$tmp .= sprintf(
|
||||
'<button type="submit" class="btn btn-outline-secondary" name="undo" value="%d"><i class="fas fa-fw %s" title="%s"></i></button>',
|
||||
'<button type="submit" class="btn btn-outline-secondary" name="undo" value="%d" %s><i class="fas fa-fw %s" title="%s"></i></button>',
|
||||
$context->getID(),
|
||||
$disabled ? 'disabled' : '',
|
||||
$icon,
|
||||
$title
|
||||
);
|
||||
|
||||
$tmp .= sprintf(
|
||||
'<button type="submit" class="btn btn-outline-secondary" name="revert" value="%d"><i class="fas fa-fw fa-backward" title="%s"></i></button>',
|
||||
'<button type="submit" class="btn btn-outline-secondary" name="revert" value="%d" %s><i class="fas fa-fw fa-backward" title="%s"></i></button>',
|
||||
$context->getID(),
|
||||
$disabled ? 'disabled' : '',
|
||||
$this->translator->trans('log.undo.revert')
|
||||
);
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ use Omines\DataTablesBundle\DataTableTypeInterface;
|
|||
use Psr\Log\LogLevel;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Symfony\Flex\Options;
|
||||
|
||||
|
@ -76,15 +77,17 @@ class LogDataTable implements DataTableTypeInterface
|
|||
protected $urlGenerator;
|
||||
protected $entityURLGenerator;
|
||||
protected $logRepo;
|
||||
protected $security;
|
||||
|
||||
public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator,
|
||||
UrlGeneratorInterface $urlGenerator, EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager)
|
||||
UrlGeneratorInterface $urlGenerator, EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager, Security $security)
|
||||
{
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->logRepo = $entityManager->getRepository(AbstractLogEntry::class);
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $optionsResolver)
|
||||
|
@ -235,7 +238,13 @@ class LogDataTable implements DataTableTypeInterface
|
|||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
'disabled' => function ($value, AbstractLogEntry $context) {
|
||||
return
|
||||
!$this->security->isGranted('@tools.timetravel')
|
||||
|| !$this->security->isGranted('show_history', $context->getTargetClass());
|
||||
}
|
||||
|
||||
]);
|
||||
|
||||
$dataTable->add('actionRevert', RevertLogColumn::class, [
|
||||
|
|
|
@ -481,7 +481,7 @@ class PermissionsEmbed
|
|||
*/
|
||||
final protected static function readBitPair($data, int $n): int
|
||||
{
|
||||
Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.');
|
||||
//Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.');
|
||||
if (0 !== $n % 2) {
|
||||
throw new InvalidArgumentException('$n must be dividable by 2, because we address bit pairs here!');
|
||||
}
|
||||
|
@ -501,7 +501,7 @@ class PermissionsEmbed
|
|||
*/
|
||||
final protected static function writeBitPair(int $data, int $n, int $new): int
|
||||
{
|
||||
Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.');
|
||||
//Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.');
|
||||
Assert::lessThanEq($new, 3, '$new must be smaller than 3, because a bit pair is written! Got %s.');
|
||||
Assert::greaterThanEq($new, 0, '$new must not be negative, because a bit pair is written! Got %s.');
|
||||
|
||||
|
|
|
@ -58,11 +58,7 @@ class AttachmentVoter extends ExtendedVoter
|
|||
*/
|
||||
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||
{
|
||||
if ($subject instanceof Attachment) {
|
||||
return $this->resolver->inherit($user, 'parts_attachments', $attribute) ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return $this->resolver->inherit($user, 'parts_attachments', $attribute) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,10 +71,11 @@ class AttachmentVoter extends ExtendedVoter
|
|||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if ($subject instanceof Attachment) {
|
||||
if (is_a($subject, Attachment::class, true)) {
|
||||
return in_array($attribute, $this->resolver->listOperationsForPermission('parts_attachments'), false);
|
||||
}
|
||||
|
||||
//Allow class name as subject
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,11 +57,7 @@ class GroupVoter extends ExtendedVoter
|
|||
*/
|
||||
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||
{
|
||||
if ($subject instanceof Group) {
|
||||
return $this->resolver->inherit($user, 'groups', $attribute) ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return $this->resolver->inherit($user, 'groups', $attribute) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,7 +70,7 @@ class GroupVoter extends ExtendedVoter
|
|||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if ($subject instanceof Group) {
|
||||
if (is_a($subject, Group::class, true)) {
|
||||
return $this->resolver->isValidOperation('groups', $attribute);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,25 +51,21 @@ class LogEntryVoter extends ExtendedVoter
|
|||
|
||||
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||
{
|
||||
if ($subject instanceof AbstractLogEntry) {
|
||||
if ('delete' === $attribute) {
|
||||
return $this->resolver->inherit($user, 'system', 'delete_logs') ?? false;
|
||||
}
|
||||
|
||||
if ('read' === $attribute) {
|
||||
//Allow read of the users own log entries
|
||||
if (
|
||||
$subject->getUser() === $user
|
||||
&& $this->resolver->inherit($user, 'self', 'show_logs')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->resolver->inherit($user, 'system', 'show_logs') ?? false;
|
||||
}
|
||||
if ('delete' === $attribute) {
|
||||
return $this->resolver->inherit($user, 'system', 'delete_logs') ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if ('read' === $attribute) {
|
||||
//Allow read of the users own log entries
|
||||
if (
|
||||
$subject->getUser() === $user
|
||||
&& $this->resolver->inherit($user, 'self', 'show_logs')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->resolver->inherit($user, 'system', 'show_logs') ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function supports($attribute, $subject)
|
||||
|
|
57
src/Security/Voter/OrderdetailVoter.php
Normal file
57
src/Security/Voter/OrderdetailVoter.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Security\Voter;
|
||||
|
||||
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Entity\PriceInformations\Orderdetail;
|
||||
use App\Entity\UserSystem\User;
|
||||
|
||||
class OrderdetailVoter extends ExtendedVoter
|
||||
{
|
||||
/** @var string[] When this permsission are encountered, they are checked on part */
|
||||
protected const PART_PERMS = ['show_history', 'revert_element'];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||
{
|
||||
if (in_array($attribute, self::PART_PERMS, true)) {
|
||||
return $this->resolver->inherit($user, 'parts', $attribute) ?? false;
|
||||
}
|
||||
|
||||
return $this->resolver->inherit($user, 'parts_orderdetails', $attribute) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if (is_a($subject, Orderdetail::class, true)) {
|
||||
return in_array($attribute, array_merge(
|
||||
self::PART_PERMS,
|
||||
$this->resolver->listOperationsForPermission('parts_orderdetails')
|
||||
), true);
|
||||
}
|
||||
}
|
||||
}
|
56
src/Security/Voter/PartLotVoter.php
Normal file
56
src/Security/Voter/PartLotVoter.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Security\Voter;
|
||||
|
||||
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Entity\UserSystem\User;
|
||||
|
||||
class PartLotVoter extends ExtendedVoter
|
||||
{
|
||||
/** @var string[] When this permsission are encountered, they are checked on part */
|
||||
protected const PART_PERMS = ['show_history', 'revert_element'];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||
{
|
||||
if (in_array($attribute, self::PART_PERMS, true)) {
|
||||
return $this->resolver->inherit($user, 'parts', $attribute) ?? false;
|
||||
}
|
||||
|
||||
return $this->resolver->inherit($user, 'parts_lots', $attribute) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if (is_a($subject, PartLot::class, true)) {
|
||||
return in_array($attribute, array_merge(
|
||||
self::PART_PERMS,
|
||||
$this->resolver->listOperationsForPermission('parts_lots')
|
||||
), true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,11 +57,7 @@ class PartVoter extends ExtendedVoter
|
|||
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
// replace with your own logic
|
||||
// https://symfony.com/doc/current/security/voters.html
|
||||
//return ($subject instanceof Part || in_array($subject, ['PERM_parts', 'PERM_parts_name']));
|
||||
|
||||
if ($subject instanceof Part) {
|
||||
if (is_a($subject, Part::class, true)) {
|
||||
//Check if a sub permission should be checked -> $attribute has format name.edit
|
||||
if (false !== strpos($attribute, '.')) {
|
||||
[$perm, $op] = explode('.', $attribute);
|
||||
|
@ -72,24 +68,21 @@ class PartVoter extends ExtendedVoter
|
|||
return $this->resolver->isValidOperation('parts', $attribute);
|
||||
}
|
||||
|
||||
//Allow class name as subject
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||
{
|
||||
if ($subject instanceof Part) {
|
||||
//Check for sub permissions
|
||||
if (false !== strpos($attribute, '.')) {
|
||||
[$perm, $op] = explode('.', $attribute);
|
||||
//Check for sub permissions
|
||||
if (false !== strpos($attribute, '.')) {
|
||||
[$perm, $op] = explode('.', $attribute);
|
||||
|
||||
return $this->resolver->inherit($user, 'parts_'.$perm, $op) ?? false;
|
||||
}
|
||||
|
||||
//Null concealing operator means, that no
|
||||
return $this->resolver->inherit($user, 'parts', $attribute) ?? false;
|
||||
return $this->resolver->inherit($user, 'parts_'.$perm, $op) ?? false;
|
||||
}
|
||||
|
||||
//Deny access by default.
|
||||
return false;
|
||||
//Null concealing operator means, that no
|
||||
return $this->resolver->inherit($user, 'parts', $attribute) ?? false;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
57
src/Security/Voter/PricedetailVoter.php
Normal file
57
src/Security/Voter/PricedetailVoter.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Security\Voter;
|
||||
|
||||
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Entity\PriceInformations\Pricedetail;
|
||||
use App\Entity\UserSystem\User;
|
||||
|
||||
class PricedetailVoter extends ExtendedVoter
|
||||
{
|
||||
/** @var string[] When this permsission are encountered, they are checked on part */
|
||||
protected const PART_PERMS = ['show_history', 'revert_element'];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||
{
|
||||
if (in_array($attribute, self::PART_PERMS, true)) {
|
||||
return $this->resolver->inherit($user, 'parts', $attribute) ?? false;
|
||||
}
|
||||
|
||||
return $this->resolver->inherit($user, 'parts_prices', $attribute) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if (is_a($subject, Pricedetail::class, true)) {
|
||||
return in_array($attribute, array_merge(
|
||||
self::PART_PERMS,
|
||||
$this->resolver->listOperationsForPermission('parts_prices')
|
||||
), true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,11 +43,13 @@ declare(strict_types=1);
|
|||
namespace App\Security\Voter;
|
||||
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\Base\AbstractStructuralDBElement;
|
||||
use App\Entity\Devices\Device;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Footprint;
|
||||
use App\Entity\Parts\Manufacturer;
|
||||
use App\Entity\Parts\MeasurementUnit;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\Storelocation;
|
||||
use App\Entity\Parts\Supplier;
|
||||
use App\Entity\PriceInformations\Currency;
|
||||
|
@ -67,24 +69,29 @@ class StructureVoter extends ExtendedVoter
|
|||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if (is_object($subject)) {
|
||||
if (is_object($subject) || is_string($subject)) {
|
||||
$permission_name = $this->instanceToPermissionName($subject);
|
||||
//If permission name is null, then the subject is not supported
|
||||
return (null !== $permission_name) && $this->resolver->isValidOperation($permission_name, $attribute);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a instance type to the permission name.
|
||||
*
|
||||
* @param mixed $subject The subject for which the permission name should be generated
|
||||
* @param object|string $subject The subject for which the permission name should be generated
|
||||
*
|
||||
* @return string|null the name of the permission for the subject's type or null, if the subject is not supported
|
||||
*/
|
||||
protected function instanceToPermissionName($subject): ?string
|
||||
{
|
||||
$class_name = get_class($subject);
|
||||
if (!is_string($subject)) {
|
||||
$class_name = get_class($subject);
|
||||
} else {
|
||||
$class_name = $subject;
|
||||
}
|
||||
switch ($class_name) {
|
||||
case AttachmentType::class:
|
||||
return 'attachment_types';
|
||||
|
|
|
@ -57,11 +57,11 @@ class UserVoter extends ExtendedVoter
|
|||
*/
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
if ($subject instanceof User) {
|
||||
if (is_a($subject, User::class, true)) {
|
||||
return in_array($attribute, array_merge(
|
||||
$this->resolver->listOperationsForPermission('users'),
|
||||
$this->resolver->listOperationsForPermission('self')),
|
||||
false
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -89,10 +89,11 @@ class UserVoter extends ExtendedVoter
|
|||
return $tmp;
|
||||
}
|
||||
}
|
||||
//Else just check users permission:
|
||||
if ($this->resolver->isValidOperation('users', $attribute)) {
|
||||
return $this->resolver->inherit($user, 'users', $attribute) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
//Else just check users permission:
|
||||
if ($this->resolver->isValidOperation('users', $attribute)) {
|
||||
return $this->resolver->inherit($user, 'users', $attribute) ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue