Merge pull request 'New version 1.1.0' (#68) from develop into main
Reviewed-on: #68pull/69/head^2 1.1.0
						commit
						7047ed7595
					
				| 
						 | 
				
			
			@ -1,4 +1,13 @@
 | 
			
		|||
# Changelog
 | 
			
		||||
## [1.1.0] - 2025-10-16
 | 
			
		||||
### Added
 | 
			
		||||
- Se ha añadido un nuevo campo en el cliente, para guardar la resolucion del menu browser.
 | 
			
		||||
- Se ha añadido un validador en el asistente "deploy", el cual comprueba que el tamaño de la partition destino de todos los clientes sea igual.
 | 
			
		||||
 | 
			
		||||
### Fixed
 | 
			
		||||
- Se ha corregido un bug a la hora de mover clientes cuando el aula destino no tiene plantilla PXE asignada.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
## [1.0.0] - 2025-10-09
 | 
			
		||||
### Added 
 | 
			
		||||
- Se ha añadido nuevo readme
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
<?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 Version20251015080216 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 client ADD resolution VARCHAR(255) DEFAULT NULL');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        // this down() migration is auto-generated, please modify it to your needs
 | 
			
		||||
        $this->addSql('ALTER TABLE client DROP resolution');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -25,7 +25,7 @@ class LoadDefaultMenuCommand extends Command
 | 
			
		|||
    {
 | 
			
		||||
        $menu = new Menu();
 | 
			
		||||
        $menu->setName('Default menu');
 | 
			
		||||
        $menu->setResolution('1920x1080');
 | 
			
		||||
        $menu->setResolution('791');
 | 
			
		||||
        $menu->setComments('Default menu comments');
 | 
			
		||||
        $menu->setPublicUrl('main');
 | 
			
		||||
        $menu->setIsDefault(true);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,18 +4,16 @@ namespace App\Controller;
 | 
			
		|||
 | 
			
		||||
use App\Controller\OgBoot\PxeBootFile\PostAction;
 | 
			
		||||
use App\Dto\Input\ChangeOrganizationalUnitInput;
 | 
			
		||||
use App\Dto\Output\ClientOutput;
 | 
			
		||||
use App\Entity\Client;
 | 
			
		||||
use App\Repository\ClientRepository;
 | 
			
		||||
use Doctrine\ORM\EntityManagerInterface;
 | 
			
		||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 | 
			
		||||
use Symfony\Component\HttpFoundation\JsonResponse;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 | 
			
		||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
 | 
			
		||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
 | 
			
		||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
 | 
			
		||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 | 
			
		||||
 | 
			
		||||
class ChangeOrganizationalUnitAction extends AbstractController
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -43,10 +41,10 @@ class ChangeOrganizationalUnitAction extends AbstractController
 | 
			
		|||
 | 
			
		||||
            $this->entityManager->persist($clientEntity);
 | 
			
		||||
 | 
			
		||||
            $template = $clientEntity->getTemplate() ?? $clientEntity->getOrganizationalUnit()->getNetworkSettings()?->getTemplate();
 | 
			
		||||
            $template = $clientEntity->getTemplate() ?? $clientEntity->getOrganizationalUnit()->getNetworkSettings()?->getPxeTemplate();
 | 
			
		||||
 | 
			
		||||
            if (!$template) {
 | 
			
		||||
                throw new BadRequestHttpException('No template found for client');
 | 
			
		||||
                throw new BadRequestHttpException('No se han encontrado plantillas PXE asociadas al cliente o a la unidad organizativa.');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->postAction->__invoke($clientEntity, $template);
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +52,6 @@ class ChangeOrganizationalUnitAction extends AbstractController
 | 
			
		|||
 | 
			
		||||
        $this->entityManager->flush();
 | 
			
		||||
 | 
			
		||||
        return new JsonResponse( data: 'Clients updated successfully', status: Response::HTTP_OK);
 | 
			
		||||
        return new JsonResponse( data: 'Clientes actualizados correctamente', status: Response::HTTP_OK);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ class PostAction extends AbstractOgBootController
 | 
			
		|||
                'ogntp' => $client->getOrganizationalUnit()->getNetworkSettings()?->getNtp(),
 | 
			
		||||
                'ogdns' => $client->getOrganizationalUnit()->getNetworkSettings()?->getDns(),
 | 
			
		||||
                'ogProxy' => $client->getOrganizationalUnit()->getNetworkSettings()?->getProxy(),
 | 
			
		||||
                'resolution' => '791'
 | 
			
		||||
                'resolution' => $client->getResolution() ?? '791'
 | 
			
		||||
            ]
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,16 +101,22 @@ final class ClientInput
 | 
			
		|||
 | 
			
		||||
    #[Groups(['client:write'])]
 | 
			
		||||
    #[ApiProperty(
 | 
			
		||||
        description: 'descriptions.client.validation'
 | 
			
		||||
        description: 'El repositorio del cliente'
 | 
			
		||||
    )]
 | 
			
		||||
    public ?ImageRepositoryOutput $repository = null;
 | 
			
		||||
 | 
			
		||||
    #[Groups(['client:write'])]
 | 
			
		||||
    #[ApiProperty(
 | 
			
		||||
        description: 'descriptions.client.validation'
 | 
			
		||||
        description: 'El mantenimiento del cliente'
 | 
			
		||||
    )]
 | 
			
		||||
    public ?bool $maintenance = false;
 | 
			
		||||
 | 
			
		||||
    #[Groups(['client:write'])]
 | 
			
		||||
    #[ApiProperty(
 | 
			
		||||
        description: 'La resolución del cliente'
 | 
			
		||||
    )]
 | 
			
		||||
    public ?string $resolution = null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function __construct(?Client $client = null)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -127,6 +133,7 @@ final class ClientInput
 | 
			
		|||
        $this->ip = $client->getIp();
 | 
			
		||||
        $this->position = $client->getPosition();
 | 
			
		||||
        $this->status = $client->getStatus();
 | 
			
		||||
        $this->resolution = $client->getResolution();
 | 
			
		||||
 | 
			
		||||
        if ($client->getMenu()) {
 | 
			
		||||
            $this->menu = new MenuOutput($client->getMenu());
 | 
			
		||||
| 
						 | 
				
			
			@ -170,6 +177,7 @@ final class ClientInput
 | 
			
		|||
        $client->setPosition($this->position);
 | 
			
		||||
        $client->setStatus($this->status);
 | 
			
		||||
        $client->setMaintenance($this->maintenance);
 | 
			
		||||
        $client->setResolution($this->resolution);  
 | 
			
		||||
        
 | 
			
		||||
        return $client;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,10 +6,10 @@ namespace App\Dto\Input;
 | 
			
		|||
 | 
			
		||||
use ApiPlatform\Metadata\ApiProperty;
 | 
			
		||||
use App\Dto\Output\ClientOutput;
 | 
			
		||||
use App\Validator\Constraints\ClientsHaveSamePartitionCount;
 | 
			
		||||
use App\Validator\Constraints\ClientsHaveSamePartitionSize;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		||||
 | 
			
		||||
#[ClientsHaveSamePartitionCount]
 | 
			
		||||
#[ClientsHaveSamePartitionSize]
 | 
			
		||||
class DeployGitImageInput
 | 
			
		||||
{
 | 
			
		||||
    #[Groups(['git-repository:write'])]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,13 +4,13 @@ namespace App\Dto\Input;
 | 
			
		|||
 | 
			
		||||
use ApiPlatform\Metadata\ApiProperty;
 | 
			
		||||
use App\Dto\Output\ClientOutput;
 | 
			
		||||
use App\Validator\Constraints\ClientsHaveSamePartitionCount;
 | 
			
		||||
use App\Validator\Constraints\ClientsHaveSamePartitionSize;
 | 
			
		||||
use App\Validator\Constraints\OrganizationalUnitMulticastMode;
 | 
			
		||||
use App\Validator\Constraints\OrganizationalUnitMulticastPort;
 | 
			
		||||
use App\Validator\Constraints\OrganizationalUnitP2PMode;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		||||
 | 
			
		||||
#[ClientsHaveSamePartitionCount]
 | 
			
		||||
#[ClientsHaveSamePartitionSize]
 | 
			
		||||
class DeployImageInput
 | 
			
		||||
{
 | 
			
		||||
    #[Groups(['image-image-repository:write'])]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,8 @@ use Symfony\Component\Validator\Constraints as Assert;
 | 
			
		|||
#[OrganizationalUnitParent]
 | 
			
		||||
class OrganizationalUnitInput
 | 
			
		||||
{
 | 
			
		||||
    private ?OrganizationalUnit $originalEntity = null;
 | 
			
		||||
 | 
			
		||||
    #[Assert\NotBlank(message: 'validators.organizational_unit.name.not_blank')]
 | 
			
		||||
    #[Groups(['organizational-unit:write'])]
 | 
			
		||||
    #[ApiProperty(
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +115,7 @@ class OrganizationalUnitInput
 | 
			
		|||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->originalEntity = $organizationalUnit;
 | 
			
		||||
        $this->name = $organizationalUnit->getName();
 | 
			
		||||
        if ($organizationalUnit->getParent()) {
 | 
			
		||||
            $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent());
 | 
			
		||||
| 
						 | 
				
			
			@ -164,4 +167,9 @@ class OrganizationalUnitInput
 | 
			
		|||
 | 
			
		||||
        return $organizationalUnit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getOriginalEntity(): ?OrganizationalUnit
 | 
			
		||||
    {
 | 
			
		||||
        return $this->originalEntity;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -160,6 +160,13 @@ final class ClientOutput extends AbstractOutput
 | 
			
		|||
    )]
 | 
			
		||||
    public ?bool $pxeSync = false;
 | 
			
		||||
 | 
			
		||||
    #[Groups(['client:read'])]
 | 
			
		||||
    #[ApiProperty(
 | 
			
		||||
        description: 'La resolución del cliente',
 | 
			
		||||
        example: '1920x1080'
 | 
			
		||||
    )]
 | 
			
		||||
    public ?string $resolution = null;
 | 
			
		||||
 | 
			
		||||
    public function __construct(Client $client)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($client);
 | 
			
		||||
| 
						 | 
				
			
			@ -208,6 +215,7 @@ final class ClientOutput extends AbstractOutput
 | 
			
		|||
        $this->createdBy = $client->getCreatedBy();
 | 
			
		||||
        $this->maintenance = $client->isMaintenance();
 | 
			
		||||
        $this->pxeSync = $client->isPxeSync();
 | 
			
		||||
        $this->resolution = $client->getResolution();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function convertMaskToCIDR($mask): int
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,14 +11,14 @@ use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		|||
#[Get(shortName: 'Menu')]
 | 
			
		||||
final class MenuOutput extends AbstractOutput
 | 
			
		||||
{
 | 
			
		||||
    #[Groups(['menu:read', 'organizational-unit:read'])]
 | 
			
		||||
    #[Groups(['menu:read', 'client:read', 'organizational-unit:read'])]
 | 
			
		||||
    #[ApiProperty(
 | 
			
		||||
        description: 'El nombre del menú de arranque',
 | 
			
		||||
        example: 'Menú Principal'
 | 
			
		||||
    )]
 | 
			
		||||
    public string $name;
 | 
			
		||||
 | 
			
		||||
    #[Groups(['menu:read'])]
 | 
			
		||||
    #[Groups(['menu:read', 'client:read', 'organizational-unit:read'])]
 | 
			
		||||
    #[ApiProperty(
 | 
			
		||||
        description: 'La resolución del menú',
 | 
			
		||||
        example: '1024x768'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,6 +94,9 @@ class Client extends AbstractEntity
 | 
			
		|||
    #[ORM\Column(length: 255, nullable: true)]
 | 
			
		||||
    private ?string $token = null;
 | 
			
		||||
 | 
			
		||||
    #[ORM\Column(length: 255, nullable: true)]
 | 
			
		||||
    private ?string $resolution = null;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
