refs #436. Improvements

pull/7/head
Manuel Aranda Rosales 2024-07-12 13:11:38 +02:00
parent f9bf9b6190
commit e4e9e3c07f
11 changed files with 138 additions and 49 deletions

View File

@ -17,6 +17,9 @@ api_platform:
mapping:
paths: ['%kernel.project_dir%/config/api_platform', '%kernel.project_dir%/src/Dto']
use_symfony_listeners: true
collection:
pagination:
items_per_page_parameter_name: 'itemsPerPage'
defaults:
pagination_client_items_per_page: true
denormalization_context:

View File

@ -1,3 +1,6 @@
imports:
- { resource: 'services/api_platform.yaml' }
parameters:
services:

View File

@ -4,109 +4,93 @@ services:
arguments:
$properties: { 'id': ~, 'name': ~, 'serialNumber': ~ }
$orderParameterName: 'order'
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.client.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact' } ]
tags:
- [ 'api_platform.filter' ]
arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact', organizationalUnit.id: 'exact' } ]
tags: [ 'api_platform.filter' ]
api_platform.filter.hardware.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'name': ~ }
$orderParameterName: 'order'
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.hardware.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial' } ]
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.menu.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'name': ~, 'title': ~ }
$orderParameterName: 'order'
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.menu.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'exact', 'title': 'exact' } ]
tags:
- [ 'api_platform.filter' ]
tags: [ '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' ]
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' ]
arguments: [ { id: 'exact', name: 'partial', type: 'exact', parent.id: 'exact'} ]
tags: [ 'api_platform.filter' ]
api_platform.filter.partition.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'usage': ~ }
$orderParameterName: 'order'
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.partition.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'usage': 'exact', 'diskNumber': 'exact' } ]
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.user.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'username': ~ }
$orderParameterName: 'order'
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.user.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'username': 'partial' } ]
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.user.boolean:
parent: 'api_platform.doctrine.orm.boolean_filter'
arguments: [ { 'enabled': ~ } ]
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.user_group.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'name': ~ }
$orderParameterName: 'order'
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.user_group.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial' } ]
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]
api_platform.filter.user_group.boolean:
parent: 'api_platform.doctrine.orm.boolean_filter'
arguments: [ { 'enabled': ~ } ]
tags:
- [ 'api_platform.filter' ]
tags: [ 'api_platform.filter' ]

View File

@ -87,9 +87,10 @@ class MigrateHardwareAndHardwareProfileCommand extends Command
$migrationId = $hardware['hardwares.grupoid'] === 0 ? $hardware['hardwares.idcentro'] : $hardware['hardwares.grupoid'];
$organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]);
/*
if ($organizationalUnit){
$hardwareEntity->setOrganizationalUnit($organizationalUnit);
}
}*/
$this->entityManager->persist($hardwareEntity);
}
@ -142,8 +143,8 @@ class MigrateHardwareAndHardwareProfileCommand extends Command
if ($hardwareProfileEntity && $hardwareEntity){
$hardwareProfileEntity->addHardwareCollection($hardwareEntity);
$this->entityManager->persist($hardwareProfileEntity);
}
$this->entityManager->persist($hardwareProfileEntity);
}

View File

@ -36,13 +36,26 @@ readonly class UserAllowedOrganizationalUnitExtension implements QueryCollection
if (OrganizationalUnit::class !== $resourceClass || null === $user || in_array('ROLE_SUPER_ADMIN', $user->getRoles())) {
return;
}
$organizationalUnitIds = [];
foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) {
$organizationalUnitIds[] = $allowedOrganizationalUnit->getId();
$this->addOrganizationalUnitAndChildrenIds($allowedOrganizationalUnit, $organizationalUnitIds);
}
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder->andWhere(sprintf('%s.id in (:ou)', $rootAlias));
$queryBuilder->setParameter('ou', $organizationalUnitIds);
}
private function addOrganizationalUnitAndChildrenIds(OrganizationalUnit $organizationalUnit, array &$organizationalUnitIds): void
{
if (!in_array($organizationalUnit->getId(), $organizationalUnitIds)) {
$organizationalUnitIds[] = $organizationalUnit->getId();
}
foreach ($organizationalUnit->getOrganizationalUnits() as $child) {
$this->addOrganizationalUnitAndChildrenIds($child, $organizationalUnitIds);
}
}
}

View File

@ -3,6 +3,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Dto\Output\UserGroupOutput;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
@ -17,7 +18,7 @@ final class UserInput
public ?string $username = null;
/**
* @var OrganizationalUnit[]
* @var OrganizationalUnitOutput[]
*/
#[Groups('user:write')]
#[ApiProperty(readableLink: false, writableLink: false)]
@ -33,7 +34,7 @@ final class UserInput
public ?bool $enabled = true;
/**
* @var UserGroup[]
* @var UserGroupOutput[]
*/
#[Groups('user:write')]
#[ApiProperty(readableLink: false, writableLink: false)]
@ -62,8 +63,18 @@ final class UserInput
$this->username = $user->getUsername();
$this->enabled= $user->isEnabled();
$this->userGroups = $user->getUserGroups()->toArray();
$this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray();
if ($user->getUserGroups()) {
foreach ($user->getUserGroups() as $userGroup) {
$this->userGroups[] = new UserGroupOutput($userGroup);
}
}
if ($user->getAllowedOrganizationalUnits()) {
foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) {
$this->allowedOrganizationalUnits[] = new OrganizationalUnitOutput($allowedOrganizationalUnit);
}
}
}
public function createOrUpdateEntity(?User $user = null): User

View File

@ -19,14 +19,20 @@ final class ClientOutput extends AbstractOutput
#[Groups(['client:read', 'organizational-unit:read'])]
public string $type = self::TYPE;
#[Groups(['client:read', 'organizational-unit:read'])]
public ?string $ip = '';
#[Groups(['client:read', 'organizational-unit:read'])]
public ?string $mac = '';
#[Groups(['client:read', 'organizational-unit:read'])]
public ?string $serialNumber = '';
#[Groups(['client:read'])]
public ?string $netiface = '';
#[Groups(['client:read', 'organizational-unit:read'])]
#[ApiProperty(readableLink: true )]
#[Groups(['client:read'])]
#[ApiProperty(readableLink: true)]
public ?OrganizationalUnitOutput $organizationalUnit = null;
#[Groups(['client:read'])]
@ -51,6 +57,8 @@ final class ClientOutput extends AbstractOutput
$this->name = $client->getName();
$this->serialNumber = $client->getSerialNumber();
$this->mac = $client->getMac();
$this->ip = $client->getIp();
$this->netiface = $client->getNetiface();
if ($client->getOrganizationalUnit()) {

View File

@ -42,13 +42,19 @@ final class OrganizationalUnitOutput extends AbstractOutput
#[ApiProperty(readableLink: true)]
public ?NetworkSettingsOutput $networkSettings = null;
#[Groups(['organizational-unit:read'])]
public array $children = [];
#[Groups(['organizational-unit:read'])]
public array $clients = [];
#[Groups(['organizational-unit:read'])]
public \DateTime $createdAt;
#[Groups(['organizational-unit:read'])]
public ?string $createdBy = null;
public function __construct(OrganizationalUnit $organizationalUnit)
public function __construct(OrganizationalUnit $organizationalUnit, array $context = [])
{
parent::__construct($organizationalUnit);
@ -65,6 +71,18 @@ final class OrganizationalUnitOutput extends AbstractOutput
$this->parent = new self($organizationalUnit->getParent());
}
if (isset($context['groups']) && in_array('organizational-unit:read', $context['groups'])) {
$this->children = $organizationalUnit->getOrganizationalUnits()->map(
fn(OrganizationalUnit $organizationalUnit) => new self($organizationalUnit, $context)
)->toArray();
}
if (isset($context['groups']) && in_array('organizational-unit:read', $context['groups'])) {
$this->clients = $organizationalUnit->getClients()->map(
fn(Client $client) => new ClientOutput($client)
)->toArray();
}
$this->path = $organizationalUnit->getPath();
$this->createdAt = $organizationalUnit->getCreatedAt();
$this->createdBy = $organizationalUnit->getCreatedBy();

View File

@ -21,9 +21,9 @@ readonly class OrganizationalUnitChangeParentHandler
return throw new \InvalidArgumentException('The organizational unit has no parent.');
}
foreach ($organizationalUnit->getOrganizationalUnits() as $child) {
$child->setParent($parent);
$this->organizationalUnitRepository->save($child);
foreach ($organizationalUnit->getClients() as $client) {
$client->setOrganizationalUnit($parent);
$this->organizationalUnitRepository->save($client);
}
$this->organizationalUnitRepository->delete($organizationalUnit);

View File

@ -0,0 +1,48 @@
<?php
namespace App\Security\Voter;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\Client;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
use App\Model\UserGroupPermissions;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;
class ClientVoter extends Voter
{
public const string VIEW = 'CLIENT_VIEW';
protected function supports(string $attribute, mixed $subject): bool
{
return $attribute === self::VIEW
&& $subject instanceof Client;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
/** @var User $user */
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return false;
}
if (in_array(UserGroupPermissions::ROLE_SUPER_ADMIN, $user->getRoles())) {
return true;
}
if ($attribute === 'CLIENT_VIEW') {
foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) {
if ($allowedOrganizationalUnit->getId() === $subject->getOrganizationalUnit()->getEntity()->getId()) {
return true;
}
}
}
return false;
}
}

View File

@ -42,7 +42,7 @@ readonly class OrganizationalUnitProvider implements ProviderInterface
$items = new \ArrayObject();
foreach ($paginator->getIterator() as $item){
$items[] = new OrganizationalUnitOutput($item);
$items[] = new OrganizationalUnitOutput($item, $context);
}
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());
@ -56,7 +56,7 @@ readonly class OrganizationalUnitProvider implements ProviderInterface
throw new NotFoundHttpException('Organizational unit not found');
}
return new OrganizationalUnitOutput($item);
return new OrganizationalUnitOutput($item, $context);
}
public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null