2019-08-10 18:06:28 +02:00
< ? php
2020-02-22 18:14:36 +01:00
/**
* This file is part of Part - DB ( https :// github . com / Part - DB / Part - DB - symfony ) .
*
2022-11-29 22:28:53 +01:00
* Copyright ( C ) 2019 - 2022 Jan Böhmer ( https :// github . com / jbtronics )
2020-02-22 18:14:36 +01:00
*
* 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 />.
*/
2020-01-05 15:46:58 +01:00
declare ( strict_types = 1 );
2019-08-10 18:06:28 +02:00
namespace App\Security\Voter ;
2023-08-28 22:00:25 +02:00
use App\Services\UserSystem\VoterHelper ;
2023-06-11 14:55:06 +02:00
use Symfony\Bundle\SecurityBundle\Security ;
use App\Entity\Attachments\AttachmentContainingDBElement ;
2019-08-12 15:47:57 +02:00
use App\Entity\Attachments\Attachment ;
2023-05-27 19:17:27 +02:00
use App\Entity\Attachments\AttachmentTypeAttachment ;
use App\Entity\Attachments\CategoryAttachment ;
use App\Entity\Attachments\CurrencyAttachment ;
use App\Entity\Attachments\FootprintAttachment ;
use App\Entity\Attachments\GroupAttachment ;
use App\Entity\Attachments\ManufacturerAttachment ;
use App\Entity\Attachments\MeasurementUnitAttachment ;
use App\Entity\Attachments\PartAttachment ;
use App\Entity\Attachments\ProjectAttachment ;
2023-09-04 22:57:40 +02:00
use App\Entity\Attachments\StorageLocationAttachment ;
2023-05-27 19:17:27 +02:00
use App\Entity\Attachments\SupplierAttachment ;
use App\Entity\Attachments\UserAttachment ;
use RuntimeException ;
2022-11-02 23:27:44 +01:00
2023-08-28 22:00:25 +02:00
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface ;
use Symfony\Component\Security\Core\Authorization\Voter\Voter ;
2020-01-05 22:49:00 +01:00
use function in_array ;
2019-08-10 18:06:28 +02:00
2024-02-19 00:01:16 +01:00
/**
* @ phpstan - extends Voter < non - empty - string , Attachment | class - string >
*/
2023-08-28 22:00:25 +02:00
final class AttachmentVoter extends Voter
2019-08-10 18:06:28 +02:00
{
2023-08-28 23:06:37 +02:00
private const ALLOWED_ATTRIBUTES = [ 'read' , 'view' , 'edit' , 'delete' , 'create' , 'show_private' , 'show_history' ];
2023-08-28 22:00:25 +02:00
public function __construct ( private readonly Security $security , private readonly VoterHelper $helper )
2022-11-02 23:27:44 +01:00
{
}
2023-08-28 22:00:25 +02:00
protected function voteOnAttribute ( string $attribute , $subject , TokenInterface $token ) : bool
2019-08-10 18:06:28 +02:00
{
2022-11-02 23:27:44 +01:00
2023-05-27 19:17:27 +02:00
//This voter only works for attachments
if ( ! is_a ( $subject , Attachment :: class , true )) {
2022-11-02 23:27:44 +01:00
return false ;
}
2023-05-27 19:17:27 +02:00
if ( $attribute === 'show_private' ) {
2023-08-28 22:00:25 +02:00
return $this -> helper -> isGranted ( $token , 'attachments' , 'show_private' );
2023-05-27 19:17:27 +02:00
}
if ( is_object ( $subject )) {
//If the attachment has no element (which should not happen), we deny access, as we can not determine if the user is allowed to access the associated element
$target_element = $subject -> getElement ();
2023-06-11 14:55:06 +02:00
if ( $target_element instanceof AttachmentContainingDBElement ) {
2023-05-27 19:17:27 +02:00
return $this -> security -> isGranted ( $this -> mapOperation ( $attribute ), $target_element );
}
}
if ( is_string ( $subject )) {
//If we do not have a concrete element (or we just got a string as value), we delegate to the different categories
if ( is_a ( $subject , AttachmentTypeAttachment :: class , true )) {
$param = 'attachment_types' ;
} elseif ( is_a ( $subject , CategoryAttachment :: class , true )) {
$param = 'categories' ;
} elseif ( is_a ( $subject , CurrencyAttachment :: class , true )) {
$param = 'currencies' ;
} elseif ( is_a ( $subject , ProjectAttachment :: class , true )) {
$param = 'projects' ;
} elseif ( is_a ( $subject , FootprintAttachment :: class , true )) {
$param = 'footprints' ;
} elseif ( is_a ( $subject , GroupAttachment :: class , true )) {
$param = 'groups' ;
} elseif ( is_a ( $subject , ManufacturerAttachment :: class , true )) {
$param = 'manufacturers' ;
} elseif ( is_a ( $subject , MeasurementUnitAttachment :: class , true )) {
$param = 'measurement_units' ;
} elseif ( is_a ( $subject , PartAttachment :: class , true )) {
$param = 'parts' ;
2023-09-04 22:57:40 +02:00
} elseif ( is_a ( $subject , StorageLocationAttachment :: class , true )) {
2023-05-27 19:17:27 +02:00
$param = 'storelocations' ;
} elseif ( is_a ( $subject , SupplierAttachment :: class , true )) {
$param = 'suppliers' ;
} elseif ( is_a ( $subject , UserAttachment :: class , true )) {
$param = 'users' ;
} elseif ( $subject === Attachment :: class ) {
//If the subject was deleted, we can not determine the type properly, so we just use the parts permission
$param = 'parts' ;
}
else {
2023-06-18 00:00:58 +02:00
throw new RuntimeException ( 'Encountered unknown Parameter type: ' . $subject );
2023-05-27 19:17:27 +02:00
}
2023-08-28 22:00:25 +02:00
return $this -> helper -> isGranted ( $token , $param , $this -> mapOperation ( $attribute ));
2023-05-27 19:17:27 +02:00
}
2023-05-27 19:29:00 +02:00
return false ;
2023-05-27 19:17:27 +02:00
}
private function mapOperation ( string $attribute ) : string
{
2023-06-11 14:15:46 +02:00
return match ( $attribute ) {
'read' , 'view' => 'read' ,
'edit' , 'create' , 'delete' => 'edit' ,
'show_history' => 'show_history' ,
default => throw new \RuntimeException ( 'Encountered unknown attribute "' . $attribute . '" in AttachmentVoter!' ),
};
2019-08-10 18:06:28 +02:00
}
/**
* Determines if the attribute and subject are supported by this voter .
*
2022-08-14 19:09:07 +02:00
* @ param string $attribute An attribute
2019-11-09 00:47:20 +01:00
* @ param mixed $subject The subject to secure , e . g . an object the user wants to access or any other PHP type
2019-08-10 18:06:28 +02:00
*
* @ return bool True if the attribute and subject are supported , false otherwise
*/
2022-08-14 19:09:07 +02:00
protected function supports ( string $attribute , $subject ) : bool
2019-08-10 18:06:28 +02:00
{
2020-03-07 20:49:52 +01:00
if ( is_a ( $subject , Attachment :: class , true )) {
2022-11-02 23:27:44 +01:00
//These are the allowed attributes
2023-08-28 23:06:37 +02:00
return in_array ( $attribute , self :: ALLOWED_ATTRIBUTES , true );
2019-08-10 18:06:28 +02:00
}
2020-03-07 20:49:52 +01:00
//Allow class name as subject
2019-08-10 18:06:28 +02:00
return false ;
}
2023-08-28 23:06:37 +02:00
public function supportsAttribute ( string $attribute ) : bool
{
return in_array ( $attribute , self :: ALLOWED_ATTRIBUTES , true );
}
public function supportsType ( string $subjectType ) : bool
{
return $subjectType === 'string' || is_a ( $subjectType , Attachment :: class , true );
}
2019-11-09 00:47:20 +01:00
}