| 
						 | 
				
			
			@ -371,4 +374,15 @@ class Client extends AbstractEntity
 | 
			
		|||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getResolution(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->resolution;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setResolution(?string $resolution): static
 | 
			
		||||
    {
 | 
			
		||||
        $this->resolution = $resolution;
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,6 +75,7 @@ readonly class ClientProcessor implements ProcessorInterface
 | 
			
		|||
 | 
			
		||||
        if ($defaultMenu && !$client->getMenu()) {
 | 
			
		||||
            $client->setMenu($defaultMenu);
 | 
			
		||||
            $client->setResolution($defaultMenu->getResolution());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($defaultPxe && !$client->getTemplate()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,39 +0,0 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Validator\Constraints;
 | 
			
		||||
 | 
			
		||||
use App\Dto\Input\DeployImageInput;
 | 
			
		||||
use App\Dto\Output\ClientOutput;
 | 
			
		||||
use App\Entity\Client;
 | 
			
		||||
use Symfony\Component\Validator\ConstraintValidator;
 | 
			
		||||
use Symfony\Component\Validator\Constraint;
 | 
			
		||||
 | 
			
		||||
class ClientsHaveSamePartitionCountValidator extends ConstraintValidator
 | 
			
		||||
{
 | 
			
		||||
    public function validate($value, Constraint $constraint): void
 | 
			
		||||
    {
 | 
			
		||||
        if (!$value instanceof DeployImageInput) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isset($value->clients) && is_array($value->clients)) {
 | 
			
		||||
            $partitionCounts = [];
 | 
			
		||||
            foreach ($value->clients as $client) {
 | 
			
		||||
                $partitionCount = $client->getEntity()->getPartitions()->count();
 | 
			
		||||
                $partitionCounts[(string) $client->getEntity()->getIp()] = $partitionCount;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (count(array_unique($partitionCounts)) > 1) {
 | 
			
		||||
                $errorDetails = [];
 | 
			
		||||
                foreach ($partitionCounts as $clientIp => $partitionCount) {
 | 
			
		||||
                    $errorDetails[] = "Cliente $clientIp tiene $partitionCount particiones.";
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $detailedMessage = implode(" ", $errorDetails);
 | 
			
		||||
 | 
			
		||||
                $this->context->buildViolation($constraint->message . ' Detalles: ' . $detailedMessage)
 | 
			
		||||
                    ->addViolation();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ namespace App\Validator\Constraints;
 | 
			
		|||
use Symfony\Component\Validator\Constraint;
 | 
			
		||||
 | 
			
		||||
#[\Attribute]
 | 
			
		||||
class ClientsHaveSamePartitionCount extends Constraint
 | 
			
		||||
class ClientsHaveSamePartitionSize extends Constraint
 | 
			
		||||
{
 | 
			
		||||
    public string $message;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class ClientsHaveSamePartitionCount extends Constraint
 | 
			
		|||
    {
 | 
			
		||||
        parent::__construct($options, $groups, $payload);
 | 
			
		||||
 | 
			
		||||
        $this->message = 'All clients must have the same number of partitions.';
 | 
			
		||||
        $this->message = 'Todos los clientes deben tener el mismo tamaño de partición para la partición seleccionada.';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getTargets(): string
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Validator\Constraints;
 | 
			
		||||
 | 
			
		||||
use App\Dto\Input\DeployImageInput;
 | 
			
		||||
use App\Dto\Input\DeployGitImageInput;
 | 
			
		||||
use App\Dto\Output\ClientOutput;
 | 
			
		||||
use App\Entity\Client;
 | 
			
		||||
use Symfony\Component\Validator\ConstraintValidator;
 | 
			
		||||
use Symfony\Component\Validator\Constraint;
 | 
			
		||||
 | 
			
		||||
class ClientsHaveSamePartitionSizeValidator extends ConstraintValidator
 | 
			
		||||
{
 | 
			
		||||
    public function validate($value, Constraint $constraint): void
 | 
			
		||||
    {
 | 
			
		||||
        if (!$value instanceof DeployImageInput && !$value instanceof DeployGitImageInput) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!isset($value->clients) || !is_array($value->clients) || empty($value->clients)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($value->diskNumber === null || $value->partitionNumber === null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $partitionSizes = [];
 | 
			
		||||
        
 | 
			
		||||
        foreach ($value->clients as $client) {
 | 
			
		||||
            $clientEntity = $client->getEntity();
 | 
			
		||||
            
 | 
			
		||||
            if (!$clientEntity instanceof Client) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $clientIp = (string) $clientEntity->getIp();
 | 
			
		||||
            
 | 
			
		||||
            $targetPartition = null;
 | 
			
		||||
            foreach ($clientEntity->getPartitions() as $partition) {
 | 
			
		||||
                if ($partition->getDiskNumber() === $value->diskNumber && 
 | 
			
		||||
                    $partition->getPartitionNumber() === $value->partitionNumber) {
 | 
			
		||||
                    $targetPartition = $partition;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($targetPartition === null) {
 | 
			
		||||
                $partitionSizes[$clientIp] = null;
 | 
			
		||||
            } else {
 | 
			
		||||
                $partitionSizes[$clientIp] = $targetPartition->getSize();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $validSizes = array_filter($partitionSizes, fn($size) => $size !== null);
 | 
			
		||||
 | 
			
		||||
        if (count($validSizes) !== count($partitionSizes)) {
 | 
			
		||||
            $clientsWithoutPartition = array_keys(array_filter($partitionSizes, fn($size) => $size === null));
 | 
			
		||||
            $this->context->buildViolation('Algunos clientes no tienen la partición seleccionada (Disco: ' . $value->diskNumber . ', Partición: ' . $value->partitionNumber . '). Clientes sin partición: ' . implode(', ', $clientsWithoutPartition))
 | 
			
		||||
                ->addViolation();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (count(array_unique($validSizes)) > 1) {
 | 
			
		||||
            $errorDetails = [];
 | 
			
		||||
            foreach ($partitionSizes as $clientIp => $partitionSize) {
 | 
			
		||||
                $errorDetails[] = "Cliente $clientIp tiene tamaño $partitionSize KB.";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $detailedMessage = implode(" ", $errorDetails);
 | 
			
		||||
 | 
			
		||||
            $this->context->buildViolation($constraint->message . ' Detalles: ' . $detailedMessage)
 | 
			
		||||
                ->addViolation();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -9,12 +9,14 @@ use Symfony\Component\Validator\Constraint;
 | 
			
		|||
class OrganizationalUnitParent extends Constraint
 | 
			
		||||
{
 | 
			
		||||
    public string $message;
 | 
			
		||||
    public string $selfParentMessage;
 | 
			
		||||
 | 
			
		||||
    public function __construct(mixed $options = null, ?array $groups = null, mixed $payload = null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($options, $groups, $payload);
 | 
			
		||||
 | 
			
		||||
        $this->message = 'Only the root organizational unit can not have a parent.';
 | 
			
		||||
        $this->message = 'validators.organizational_unit.parent.required';
 | 
			
		||||
        $this->selfParentMessage = 'validators.organizational_unit.parent.self_parent';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getTargets(): array|string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,5 +21,14 @@ class OrganizationalUnitParentValidator extends ConstraintValidator
 | 
			
		|||
            $this->context->buildViolation($constraint->message)->addViolation();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validar que el parent no sea la misma entidad que se está modificando
 | 
			
		||||
        if ($value->parent && $value->getOriginalEntity()) {
 | 
			
		||||
            if ($value->parent->getEntity()->getId() === $value->getOriginalEntity()->getId()) {
 | 
			
		||||
                $this->context->buildViolation($constraint->selfParentMessage)
 | 
			
		||||
                    ->atPath('parent')
 | 
			
		||||
                    ->addViolation();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +57,11 @@ validators:
 | 
			
		|||
            not_blank: 'The name should not be blank.'
 | 
			
		||||
            unique: 'The name should be unique.'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    organizational_unit:
 | 
			
		||||
        parent:
 | 
			
		||||
            self_parent: 'The parent should not be the same as the organizational unit.'
 | 
			
		||||
            required: 'The parent should be required.'
 | 
			
		||||
    subnet:
 | 
			
		||||
        name:
 | 
			
		||||
            not_blank: 'The name should not be blank.'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,11 @@ validators:
 | 
			
		|||
            not_blank: 'El nombre no debería estar vacío.'
 | 
			
		||||
            unique: 'El nombre debería ser único. Ya existe un archivo con ese nombre.'
 | 
			
		||||
 | 
			
		||||
    organizational_unit:
 | 
			
		||||
        parent:
 | 
			
		||||
            self_parent: 'El padre no debería ser la misma unidad organizativa.'
 | 
			
		||||
            required: 'El padre debería ser requerido.'
 | 
			
		||||
 | 
			
		||||
    network_settings:
 | 
			
		||||
        ip_address:
 | 
			
		||||
            invalid: 'La dirección IP "{{ value }}" no es válida.'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue