refs #421. Some improvements
parent
14c9f44c63
commit
5d1b553c0b
|
@ -11,8 +11,8 @@ resources:
|
||||||
ApiPlatform\Metadata\GetCollection:
|
ApiPlatform\Metadata\GetCollection:
|
||||||
provider: App\State\Provider\OperativeSystemProvider
|
provider: App\State\Provider\OperativeSystemProvider
|
||||||
filters:
|
filters:
|
||||||
- 'api_platform.filter.operative-system.order'
|
- 'api_platform.filter.operative_system.order'
|
||||||
- 'api_platform.filter.operative-system.search'
|
- 'api_platform.filter.operative_system.search'
|
||||||
|
|
||||||
ApiPlatform\Metadata\Get:
|
ApiPlatform\Metadata\Get:
|
||||||
provider: App\State\Provider\OperativeSystemProvider
|
provider: App\State\Provider\OperativeSystemProvider
|
||||||
|
|
|
@ -7,13 +7,16 @@ resources:
|
||||||
groups: ['default', 'organizational-unit:read']
|
groups: ['default', 'organizational-unit:read']
|
||||||
denormalization_context:
|
denormalization_context:
|
||||||
groups: ['organizational-unit:write']
|
groups: ['organizational-unit:write']
|
||||||
validation_context:
|
|
||||||
groups: ['organizational-unit:write']
|
|
||||||
operations:
|
operations:
|
||||||
ApiPlatform\Metadata\GetCollection:
|
ApiPlatform\Metadata\GetCollection:
|
||||||
provider: App\State\Provider\OrganizationalUnitProvider
|
provider: App\State\Provider\OrganizationalUnitProvider
|
||||||
|
filters:
|
||||||
|
- 'api_platform.filter.organizational_unit.order'
|
||||||
|
- 'api_platform.filter.organizational_unit.search'
|
||||||
ApiPlatform\Metadata\Get:
|
ApiPlatform\Metadata\Get:
|
||||||
|
security: 'is_granted("ORGANIZATIONAL_UNIT_VIEW", object)'
|
||||||
provider: App\State\Provider\OrganizationalUnitProvider
|
provider: App\State\Provider\OrganizationalUnitProvider
|
||||||
|
securityMessage: 'Sorry, but you are not allowed to access this resource.'
|
||||||
ApiPlatform\Metadata\Put:
|
ApiPlatform\Metadata\Put:
|
||||||
provider: App\State\Provider\OrganizationalUnitProvider
|
provider: App\State\Provider\OrganizationalUnitProvider
|
||||||
ApiPlatform\Metadata\Patch:
|
ApiPlatform\Metadata\Patch:
|
||||||
|
|
|
@ -4,7 +4,14 @@ api_platform:
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
path_segment_name_generator: 'api_platform.path_segment_name_generator.dash'
|
path_segment_name_generator: 'api_platform.path_segment_name_generator.dash'
|
||||||
formats:
|
formats:
|
||||||
jsonld: ['application/ld+json', 'application/json']
|
jsonld: [ 'application/ld+json' ]
|
||||||
|
jsonhal: [ 'application/hal+json' ]
|
||||||
|
jsonapi: [ 'application/vnd.api+json' ]
|
||||||
|
json: [ 'application/json' ]
|
||||||
|
xml: [ 'application/xml', 'text/xml' ]
|
||||||
|
yaml: [ 'application/x-yaml' ]
|
||||||
|
csv: [ 'text/csv' ]
|
||||||
|
html: [ 'text/html' ]
|
||||||
patch_formats:
|
patch_formats:
|
||||||
jsonld: ['application/ld+json', 'application/json']
|
jsonld: ['application/ld+json', 'application/json']
|
||||||
mapping:
|
mapping:
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
# This file is the entry point to configure your own services.
|
|
||||||
# Files in the packages/ subdirectory configure your dependencies.
|
|
||||||
|
|
||||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
|
||||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
|
||||||
parameters:
|
parameters:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
@ -11,8 +6,6 @@ services:
|
||||||
autowire: true # Automatically injects dependencies in your services.
|
autowire: true # Automatically injects dependencies in your services.
|
||||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||||
|
|
||||||
# makes classes in src/ available to be used as services
|
|
||||||
# this creates a service per class whose id is the fully-qualified class name
|
|
||||||
App\:
|
App\:
|
||||||
resource: '../src/'
|
resource: '../src/'
|
||||||
exclude:
|
exclude:
|
||||||
|
@ -20,6 +13,11 @@ services:
|
||||||
- '../src/Entity/'
|
- '../src/Entity/'
|
||||||
- '../src/Kernel.php'
|
- '../src/Kernel.php'
|
||||||
|
|
||||||
|
App\Doctrine\UserAllowedOrganizationalUnitExtension:
|
||||||
|
tags:
|
||||||
|
- { name: api_platform.doctrine.orm.query_extension.collection }
|
||||||
|
- { name: api_platform.doctrine.orm.query_extension.item }
|
||||||
|
|
||||||
App\OpenApi\OpenApiFactory:
|
App\OpenApi\OpenApiFactory:
|
||||||
decorates: 'api_platform.openapi.factory'
|
decorates: 'api_platform.openapi.factory'
|
||||||
arguments: [ '@App\OpenApi\OpenApiFactory.inner' ]
|
arguments: [ '@App\OpenApi\OpenApiFactory.inner' ]
|
||||||
|
|
|
@ -41,6 +41,19 @@ services:
|
||||||
tags:
|
tags:
|
||||||
- [ 'api_platform.filter' ]
|
- [ 'api_platform.filter' ]
|
||||||
|
|
||||||
|
api_platform.filter.organizational_unit.order:
|
||||||
|
parent: 'api_platform.doctrine.orm.order_filter'
|
||||||
|
arguments:
|
||||||
|
$properties: { 'id': ~, 'name': ~, 'type': ~ }
|
||||||
|
$orderParameterName: 'order'
|
||||||
|
tags:
|
||||||
|
- [ 'api_platform.filter' ]
|
||||||
|
|
||||||
|
api_platform.filter.organizational_unit.search:
|
||||||
|
parent: 'api_platform.doctrine.orm.search_filter'
|
||||||
|
arguments: [ { 'id': 'exact', 'name': 'exact', 'type': 'exact' } ]
|
||||||
|
tags:
|
||||||
|
- [ 'api_platform.filter' ]
|
||||||
|
|
||||||
api_platform.filter.partition.order:
|
api_platform.filter.partition.order:
|
||||||
parent: 'api_platform.doctrine.orm.order_filter'
|
parent: 'api_platform.doctrine.orm.order_filter'
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20240620095914 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921');
|
||||||
|
$this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id) ON DELETE SET NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921');
|
||||||
|
$this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id)');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20240620100039 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921');
|
||||||
|
$this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id) ON DELETE CASCADE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921');
|
||||||
|
$this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id) ON DELETE SET NULL');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Doctrine;
|
||||||
|
|
||||||
|
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
|
||||||
|
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
|
||||||
|
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
|
||||||
|
use ApiPlatform\Metadata\Operation;
|
||||||
|
use App\Entity\OrganizationalUnit;
|
||||||
|
use App\Entity\User;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
|
||||||
|
readonly class UserAllowedOrganizationalUnitExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private Security $security,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void
|
||||||
|
{
|
||||||
|
$this->addWhere($queryBuilder, $resourceClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, Operation $operation = null, array $context = []): void
|
||||||
|
{
|
||||||
|
$this->addWhere($queryBuilder, $resourceClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
|
||||||
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
if (OrganizationalUnit::class !== $resourceClass || null === $user || in_array('ROLE_SUPER_ADMIN', $user->getRoles())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$organizationalUnitIds = [];
|
||||||
|
foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) {
|
||||||
|
$organizationalUnitIds[] = $allowedOrganizationalUnit->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$rootAlias = $queryBuilder->getRootAliases()[0];
|
||||||
|
$queryBuilder->andWhere(sprintf('%s.id in (:ou)', $rootAlias));
|
||||||
|
$queryBuilder->setParameter('ou', $organizationalUnitIds);
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ class Partition extends AbstractEntity
|
||||||
private ?string $filesystem = null;
|
private ?string $filesystem = null;
|
||||||
|
|
||||||
#[ORM\ManyToOne(inversedBy: 'partitions')]
|
#[ORM\ManyToOne(inversedBy: 'partitions')]
|
||||||
|
#[ORM\JoinColumn( onDelete: 'CASCADE')]
|
||||||
private ?Client $client = null;
|
private ?Client $client = null;
|
||||||
|
|
||||||
#[ORM\Column]
|
#[ORM\Column]
|
||||||
|
|
|
@ -17,8 +17,8 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate
|
||||||
{
|
{
|
||||||
use ToggleableTrait;
|
use ToggleableTrait;
|
||||||
|
|
||||||
const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
|
const string ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
|
||||||
const ROLE_USER = 'ROLE_USER';
|
const string ROLE_USER = 'ROLE_USER';
|
||||||
|
|
||||||
#[ORM\Column(length: 180)]
|
#[ORM\Column(length: 180)]
|
||||||
private ?string $username = null;
|
private ?string $username = null;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Security\Voter;
|
||||||
|
|
||||||
|
use App\Dto\Output\OrganizationalUnitOutput;
|
||||||
|
use App\Entity\OrganizationalUnit;
|
||||||
|
use App\Entity\User;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
|
||||||
|
class OrganizationalUnitVoter extends Voter
|
||||||
|
{
|
||||||
|
public const string VIEW = 'ORGANIZATIONAL_UNIT_VIEW';
|
||||||
|
|
||||||
|
protected function supports(string $attribute, mixed $subject): bool
|
||||||
|
{
|
||||||
|
return $attribute === self::VIEW
|
||||||
|
&& $subject instanceof OrganizationalUnitOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
|
||||||
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $token->getUser();
|
||||||
|
|
||||||
|
// if the user is anonymous, do not grant access
|
||||||
|
if (!$user instanceof UserInterface) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($attribute === 'ORGANIZATIONAL_UNIT_VIEW' ) {
|
||||||
|
foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) {
|
||||||
|
if ($allowedOrganizationalUnit->getId() === $subject->getEntity()->getId()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue