Compare commits

...

9 Commits

Author SHA1 Message Date
Manuel Aranda Rosales 55e02b6400 Stable version
testing/ogcore-api/pipeline/head This commit looks good Details
ogcore-debian-package/pipeline/tag This commit looks good Details
ogcore-debian-package/pipeline/head This commit looks good Details
2025-10-09 16:03:55 +02:00
Manuel Aranda Rosales 5a1fb24177 Stable version
ogcore-debian-package/pipeline/head There was a failure building this commit Details
ogcore-debian-package/pipeline/tag There was a failure building this commit Details
testing/ogcore-api/pipeline/head This commit looks good Details
2025-10-09 14:38:37 +02:00
Manuel Aranda Rosales 2aacdb3c7f Merge pull request 'develop' (#67) from develop into main
ogcore-debian-package/pipeline/head This commit looks good Details
testing/ogcore-api/pipeline/head This commit looks good Details
ogcore-debian-package/pipeline/tag This commit looks good Details
Reviewed-on: #67
2025-10-09 11:05:55 +02:00
Manuel Aranda Rosales 9db9d61129 Updated ogCore wieh new docu
testing/ogcore-api/pipeline/head This commit looks good Details
testing/ogcore-api/pipeline/pr-main Build queued... Details
2025-10-09 10:53:32 +02:00
Manuel Aranda Rosales 84709a7c31 Merge branch 'main' into develop
testing/ogcore-api/pipeline/head There was a failure building this commit Details
2025-10-01 08:22:40 +02:00
Manuel Aranda Rosales 93d17be4ed Fixed some command task bugs
testing/ogcore-api/pipeline/head Build queued... Details
2025-10-01 08:22:10 +02:00
Manuel Aranda Rosales 51f968e494 Fixed some command task bugs 2025-10-01 08:21:23 +02:00
Nicolas Arenas 6ed01d6f9d Merge pull request 'Clean cache in upgrade' (#66) from fix_package into main
ogcore-debian-package/pipeline/head This commit looks good Details
testing/ogcore-api/pipeline/head There was a failure building this commit Details
Reviewed-on: #66
2025-09-26 10:41:05 +02:00
Nicolas Arenas 8fea637440 Merge pull request 'Clean cache in upgrade' (#65) from fix_package into main
testing/ogcore-api/pipeline/head There was a failure building this commit Details
ogcore-debian-package/pipeline/head This commit looks good Details
Reviewed-on: #65
2025-09-26 10:25:59 +02:00
80 changed files with 5891 additions and 297 deletions

View File

@ -1,4 +1,20 @@
# Changelog
## [1.0.0] - 2025-10-09
### Added
- Se ha añadido nuevo readme
---
## [0.26.0] - 2025-10-09
### Added
- Se han añadido nueva documentacion en swagger para facilitar la integracion de ogCore
- Se ha añadido y completado el README y la documentacion funcional
---
## [0.25.1] - 2025-10-01
### Fixed
- Se han corregido varios errores con respecto a las tareas programadas.
---
## [0.25.0] - 2025-09-23
### Added
- Se ha añadido logica para obtener el inventario hardware de un cliente para poder almanecarlo en base de datos.

1854
README.md

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
api_platform:
title: 'OgCore Api'
description: 'Api Documentation for OgCore'
version: 0.5.0
version: 1.0.0
path_segment_name_generator: api_platform.path_segment_name_generator.dash
defaults:
pagination_client_items_per_page: true

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,286 @@
<?php
declare(strict_types=1);
namespace App\Command;
use App\Entity\Image;
use App\Entity\ImageRepository;
use App\Entity\ImageImageRepository;
use App\Model\ImageStatus;
use App\Repository\ImageRepository as ImageRepositoryRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
#[AsCommand(
name: 'app:create-image-repositories',
description: 'Crea una ImageRepository y/o ImageImageRepository con datos interactivos'
)]
class CreateImageRepositoriesCommand extends Command
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly ImageRepositoryRepository $imageRepository
) {
parent::__construct();
}
protected function configure(): void
{
$this
->setDescription('Crea una ImageRepository y/o ImageImageRepository')
->addArgument('action', InputArgument::OPTIONAL, 'Acción a realizar: repository, image-repository, o both', 'both')
->addOption('repository-name', null, InputOption::VALUE_OPTIONAL, 'Nombre del repositorio de imágenes')
->addOption('repository-ip', null, InputOption::VALUE_OPTIONAL, 'IP del repositorio de imágenes')
->addOption('repository-user', null, InputOption::VALUE_OPTIONAL, 'Usuario del repositorio', ImageRepository::DEFAULT_USER)
->addOption('repository-ssh-port', null, InputOption::VALUE_OPTIONAL, 'Puerto SSH del repositorio')
->addOption('repository-comments', null, InputOption::VALUE_OPTIONAL, 'Comentarios del repositorio')
->addOption('image-name', null, InputOption::VALUE_OPTIONAL, 'Nombre de la imagen')
->addOption('image-type', null, InputOption::VALUE_OPTIONAL, 'Tipo de imagen', 'Server')
->addOption('image-version', null, InputOption::VALUE_OPTIONAL, 'Versión de la imagen', '1')
->addOption('image-repository-name', null, InputOption::VALUE_OPTIONAL, 'Nombre para ImageImageRepository')
->addOption('image-repository-status', null, InputOption::VALUE_OPTIONAL, 'Status para ImageImageRepository', ImageStatus::SUCCESS)
->addOption('batch', 'b', InputOption::VALUE_NONE, 'Modo no interactivo (usar solo opciones)');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$action = $input->getArgument('action');
$batchMode = $input->getOption('batch');
$helper = $this->getHelper('question');
$output->writeln('<info>🚀 Creador de ImageRepository e ImageImageRepository</info>');
$output->writeln('');
try {
switch ($action) {
case 'repository':
$imageRepository = $this->createImageRepository($input, $output, $helper, $batchMode);
$output->writeln("<success>✅ ImageRepository creado exitosamente: {$imageRepository->getName()}</success>");
break;
case 'image-repository':
$imageImageRepository = $this->createImageImageRepository($input, $output, $helper, $batchMode);
$output->writeln("<success>✅ ImageImageRepository creado exitosamente: {$imageImageRepository->getName()}</success>");
break;
case 'both':
default:
$output->writeln('<comment>Creando ImageRepository primero...</comment>');
$imageRepository = $this->createImageRepository($input, $output, $helper, $batchMode);
$output->writeln("<success>✅ ImageRepository creado: {$imageRepository->getName()}</success>");
$output->writeln('');
$output->writeln('<comment>Ahora creando ImageImageRepository...</comment>');
$imageImageRepository = $this->createImageImageRepository($input, $output, $helper, $batchMode, $imageRepository);
$output->writeln("<success>✅ ImageImageRepository creado: {$imageImageRepository->getName()}</success>");
break;
}
$this->entityManager->flush();
$output->writeln('');
$output->writeln('<success>🎉 ¡Proceso completado exitosamente!</success>');
return Command::SUCCESS;
} catch (\Exception $e) {
$output->writeln("<error>❌ Error: {$e->getMessage()}</error>");
return Command::FAILURE;
}
}
private function createImageRepository(InputInterface $input, OutputInterface $output, $helper, bool $batchMode): ImageRepository
{
// Recopilar datos para ImageRepository
$name = $input->getOption('repository-name');
if (!$name && !$batchMode) {
$question = new Question('<question>Nombre del repositorio de imágenes: </question>');
$question->setValidator(function ($value) {
if (empty($value)) {
throw new \RuntimeException('El nombre no puede estar vacío');
}
return $value;
});
$name = $helper->ask($input, $output, $question);
}
$ip = $input->getOption('repository-ip');
if (!$ip && !$batchMode) {
$question = new Question('<question>IP del repositorio: </question>');
$question->setValidator(function ($value) {
if (empty($value)) {
throw new \RuntimeException('La IP no puede estar vacía');
}
if (!filter_var($value, FILTER_VALIDATE_IP)) {
throw new \RuntimeException('La IP no es válida');
}
return $value;
});
$ip = $helper->ask($input, $output, $question);
}
$user = $input->getOption('repository-user') ?: ImageRepository::DEFAULT_USER;
if (!$batchMode) {
$question = new Question("<question>Usuario [{$user}]: </question>", $user);
$user = $helper->ask($input, $output, $question);
}
$sshPort = $input->getOption('repository-ssh-port');
if (!$sshPort && !$batchMode) {
$question = new Question('<question>Puerto SSH [22]: </question>', '22');
$sshPort = $helper->ask($input, $output, $question);
}
$comments = $input->getOption('repository-comments');
if (!$comments && !$batchMode) {
$question = new Question('<question>Comentarios (opcional): </question>');
$comments = $helper->ask($input, $output, $question);
}
// Crear ImageRepository
$imageRepository = new ImageRepository();
$imageRepository->setName($name);
$imageRepository->setIp($ip);
$imageRepository->setUser($user);
$imageRepository->setSshPort($sshPort);
if ($comments) {
$imageRepository->setComments($comments);
}
$this->entityManager->persist($imageRepository);
return $imageRepository;
}
private function createImageImageRepository(InputInterface $input, OutputInterface $output, $helper, bool $batchMode, ?ImageRepository $repository = null): ImageImageRepository
{
// Si no tenemos repository, necesitamos seleccionar uno existente
if (!$repository) {
$repositories = $this->imageRepository->findAll();
if (empty($repositories)) {
throw new \RuntimeException('No hay ImageRepositories disponibles. Crea uno primero.');
}
if (!$batchMode) {
$output->writeln('<comment>Repositorios disponibles:</comment>');
foreach ($repositories as $i => $repo) {
$output->writeln(" [{$i}] {$repo->getName()} ({$repo->getIp()})");
}
$question = new Question('<question>Selecciona un repositorio (número): </question>');
$question->setValidator(function ($value) use ($repositories) {
if (!is_numeric($value) || !isset($repositories[$value])) {
throw new \RuntimeException('Selección inválida');
}
return (int)$value;
});
$repoIndex = $helper->ask($input, $output, $question);
$repository = $repositories[$repoIndex];
} else {
$repository = $repositories[0]; // Usar el primero disponible en modo batch
}
}
// Obtener todas las imágenes disponibles
$images = $this->entityManager->getRepository(Image::class)->findAll();
$image = null;
if (!empty($images) && !$batchMode) {
$output->writeln('<comment>Imágenes disponibles:</comment>');
foreach ($images as $i => $img) {
$output->writeln(" [{$i}] {$img->getName()} (Tipo: {$img->getType()})");
}
$output->writeln(" [new] Crear nueva imagen");
$question = new Question('<question>Selecciona una imagen o "new" para crear nueva: </question>');
$imageChoice = $helper->ask($input, $output, $question);
if ($imageChoice !== 'new' && is_numeric($imageChoice) && isset($images[$imageChoice])) {
$image = $images[$imageChoice];
}
}
// Si no hay imagen seleccionada, crear una nueva
if (!$image) {
$imageName = $input->getOption('image-name');
if (!$imageName && !$batchMode) {
$question = new Question('<question>Nombre de la imagen: </question>');
$question->setValidator(function ($value) {
if (empty($value)) {
throw new \RuntimeException('El nombre de la imagen no puede estar vacío');
}
return $value;
});
$imageName = $helper->ask($input, $output, $question);
}
$imageType = $input->getOption('image-type') ?: 'Server';
if (!$batchMode) {
$question = new Question("<question>Tipo de imagen [{$imageType}]: </question>", $imageType);
$imageType = $helper->ask($input, $output, $question);
}
$imageVersion = $input->getOption('image-version') ?: 1;
if (!$batchMode) {
$question = new Question("<question>Versión de la imagen [{$imageVersion}]: </question>", $imageVersion);
$imageVersion = (int)$helper->ask($input, $output, $question);
}
// Crear nueva imagen
$image = new Image();
$image->setName($imageName);
$image->setType($imageType);
$image->setVersion($imageVersion);
$image->setRemotePc(false);
$image->setIsGlobal(true);
$this->entityManager->persist($image);
}
// Recopilar datos para ImageImageRepository
$imageRepositoryName = $input->getOption('image-repository-name');
if (!$imageRepositoryName && !$batchMode) {
$defaultName = $image->getName() . '_' . $repository->getName();
$question = new Question("<question>Nombre para ImageImageRepository [{$defaultName}]: </question>", $defaultName);
$imageRepositoryName = $helper->ask($input, $output, $question);
} elseif (!$imageRepositoryName) {
$imageRepositoryName = $image->getName() . '_' . $repository->getName();
}
$status = $input->getOption('image-repository-status') ?: ImageStatus::SUCCESS;
if (!$batchMode) {
$output->writeln('<comment>Status disponibles:</comment>');
foreach (ImageStatus::getStatusKeys() as $statusKey) {
$output->writeln(" - {$statusKey}");
}
$question = new Question("<question>Status [{$status}]: </question>", $status);
$question->setValidator(function ($value) {
if (!in_array($value, ImageStatus::getStatusKeys())) {
throw new \RuntimeException('Status inválido');
}
return $value;
});
$status = $helper->ask($input, $output, $question);
}
// Crear ImageImageRepository
$imageImageRepository = new ImageImageRepository();
$imageImageRepository->setName($imageRepositoryName);
$imageImageRepository->setImage($image);
$imageImageRepository->setRepository($repository);
$imageImageRepository->setStatus($status);
$imageImageRepository->setCreated(true);
$imageImageRepository->setVersion($image->getVersion());
$this->entityManager->persist($imageImageRepository);
return $imageImageRepository;
}
}

View File

@ -223,7 +223,7 @@ class ExecutePendingTracesCommand extends Command
if (isset($input['action']) && $input['action'] === 'create') {
$image = new Image();
$image->setName($input['imageName'] ?? 'Image_' . uniqid());
$image->setName($input['name'] );
$image->setType($input['type'] ?? 'monolithic');
$image->setRemotePc($input['remotePc'] ?? false);
$image->setIsGlobal($input['isGlobal'] ?? false);
@ -368,7 +368,7 @@ class ExecutePendingTracesCommand extends Command
$partitionInputObj->partitionCode = $item['partitionCode'] ?? 'LINUX';
$partitionInputObj->size = $item['size'];
$partitionInputObj->filesystem = $item['filesystem'] ?? 'EXT4';
$partitionInputObj->format = ($item['format'] ?? '0') === '1';
$partitionInputObj->format = $item['format'] ?? false;
$partitions[] = $partitionInputObj;
}

View File

@ -6,32 +6,24 @@ namespace App\Controller;
use ApiPlatform\Validator\ValidatorInterface;
use App\Dto\Input\DeployGitImageInput;
use App\Entity\Command;
use App\Entity\Image;
use App\Model\ClientStatus;
use App\Entity\ImageImageRepository;
use App\Entity\OrganizationalUnit;
use App\Entity\Partition;
use App\Model\CommandTypes;
use App\Model\DeployMethodTypes;
use App\Model\TraceStatus;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class DeployGitImageAction extends AbstractController
{
public function __construct(
protected readonly EntityManagerInterface $entityManager,
protected readonly CreateService $createService,
protected readonly ValidatorInterface $validator,
protected readonly LoggerInterface $logger,
public readonly \App\Controller\OgAgent\DeployGitImageAction $deployGitImageOgAgentAction,
) {
}
@ -55,11 +47,25 @@ class DeployGitImageAction extends AbstractController
$clientJobs = [];
foreach ($input->clients as $client) {
$inputData = $this->createInputData($input, $client->getEntity());
$jobId = $this->processDeployment($client->getEntity(), $input, $inputData, DeployMethodTypes::GIT);
if ($jobId) {
$clientJobs[(string) '/clients/' . $client->getEntity()->getUuid()] = $jobId;
try {
$inputData = $this->createInputData($input, $client->getEntity());
$jobId = $this->processDeployment($client->getEntity(), $input, $inputData, DeployMethodTypes::GIT);
if ($jobId) {
$clientJobs[(string) '/clients/' . $client->getEntity()->getUuid()] = $jobId;
}
} catch (\Exception $e) {
$this->logger->warning('Error deploying git image to client', [
'client_uuid' => $client->getEntity()->getUuid(),
'error' => $e->getMessage()
]);
if ($input->queue) {
$inputData = $this->createInputData($input, $client->getEntity());
$this->createService->__invoke($client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::PENDING, null, $inputData);
}
continue;
}
}
@ -85,7 +91,6 @@ class DeployGitImageAction extends AbstractController
private function createInputData(DeployGitImageInput $input, $client): array
{
return [
'method' => $input->method,
'client' => $client->getUuid(),
'hexsha' => $input->hexsha,
'repositoryName' => $input->repositoryName,

View File

@ -6,28 +6,14 @@ namespace App\Controller\OgAgent;
use App\Dto\Input\CheckPartitionSizesInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\Partition;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Validator\Exception\ValidatorException;
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\Contracts\HttpClient\HttpClientInterface;
class CheckPartitionSizesAction extends AbstractOgAgentController
{

View File

@ -200,7 +200,6 @@ class CreateImageAction extends AbstractOgAgentController
if ($existingTrace) {
$existingTrace->setStatus(TraceStatus::IN_PROGRESS);
$existingTrace->setJobId($jobId);
$existingTrace->setInput($inputData);
$this->entityManager->persist($existingTrace);
$this->entityManager->flush();
} else {

View File

@ -6,10 +6,7 @@ namespace App\Controller\OgAgent;
use App\Dto\Input\DeployGitImageInput;
use App\Entity\Client;
use App\Entity\Image;
use App\Model\ClientStatus;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
@ -31,7 +28,7 @@ class DeployGitImageAction extends AbstractOgAgentController
throw new BadRequestHttpException('IP is required');
}
if (!$input->hexsha && !$input->tag) {
if (!$input->hexsha) {
throw new BadRequestHttpException('Either hexsha or tag is required for Git image deployment');
}
@ -51,9 +48,9 @@ class DeployGitImageAction extends AbstractOgAgentController
'idi' => $input->repositoryName,
'image_name' => $input->repositoryName,
'repository' => $repository->getIp(),
'nfn' => 'RestaurarImagenGit',
'nfn' => 'RestaurarImagenGit',
'ids' => '0',
'commit' => $input->hexsha ?? $input->tag,
'commit' => $input->hexsha,
'branch' => $input->branch
];
@ -71,7 +68,7 @@ class DeployGitImageAction extends AbstractOgAgentController
$this->logger->info('Deploying Git image', [
'repository' => $input->repositoryName,
'branch' => $input->branch,
'ref' => $input->hexsha ?? $input->tag,
'ref' => $input->hexsha,
'client' => $client->getIp()
]);

View File

@ -6,29 +6,15 @@ namespace App\Controller\OgAgent;
use App\Dto\Input\DeployImageInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\Partition;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\DeployMethodTypes;
use App\Model\TraceStatus;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpClient\Exception\TransportException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Validator\Exception\ValidatorException;
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\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class DeployImageAction extends AbstractOgAgentController
{

View File

@ -6,28 +6,20 @@ namespace App\Controller\OgAgent;
use App\Dto\Input\PartitionPostInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\Partition;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Validator\Exception\ValidatorException;
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\Contracts\HttpClient\HttpClientInterface;
class PartitionAssistantAction extends AbstractOgAgentController
{
@ -130,7 +122,6 @@ class PartitionAssistantAction extends AbstractOgAgentController
if ($existingTrace) {
$existingTrace->setStatus(TraceStatus::IN_PROGRESS);
$existingTrace->setJobId($jobId);
$existingTrace->setInput($data);
$this->entityManager->persist($existingTrace);
$this->entityManager->flush();
} else {

View File

@ -6,27 +6,16 @@ namespace App\Controller\OgAgent;
use App\Dto\Input\MultipleClientsInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Validator\Exception\ValidatorException;
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\Contracts\HttpClient\HttpClientInterface;
class RebootAction extends AbstractOgAgentController
{

View File

@ -11,7 +11,6 @@ use App\Model\TraceStatus;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;

View File

@ -2,26 +2,19 @@
namespace App\Controller\OgAgent;
use App\Dto\Input\CommandExecuteInput;
use App\Dto\Input\MultipleClientsInput;
use App\Dto\Input\CommandExecuteInput;
use App\Entity\Client;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
use App\Model\TraceStatus;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Validator\Exception\ValidatorException;
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\Contracts\HttpClient\HttpClientInterface;
class RunScriptAction extends AbstractOgAgentController
{
@ -170,7 +163,6 @@ class RunScriptAction extends AbstractOgAgentController
$status = ($this->isLinuxOrWindows($client) || $this->isLinuxOrWindowsSession($client)) ? TraceStatus::SENT : TraceStatus::IN_PROGRESS;
$trace->setStatus($status);
$trace->setJobId($jobId);
$trace->setInput($inputData);
$this->entityManager->persist($trace);
$this->entityManager->flush();
}

View File

@ -47,7 +47,7 @@ class UpdateGitImageAction extends AbstractOgAgentController
'nfn' => 'ModificarImagenGit',
'ids' => '0',
'branch' => $input->destinationBranch,
'options' => $input->options ? 'force push' : null,
'options' => $input->options ? 'force_push' : null,
];
$url = 'https://'.$client->getIp().':8000/opengnsys/ModificarImagenGit';

View File

@ -3,11 +3,8 @@
namespace App\Controller\OgBoot\PxeBootFile;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Dto\Input\PxeTemplateSyncClientInput;
use App\Entity\Client;
use App\Entity\PxeTemplate;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
@ -15,7 +12,6 @@ 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\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class PostAction extends AbstractOgBootController

View File

@ -3,22 +3,21 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\PartitionOutput;
use App\Validator\Constraints\ClientsHaveSamePartitionCount;
use App\Validator\Constraints\OrganizationalUnitMulticastMode;
use App\Validator\Constraints\OrganizationalUnitMulticastPort;
use App\Validator\Constraints\OrganizationalUnitP2PMode;
use Symfony\Component\Serializer\Annotation\Groups;
final class BackupImageInput
{
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The repository ip', example: "")]
#[ApiProperty(
description: 'La IP del repositorio de destino',
example: '192.168.1.100'
)]
public ?string $repoIp = null;
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The remote path', example: "")]
#[ApiProperty(
description: 'La ruta remota donde guardar el backup',
example: '/backups/images/'
)]
public ?string $remotePath = null;
}

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\PartitionOutput;
use Symfony\Component\Serializer\Annotation\Groups;
@ -12,10 +13,17 @@ final class BootClientsInput
* @var ClientOutput[]
*/
#[Groups(['client:write'])]
#[ApiProperty(
description: 'Los clientes a arrancar',
example: []
)]
public array $clients = [];
#[Groups(['client:write'])]
#[ApiProperty(
description: 'La partición desde la que arrancar',
example: null
)]
public ?PartitionOutput $partition = null;
}

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\TraceOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -13,5 +14,9 @@ final class CancelMultipleTracesInput
*/
#[Assert\NotNull]
#[Groups(['trace:write'])]
#[ApiProperty(
description: 'Las trazas a cancelar',
example: []
)]
public array $traces = [];
}

View File

@ -2,9 +2,9 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\Client;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -15,9 +15,17 @@ final class ChangeOrganizationalUnitInput
*/
#[Assert\GreaterThan(1)]
#[Groups(['client:write'])]
#[ApiProperty(
description: 'Los clientes a mover (mínimo 2)',
example: []
)]
public ?array $clients = [];
#[Assert\NotNull]
#[Groups(['client:write'])]
#[ApiProperty(
description: 'La nueva unidad organizativa de destino',
example: null
)]
public ?OrganizationalUnitOutput $organizationalUnit = null;
}

View File

@ -2,7 +2,7 @@
namespace App\Dto\Input;
use App\Dto\Output\ClientOutput;
use ApiPlatform\Metadata\ApiProperty;
use Symfony\Component\Serializer\Annotation\Groups;
final class CheckPartitionSizesInput
@ -11,6 +11,10 @@ final class CheckPartitionSizesInput
* @var PartitionInput[]
*/
#[Groups(['client:write'])]
#[ApiProperty(
description: 'Las particiones a verificar',
example: []
)]
public array $partitions = [];
}

View File

@ -44,7 +44,7 @@ final class ClientInput
description: 'El driver de red del cliente',
example: 'e1000e'
)]
public ?string $netDriver = null;
public ?string $netDriver = 'generic';
#[Groups(['client:write'])]
#[ApiProperty(
@ -85,13 +85,7 @@ final class ClientInput
#[ApiProperty(
description: 'La plantilla PXE del cliente'
)]
public ?PxeTemplateOutput $pxeTemplate = null;
#[Groups(['client:write'])]
#[ApiProperty(
description: 'El perfil de hardware del cliente'
)]
public ?HardwareProfileOutput $hardwareProfile = null;
public ?PxeTemplateOutput $pxeTemplate = null;
#[Groups(['client:write'])]
#[ApiProperty(
@ -146,10 +140,6 @@ final class ClientInput
$this->pxeTemplate = new PxeTemplateOutput($client->getTemplate());
}
if ($client->getHardwareProfile()) {
$this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile());
}
if ($client->getRepository()) {
$this->repository = new ImageRepositoryOutput($client->getRepository());
}
@ -163,7 +153,6 @@ final class ClientInput
$menu = $this->menu?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getMenu();
$ogLive = $this->ogLive?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getOgLive();
$hardwareProfile = $this->hardwareProfile?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getHardwareProfile();
$repository = $this->repository?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getRepository();
$template = $this->pxeTemplate?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getPxeTemplate();
@ -176,7 +165,6 @@ final class ClientInput
$client->setIp($this->ip);
$client->setMenu($menu);
$client->setOgLive($ogLive);
$client->setHardwareProfile($hardwareProfile);
$client->setRepository($repository);
$client->setTemplate($template);
$client->setPosition($this->position);

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -13,13 +14,24 @@ final class CommandExecuteInput
*/
#[Assert\NotNull]
#[Groups(['command:write'])]
#[ApiProperty(
description: 'Los clientes donde ejecutar el comando',
example: []
)]
public array $clients = [];
#[Assert\NotNull]
#[Groups(['command:write'])]
#[ApiProperty(
description: 'El script a ejecutar',
example: 'echo "Hello World"'
)]
public string $script = '';
#[Groups(['command:write'])]
#[ApiProperty(
description: 'Si encolar la ejecución del comando',
example: false
)]
public bool $queue = false;
}

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\CommandOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -13,5 +14,9 @@ final class CommandGroupAddCommandsInput
*/
#[Assert\NotNull]
#[Groups(['command-group:write'])]
#[ApiProperty(
description: 'Los comandos a añadir al grupo',
example: []
)]
public array $commands = [];
}

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -13,5 +14,9 @@ final class CommandGroupExecuteInput
*/
#[Assert\NotNull]
#[Groups(['command-group:write'])]
#[ApiProperty(
description: 'Los clientes donde ejecutar el grupo de comandos',
example: []
)]
public array $clients = [];
}

View File

@ -2,29 +2,53 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\CommandTaskOutput;
use App\Dto\Output\CommandTaskScheduleOutput;
use App\Entity\CommandTaskSchedule;
use Symfony\Component\Serializer\Annotation\Groups;
final class CommandTaskScheduleInput
{
#[Groups(['command-task-schedule:write'])]
#[ApiProperty(
description: 'La tarea de comando a programar',
example: null
)]
public ?CommandTaskOutput $commandTask = null;
#[Groups(['command-task-schedule:write'])]
#[ApiProperty(
description: 'El tipo de recurrencia de la programación',
example: 'daily'
)]
public ?string $recurrenceType = null;
#[Groups(['command-task-schedule:write'])]
#[ApiProperty(
description: 'La fecha de ejecución de la tarea',
example: '2024-01-15T00:00:00+00:00'
)]
public ?\DateTimeInterface $executionDate = null;
#[Groups(['command-task-schedule:write'])]
#[ApiProperty(
description: 'La hora de ejecución de la tarea',
example: '2024-01-15T09:00:00+00:00'
)]
public ?\DateTimeInterface $executionTime = null;
#[Groups(['command-task-schedule:write'])]
#[ApiProperty(
description: 'Los detalles de la recurrencia',
example: ['interval' => 1, 'days' => ['monday', 'wednesday', 'friday']]
)]
public ?array $recurrenceDetails = null;
#[Groups(['command-task-schedule:write'])]
#[ApiProperty(
description: 'Si la programación está habilitada',
example: true
)]
public ?bool $enabled = null;
public function __construct(?CommandTaskSchedule $commandTaskSchedule = null)

View File

@ -2,27 +2,46 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\CommandTaskOutput;
use App\Dto\Output\CommandTaskScheduleOutput;
use App\Entity\CommandTaskSchedule;
use App\Entity\CommandTaskScript;
use Symfony\Component\Serializer\Annotation\Groups;
final class CommandTaskScriptInput
{
#[Groups(['command-task-script:write'])]
#[ApiProperty(
description: 'El contenido del script',
example: '#!/bin/bash\necho "Hello World"'
)]
public ?string $content = null;
#[Groups(['command-task-script:write'])]
#[ApiProperty(
description: 'El tipo de script',
example: 'bash'
)]
public ?string $type = null;
#[Groups(['command-task-script:write'])]
#[ApiProperty(
description: 'Los parámetros del script',
example: ['param1' => 'value1', 'param2' => 'value2']
)]
public ?array $parameters = null;
#[Groups(['command-task-script:write'])]
#[ApiProperty(
description: 'La tarea de comando asociada',
example: null
)]
public ?CommandTaskOutput $commandTask = null;
#[Groups(['command-task-script:write'])]
#[ApiProperty(
description: 'El orden de ejecución del script',
example: 1
)]
public ?int $order = null;
public function __construct(?CommandTaskScript $commandTaskScript = null)

View File

@ -2,8 +2,7 @@
namespace App\Dto\Input;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\ImageRepositoryOutput;
use ApiPlatform\Metadata\ApiProperty;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -11,5 +10,9 @@ class ConvertImageToVirtualInput
{
#[Assert\NotNull]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(
description: 'La extensión del archivo virtual a generar',
example: 'qcow2'
)]
public ?string $extension = '';
}

View File

@ -2,8 +2,8 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\ImageRepositoryOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -14,5 +14,9 @@ class ExportImportImageRepositoryInput
*/
#[Assert\NotNull]
#[Groups(['repository:write'])]
#[ApiProperty(
description: 'Las imágenes a exportar o importar',
example: []
)]
public array $images = [];
}

View File

@ -2,7 +2,8 @@
namespace App\Dto\Input;
use App\Dto\Output\ClientOutput;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Input\PartitionInput;
use Symfony\Component\Serializer\Annotation\Groups;
final class GetPartitionScriptDataInput
@ -11,6 +12,10 @@ final class GetPartitionScriptDataInput
* @var PartitionInput[]
*/
#[Groups(['client:write'])]
#[ApiProperty(
description: 'Las particiones para obtener datos del script',
example: []
)]
public array $partitions = [];
}

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use Symfony\Component\Serializer\Annotation\Groups;
@ -11,9 +12,17 @@ final class MultipleClientsInput
* @var ClientOutput[]
*/
#[Groups(['client:write'])]
#[ApiProperty(
description: 'Los clientes para la operación múltiple',
example: []
)]
public array $clients = [];
#[Groups(['client:write'])]
#[ApiProperty(
description: 'Si encolar la operación',
example: false
)]
public bool $queue = false;
}

View File

@ -8,8 +8,6 @@ use App\Dto\Output\ImageRepositoryOutput;
use App\Dto\Output\MenuOutput;
use App\Dto\Output\OgLiveOutput;
use App\Dto\Output\PxeTemplateOutput;
use App\Entity\HardwareProfile;
use App\Entity\Menu;
use App\Entity\NetworkSettings;
use App\Validator\Constraints\OrganizationalUnitMulticastMode;
use App\Validator\Constraints\OrganizationalUnitMulticastPort;
@ -20,71 +18,146 @@ use Symfony\Component\Validator\Constraints as Assert;
class NetworkSettingsInput
{
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El servidor siguiente (next server) para PXE',
example: '192.168.1.1'
)]
public ?string $nextServer = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El nombre del archivo de arranque',
example: 'pxelinux.0'
)]
public ?string $bootFileName = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El servidor proxy',
example: 'http://proxy.example.com:8080'
)]
public ?string $proxy = null;
#[Assert\Ip(message: 'validators.network_settings.ip_address.invalid')]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El servidor DNS',
example: '8.8.8.8'
)]
public ?string $dns = null;
#[Assert\Ip(message: 'validators.network_settings.ip_address.invalid')]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La máscara de red',
example: '255.255.255.0'
)]
public ?string $netmask = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La puerta de enlace (router)',
example: '192.168.1.1'
)]
public ?string $router = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El servidor NTP',
example: 'pool.ntp.org'
)]
public ?string $ntp = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La interfaz de red',
example: 'eth0'
)]
public ?string $netiface = null;
#[OrganizationalUnitP2PMode]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El modo P2P para despliegues torrent',
example: 'seed'
)]
public ?string $p2pMode = null;
#[Assert\GreaterThan(0, message: 'validators.network_settings.p2p_time.invalid')]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El tiempo P2P en segundos',
example: 3600
)]
public ?int $p2pTime = null;
#[Assert\Ip(message: 'validators.network_settings.ip_address.invalid')]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La dirección IP de multicast',
example: '239.255.255.250'
)]
public ?string $mcastIp = null;
#[Assert\GreaterThan(0, message: 'validators.network_settings.mcast_speed.invalid')]
#[Groups(['organizational-write:write'])]
#[ApiProperty(
description: 'La velocidad de multicast en Mbps',
example: 100
)]
public ?int $mcastSpeed = null;
#[OrganizationalUnitMulticastPort]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El puerto de multicast',
example: 8000
)]
public ?int $mcastPort = null;
#[OrganizationalUnitMulticastMode]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El modo de multicast',
example: 'full'
)]
public ?string $mcastMode = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El menú de la configuración de red'
)]
public ?MenuOutput $menu = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El perfil de hardware de la configuración de red'
)]
public ?HardwareProfileOutput $hardwareProfile = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La configuración OgLive de la configuración de red'
)]
public ?OgLiveOutput $ogLive = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El repositorio de imágenes de la configuración de red'
)]
public ?ImageRepositoryOutput $repository = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La plantilla PXE de la configuración de red'
)]
public ?PxeTemplateOutput $pxeTemplate = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La ruta de ogshare',
example: '/var/ogshare'
)]
public ?string $ogshare = null;
public function __construct(?NetworkSettings $networkSettings = null)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Entity\OperativeSystem;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -10,6 +11,10 @@ class OperativeSystemInput
{
#[Assert\NotBlank(message: 'validators.operative_system.name.not_blank')]
#[Groups(['operative-system:write'])]
#[ApiProperty(
description: 'El nombre del sistema operativo',
example: 'Ubuntu 20.04 LTS'
)]
public ?string $name = null;
public function __construct(?OperativeSystem $operativeSystem = null)

View File

@ -6,9 +6,6 @@ use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Dto\Output\RemoteCalendarOutput;
use App\Entity\OrganizationalUnit;
use App\Validator\Constraints\OrganizationalUnitMulticastMode;
use App\Validator\Constraints\OrganizationalUnitMulticastPort;
use App\Validator\Constraints\OrganizationalUnitP2PMode;
use App\Validator\Constraints\OrganizationalUnitParent;
use App\Validator\Constraints\OrganizationalUnitType;
use Symfony\Component\Serializer\Annotation\Groups;
@ -19,45 +16,95 @@ class OrganizationalUnitInput
{
#[Assert\NotBlank(message: 'validators.organizational_unit.name.not_blank')]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El nombre de la unidad organizativa',
example: 'Aula 1'
)]
public ?string $name = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La unidad organizativa padre',
example: null
)]
public ?OrganizationalUnitOutput $parent = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La descripción de la unidad organizativa',
example: 'Aula de informática principal'
)]
public ?string $description = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La ubicación de la unidad organizativa',
example: 'Planta baja, edificio A'
)]
public ?string $location = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'Si tiene proyector',
example: true
)]
public ?bool $projector = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'Si tiene pizarra digital',
example: false
)]
public ?bool $board = null;
#[Assert\GreaterThan(0)]
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'La capacidad de la unidad organizativa',
example: 30
)]
public ?int $capacity = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'Comentarios adicionales',
example: 'Aula equipada con ordenadores de última generación'
)]
public ?string $comments = null;
#[Groups(['organizational-unit:write'])]
#[OrganizationalUnitType]
#[ApiProperty(
description: 'El tipo de unidad organizativa',
example: 'aula'
)]
public ?string $type = null;
#[Groups(['organizational-unit:write'])]
#[Assert\Valid()]
#[ApiProperty(
description: 'La configuración de red de la unidad organizativa'
)]
public ?NetworkSettingsInput $networkSettings = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'El calendario remoto de la unidad organizativa'
)]
public ?RemoteCalendarOutput $remoteCalendar = null;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'Si es un PC remoto',
example: false
)]
public ?bool $remotePc = false;
#[Groups(['organizational-unit:write'])]
#[ApiProperty(
description: 'Si excluir cambios del padre',
example: false
)]
public ?bool $excludeParentChanges = null;
public function __construct(?OrganizationalUnit $organizationalUnit = null)

View File

@ -3,12 +3,8 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\OperativeSystemOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\HardwareProfile;
use App\Entity\Menu;
use App\Entity\Partition;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Serializer\Annotation\Groups;

View File

@ -4,9 +4,6 @@ namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\PxeTemplateOutput;
use App\Dto\Output\SubnetOutput;
use App\Entity\PxeBootFile;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -17,5 +14,9 @@ final class SubnetAddHostInput
*/
#[Assert\NotNull]
#[Groups(['subnet:write'])]
#[ApiProperty(
description: 'Los clientes a añadir a la subred',
example: []
)]
public ?array $clients = [];
}

View File

@ -3,7 +3,7 @@
namespace App\Dto\Input;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\ImageRepositoryOutput;
use ApiPlatform\Metadata\ApiProperty;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -14,5 +14,9 @@ class TransferGlobalImageInput
*/
#[Assert\NotNull]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(
description: 'Los repositorios de destino para transferir la imagen global',
example: []
)]
public array $repositories = [];
}

View File

@ -2,6 +2,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Entity\UserGroup;
use App\Validator\Constraints\UserGroupsValidPermission;
use Symfony\Component\Serializer\Annotation\Groups;
@ -11,14 +12,26 @@ final class UserGroupInput
{
#[Assert\NotBlank]
#[Groups(['user-group:write'])]
#[ApiProperty(
description: 'El nombre del grupo de usuario',
example: 'Administradores'
)]
public ?string $name = null;
#[Groups(['user-group:write'])]
#[UserGroupsValidPermission]
#[ApiProperty(
description: 'Los permisos del grupo de usuario',
example: ['ROLE_ADMIN', 'ROLE_USER_MANAGEMENT']
)]
public ?array $permissions = [];
#[Assert\NotNull]
#[Groups(['user-group:write'])]
#[ApiProperty(
description: 'Si el grupo está habilitado',
example: true
)]
public ?bool $enabled = false;
public function __construct(?UserGroup $userGroupGroup = null)

View File

@ -15,47 +15,85 @@ final class UserInput
{
#[Assert\NotBlank]
#[Groups('user:write')]
#[ApiProperty(
description: 'El nombre de usuario',
example: 'admin'
)]
public ?string $username = null;
/**
* @var OrganizationalUnitOutput[]
*/
#[Groups('user:write')]
#[ApiProperty(readableLink: false, writableLink: false)]
#[ApiProperty(
description: 'Las unidades organizativas permitidas para el usuario',
example: [],
readableLink: false,
writableLink: false
)]
public array $allowedOrganizationalUnits = [];
#[Assert\NotBlank(groups: ['user:post'])]
#[Assert\Length(min: 8, groups: ['user:write', 'user:post'])]
#[Groups('user:write')]
#[ApiProperty(
description: 'La contraseña del usuario (mínimo 8 caracteres)',
example: 'password123'
)]
public ?string $password = null;
#[Groups('user:write')]
#[ApiProperty(
description: 'La vista por defecto de grupos para el usuario',
example: 'grid'
)]
public ?string $groupsView = null;
#[Assert\NotNull]
#[Groups('user:write')]
#[ApiProperty(
description: 'Si el usuario está habilitado',
example: true
)]
public ?bool $enabled = true;
/**
* @var UserGroupOutput[]
*/
#[Groups('user:write')]
#[ApiProperty(readableLink: false, writableLink: false)]
#[ApiProperty(
description: 'Los grupos de usuario asignados',
example: [],
readableLink: false,
writableLink: false
)]
public array $userGroups = [];
#[Assert\NotBlank(groups: ['user:reset-password'])]
#[Groups('user:reset-password')]
#[ApiProperty(
description: 'La contraseña actual del usuario',
example: 'currentpass123'
)]
public ?string $currentPassword = null;
#[Assert\NotBlank(groups: ['user:reset-password'])]
#[Assert\Length(min: 8, groups: ['user:reset-password'])]
#[Groups('user:reset-password')]
#[ApiProperty(
description: 'La nueva contraseña del usuario (mínimo 8 caracteres)',
example: 'newpass123'
)]
public ?string $newPassword = null;
#[Assert\NotBlank(groups: ['user:reset-password'])]
#[Assert\Length(min: 8, groups: ['user:reset-password'])]
#[Assert\Expression(expression: 'this.newPassword === this.repeatNewPassword', message: 'This value should be the same as the new password', groups: ['user:reset-password'])]
#[Groups('user:reset-password')]
#[ApiProperty(
description: 'Repetir la nueva contraseña para confirmación',
example: 'newpass123'
)]
public ?string $repeatNewPassword = null;
public function __construct(?User $user = null)

View File

@ -12,6 +12,9 @@ class WoLInput
* @var ClientOutput[]|null
*/
#[Groups(['repository:write'])]
#[ApiProperty(description: 'The client to wol')]
#[ApiProperty(
description: 'Los clientes para Wake on LAN',
example: []
)]
public ?array $clients = null;
}

View File

@ -14,70 +14,150 @@ final class ClientOutput extends AbstractOutput
CONST string TYPE = 'client';
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])]
#[ApiProperty(
description: 'El nombre del cliente',
example: 'PC-Aula-01'
)]
public string $name;
#[Groups(['client:read', 'organizational-unit:read'])]
#[ApiProperty(
description: 'El tipo de entidad',
example: 'client'
)]
public string $type = self::TYPE;
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])]
#[ApiProperty(
description: 'La dirección IP del cliente',
example: '192.168.1.100'
)]
public ?string $ip = '';
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])]
#[ApiProperty(
description: 'La dirección MAC del cliente',
example: '00:1A:2B:3C:4D:5E'
)]
public ?string $mac = '';
#[Groups(['client:read'])]
#[ApiProperty(
description: 'El tipo de firmware (BIOS/UEFI)',
example: 'UEFI'
)]
public ?string $firmwareType = '';
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
#[ApiProperty(
description: 'El número de serie del cliente',
example: 'SN123456789'
)]
public ?string $serialNumber = '';
#[Groups(['client:read'])]
#[ApiProperty(
description: 'La interfaz de red',
example: 'eth0'
)]
public ?string $netiface = '';
#[Groups(['client:read'])]
#[ApiProperty(
description: 'El controlador de red',
example: 'e1000'
)]
public ?string $netDriver = '';
#[Groups(['client:read'])]
#[ApiProperty(readableLink: true)]
#[ApiProperty(
description: 'La unidad organizativa a la que pertenece el cliente',
readableLink: true
)]
public ?OrganizationalUnitOutput $organizationalUnit = null;
#[Groups(['client:read'])]
#[ApiProperty(
description: 'Las particiones del disco del cliente',
example: []
)]
public array $partitions = [];
#[Groups(['client:read'])]
#[ApiProperty(
description: 'El menú de arranque asignado al cliente',
example: null
)]
public ?MenuOutput $menu = null;
#[Groups(['client:read'])]
#[ApiProperty(readableLink: true )]
#[ApiProperty(
description: 'El repositorio de imágenes asignado al cliente',
readableLink: true
)]
public ?ImageRepositoryOutput $repository = null;
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
#[ApiProperty(readableLink: true )]
#[ApiProperty(
description: 'La plantilla PXE asignada al cliente',
readableLink: true
)]
public ?PxeTemplateOutput $pxeTemplate = null;
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
#[ApiProperty(readableLink: true )]
#[ApiProperty(
description: 'La imagen OGLive asignada al cliente',
readableLink: true
)]
public ?OgLiveOutput $ogLive = null;
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
#[ApiProperty(
description: 'La subred del cliente en formato CIDR',
example: '192.168.1.0/24'
)]
public ?string $subnet = null;
#[Groups(['client:read', 'organizational-unit:read'])]
#[ApiProperty(
description: 'La posición del cliente en la interfaz gráfica',
example: ['x' => 100, 'y' => 200]
)]
public ?array $position = ['x' => 0, 'y' => 0];
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
#[ApiProperty(
description: 'El estado actual del cliente',
example: 'online'
)]
public ?string $status = '';
#[Groups(['client:read'])]
#[ApiProperty(
description: 'Fecha de creación del cliente',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['client:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
#[ApiProperty(
description: 'Indica si el cliente está en modo mantenimiento',
example: false
)]
public ?bool $maintenance = false;
#[Groups(['client:read'])]
#[ApiProperty(
description: 'Indica si la configuración PXE está sincronizada',
example: true
)]
public ?bool $pxeSync = false;
public function __construct(Client $client)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\Command;
use App\Entity\CommandGroup;
@ -11,15 +12,31 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class CommandGroupOutput extends AbstractOutput
{
#[Groups(['command-group:read', 'command-task:read'])]
#[ApiProperty(
description: 'El nombre del grupo de comandos',
example: 'Comandos de sistema'
)]
public string $name;
#[Groups(['command-group:read', 'command-task:read'])]
#[ApiProperty(
description: 'Los comandos incluidos en el grupo',
example: []
)]
public array $commands = [];
#[Groups(['command-group:read'])]
#[ApiProperty(
description: 'Fecha de creación del grupo de comandos',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['command-group:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(CommandGroup $commandGroup)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\Command;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,27 +11,59 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class CommandOutput extends AbstractOutput
{
#[Groups(['command:read', 'command-group:read', 'command-task:read', 'trace:read'])]
#[ApiProperty(
description: 'El nombre del comando',
example: 'Reiniciar sistema'
)]
public string $name;
#[Groups(['command:read', 'command-group:read', 'command-task:read', 'trace:read'])]
#[ApiProperty(
description: 'El script del comando',
example: 'reboot'
)]
public ?string $script = '';
#[Groups(['command:read'])]
#[ApiProperty(
description: 'Indica si el comando es de solo lectura',
example: false
)]
public ?bool $readOnly = false;
#[Groups(['command:read'])]
#[ApiProperty(
description: 'Indica si el comando está habilitado',
example: true
)]
public ?bool $enabled = true;
#[Groups(['command:read'])]
#[ApiProperty(
description: 'Indica si el comando acepta parámetros',
example: true
)]
public ?bool $parameters = true;
#[Groups(['command:read'])]
#[ApiProperty(
description: 'Comentarios sobre el comando',
example: 'Reinicia el equipo de forma controlada'
)]
public ?string $comments = '';
#[Groups(['command:read'])]
#[ApiProperty(
description: 'Fecha de creación del comando',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['command:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(Command $command)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\Client;
use App\Entity\Command;
@ -13,30 +14,66 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class CommandTaskOutput extends AbstractOutput
{
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'El nombre de la tarea de comando',
example: 'Actualización nocturna'
)]
public ?string $name = null;
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'Los clientes asignados a la tarea',
example: []
)]
public array $clients = [];
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'La unidad organizativa asociada a la tarea',
example: null
)]
public ?OrganizationalUnitOutput $organizationalUnit = null;
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'Fecha de la última ejecución',
example: '2024-01-15T02:00:00+00:00'
)]
public ?\DateTimeInterface $lastExecution = null;
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'Fecha de la próxima ejecución programada',
example: '2024-01-16T02:00:00+00:00'
)]
public ?\DateTimeInterface $nextExecution = null;
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'Notas adicionales sobre la tarea',
example: 'Ejecutar fuera del horario escolar'
)]
public ?string $notes = null;
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'El alcance de la tarea',
example: 'clients'
)]
public ?string $scope = null;
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'Fecha de creación de la tarea',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['command-task:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\CommandTaskSchedule;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,18 +11,38 @@ use Symfony\Component\Serializer\Annotation\Groups;
class CommandTaskScheduleOutput extends AbstractOutput
{
#[Groups(['command-task-schedule:read'])]
#[ApiProperty(
description: 'El tipo de recurrencia de la programación',
example: 'weekly'
)]
public ?string $recurrenceType = null;
#[Groups(['command-task-schedule:read'])]
#[ApiProperty(
description: 'La fecha de ejecución programada',
example: '2024-01-20T00:00:00+00:00'
)]
public ?\DateTimeInterface $executionDate = null;
#[Groups(['command-task-schedule:read'])]
#[ApiProperty(
description: 'La hora de ejecución programada',
example: '2024-01-15T02:00:00+00:00'
)]
public ?\DateTimeInterface $executionTime = null;
#[Groups(['command-task-schedule:read'])]
#[ApiProperty(
description: 'Los detalles de la recurrencia',
example: ['days' => ['monday', 'wednesday', 'friday']]
)]
public ?array $recurrenceDetails = null;
#[Groups(['command-task-schedule:read'])]
#[ApiProperty(
description: 'Indica si la programación está habilitada',
example: true
)]
public ?bool $enabled = null;
public function __construct(?CommandTaskSchedule $commandTaskSchedule = null)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\CommandTaskSchedule;
use App\Entity\CommandTaskScript;
@ -11,18 +12,38 @@ use Symfony\Component\Serializer\Annotation\Groups;
class CommandTaskScriptOutput extends AbstractOutput
{
#[Groups(['command-task-script:read'])]
#[ApiProperty(
description: 'El contenido del script',
example: '#!/bin/bash\necho "Hello World"'
)]
public ?string $content = null;
#[Groups(['command-task-script:read'])]
#[ApiProperty(
description: 'El tipo de script',
example: 'bash'
)]
public ?string $type = null;
#[Groups(['command-task-script:read'])]
#[ApiProperty(
description: 'Los parámetros del script',
example: []
)]
public ?array $parameters = null;
#[Groups(['command-task-script:read'])]
#[ApiProperty(
description: 'La tarea de comando asociada',
example: null
)]
public ?CommandTaskOutput $commandTaskOutput = null;
#[Groups(['command-task-script:read'])]
#[ApiProperty(
description: 'El orden de ejecución del script',
example: 1
)]
public ?int $order = null;
public function __construct(?CommandTaskScript $commandTaskScript = null)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\GitRepository;
use Symfony\Component\Serializer\Annotation\Groups;
@ -22,6 +23,10 @@ final class GitRepositoryOutput
* )
*/
#[Groups(['git-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'El UUID del repositorio Git',
example: '123e4567-e89b-12d3-a456-426614174000'
)]
public string $uuid = '';
/**
@ -31,6 +36,10 @@ final class GitRepositoryOutput
* )
*/
#[Groups(['git-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'El ID del repositorio Git',
example: 1
)]
public int $id = 0;
/**
@ -40,6 +49,10 @@ final class GitRepositoryOutput
* )
*/
#[Groups(['git-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'El nombre del repositorio Git',
example: 'mi-repositorio'
)]
public string $name = '';
/**
@ -49,6 +62,10 @@ final class GitRepositoryOutput
* )
*/
#[Groups(['git-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'La descripción del repositorio',
example: 'Repositorio para el proyecto principal'
)]
public ?string $description = '';
/**
@ -58,6 +75,10 @@ final class GitRepositoryOutput
* )
*/
#[Groups(['git-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'El servidor donde se encuentra el repositorio',
example: null
)]
public ?ImageRepositoryOutput $repository = null;
/**
@ -67,6 +88,10 @@ final class GitRepositoryOutput
* )
*/
#[Groups(['git-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'Fecha de creación del repositorio',
example: '2024-01-01T00:00:00+00:00'
)]
public ?\DateTime $createdAt = null;
/**
@ -76,6 +101,10 @@ final class GitRepositoryOutput
* )
*/
#[Groups(['git-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(GitRepository $gitRepository, array $context = [])

View File

@ -11,19 +11,38 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class HardwareOutput extends AbstractOutput
{
#[Groups(['hardware:read', 'hardware-profile:read'])]
#[ApiProperty(
description: 'El nombre del componente de hardware',
example: 'Intel Core i7-9700K'
)]
public string $name;
#[Groups(['hardware:read'])]
#[ApiProperty(
description: 'La descripción del componente de hardware',
example: 'Procesador de 8 núcleos a 3.6GHz'
)]
public ?string $description = '';
#[Groups(['hardware:read'])]
#[ApiProperty(readableLink: true)]
#[ApiProperty(
description: 'El tipo de hardware',
readableLink: true
)]
public ?HardwareTypeOutput $type = null;
#[Groups(['hardware:read'])]
#[ApiProperty(
description: 'Fecha de creación del componente de hardware',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['hardware:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(Hardware $hardware)

View File

@ -12,21 +12,45 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class HardwareProfileOutput extends AbstractOutput
{
#[Groups(['hardware-profile:read', 'client:read'])]
#[ApiProperty(
description: 'La descripción del perfil de hardware',
example: 'Perfil de hardware estándar para aula de informática'
)]
public ?string $description = '';
#[Groups(['hardware-profile:read'])]
#[ApiProperty(
description: 'Comentarios adicionales sobre el perfil',
example: 'Configuración actualizada en enero 2024'
)]
public ?string $comments = '';
#[Groups(['hardware-profile:read'])]
#[ApiProperty(
description: 'El cliente asociado a este perfil de hardware',
example: null
)]
public ?ClientOutput $client = null;
#[Groups(['hardware-profile:read'])]
#[ApiProperty(
description: 'La colección de componentes de hardware',
example: []
)]
public ?array $hardwareCollection = [];
#[Groups(['hardware-profile:read'])]
#[ApiProperty(
description: 'Fecha de creación del perfil de hardware',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['hardware-profile:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(HardwareProfile $hardwareProfile)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\HardwareType;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,15 +11,31 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class HardwareTypeOutput extends AbstractOutput
{
#[Groups(['hardware-type:read', 'hardware:read'])]
#[ApiProperty(
description: 'El nombre del tipo de hardware',
example: 'Tarjeta de red'
)]
public string $name;
#[Groups(['hardware-type:read', 'hardware:read'])]
#[ApiProperty(
description: 'La descripción del tipo de hardware',
example: 'Dispositivo de red Ethernet'
)]
public ?string $description = null;
#[Groups(['hardware-type:read', 'hardware:read'])]
#[ApiProperty(
description: 'El código del tipo de hardware',
example: 'NET'
)]
public ?string $code = null;
#[Groups(['hardware-type:read', 'hardware:read'])]
#[ApiProperty(
description: 'Fecha de creación del tipo de hardware',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
public function __construct(HardwareType $hardwareType)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\ImageImageRepository;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,36 +11,80 @@ use Symfony\Component\Serializer\Annotation\Groups;
class ImageImageRepositoryOutput extends AbstractOutput
{
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'La imagen asociada',
example: null
)]
public ?ImageOutput $image = null;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'El repositorio donde está almacenada la imagen',
example: null
)]
public ?ImageRepositoryOutput $imageRepository = null;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'El estado de la imagen en el repositorio',
example: 'synchronized'
)]
public string $status;
#[Groups(['image-image-repository:read', 'image:read', 'partition:read', 'client:read'])]
#[ApiProperty(
description: 'El nombre de la imagen',
example: 'Windows10-v1'
)]
public string $name;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'La suma de verificación completa de la imagen',
example: 'a1b2c3d4e5f6...'
)]
public ?string $imageFullsum = null;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'Información sobre las particiones de la imagen',
example: []
)]
public ?array $partitionInfo = null;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'El tamaño de los datos en bytes',
example: '10737418240'
)]
public ?string $datasize = null;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'La descripción de la imagen',
example: 'Imagen base de Windows 10 actualizado'
)]
public ?string $description = null;
#[Groups(['image:read', 'image-image-repository:read'])]
#[ApiProperty(
description: 'La versión de la imagen',
example: 1
)]
public ?int $version = null;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'Fecha de creación de la relación imagen-repositorio',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['image-image-repository:read', 'image:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(ImageImageRepository $imageImageRepository, array $context = [])

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
@ -13,35 +14,76 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class ImageOutput extends AbstractOutput
{
#[Groups(['image:read', 'image-image-repository:read', 'git-image-repository:read'])]
#[ApiProperty(
description: 'El nombre de la imagen',
example: 'Windows 10 Pro'
)]
public ?string $name = '';
#[Groups(['image:read', 'image-image-repository:read'])]
#[ApiProperty(
description: 'Indica si es una imagen de PC remoto',
example: false
)]
public ?bool $remotePc = null;
#[Groups(['image:read', 'image-image-repository:read'])]
#[ApiProperty(
description: 'Indica si la imagen es global',
example: true
)]
public ?bool $isGlobal = null;
#[Groups(['image:read', 'image-image-repository:read'])]
#[ApiProperty(
description: 'El tipo de imagen',
example: 'basic'
)]
public ?string $type = '';
#[Groups(['image:read'])]
#[ApiProperty(
description: 'El perfil de software asociado a la imagen',
example: null
)]
public ?SoftwareProfileOutput $softwareProfile = null;
/**
* @var ImageRepositoryOutput[]|null
*/
#[Groups(['image:read'])]
#[ApiProperty(
description: 'Los repositorios donde está almacenada la imagen',
example: []
)]
public ?array $imageRepositories = [];
#[Groups(['image:read'])]
#[ApiProperty(
description: 'Información sobre las particiones de la imagen',
example: []
)]
public ?array $partitionInfo = null;
#[Groups(['image:read', 'image-image-repository:read'])]
#[ApiProperty(
description: 'La versión de la imagen',
example: 1
)]
public ?int $version = null;
#[Groups(['image:read'])]
#[ApiProperty(
description: 'Fecha de creación de la imagen',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['image:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(Image $image)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\ImageRepository;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,24 +11,52 @@ use Symfony\Component\Serializer\Annotation\Groups;
class ImageRepositoryOutput extends AbstractOutput
{
#[Groups(['repository:read', 'image:read', 'client:read', "organizational-unit:read", "image-image-repository:read"])]
#[ApiProperty(
description: 'El nombre del repositorio de imágenes',
example: 'Repositorio Principal'
)]
public ?string $name = '';
#[Groups(['repository:read'])]
#[ApiProperty(
description: 'La dirección IP del servidor del repositorio',
example: '192.168.1.50'
)]
public ?string $ip = '';
#[Groups(['repository:read'])]
#[ApiProperty(
description: 'Comentarios sobre el repositorio',
example: 'Servidor principal de almacenamiento de imágenes'
)]
public ?string $comments = '';
#[Groups(['repository:read'])]
#[ApiProperty(
description: 'El puerto SSH del servidor',
example: '22'
)]
public ?string $sshPort = '';
#[Groups(['repository:read'])]
#[ApiProperty(
description: 'El usuario SSH para acceder al repositorio',
example: 'opengnsys'
)]
public ?string $user = '';
#[Groups(['repository:read'])]
#[ApiProperty(
description: 'Fecha de creación del repositorio',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['repository:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(ImageRepository $imageRepository, bool $status = true)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\HardwareProfile;
use App\Entity\Menu;
@ -11,27 +12,59 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class MenuOutput extends AbstractOutput
{
#[Groups(['menu:read', 'organizational-unit:read'])]
#[ApiProperty(
description: 'El nombre del menú de arranque',
example: 'Menú Principal'
)]
public string $name;
#[Groups(['menu:read'])]
#[ApiProperty(
description: 'La resolución del menú',
example: '1024x768'
)]
public string $resolution;
#[Groups(['menu:read'])]
#[ApiProperty(
description: 'Comentarios sobre el menú',
example: 'Menú de arranque predeterminado para todas las aulas'
)]
public ?string $comments = null;
#[Groups(['menu:read'])]
#[ApiProperty(
description: 'URL pública del menú',
example: 'https://example.com/menu/public'
)]
public ?string $publicUrl = null;
#[Groups(['menu:read'])]
#[ApiProperty(
description: 'URL privada del menú',
example: 'https://example.com/menu/private'
)]
public ?string $privateUrl = null;
#[Groups(['menu:read'])]
#[ApiProperty(
description: 'Indica si es el menú predeterminado',
example: true
)]
public ?bool $isDefault = false;
#[Groups(['menu:read'])]
#[ApiProperty(
description: 'Fecha de creación del menú',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['menu:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(Menu $menu)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\NetworkSettings;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,69 +11,157 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class NetworkSettingsOutput extends AbstractOutput
{
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La dirección del servidor TFTP siguiente',
example: '192.168.1.10'
)]
public ?string $nextServer = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'El nombre del archivo de arranque',
example: 'pxelinux.0'
)]
public ?string $bootFileName = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La dirección del servidor proxy',
example: 'http://proxy.example.com:8080'
)]
public ?string $proxy = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La dirección del servidor DNS',
example: '8.8.8.8'
)]
public ?string $dns = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La máscara de subred',
example: '255.255.255.0'
)]
public ?string $netmask = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La dirección del router/gateway',
example: '192.168.1.1'
)]
public ?string $router = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La dirección del servidor NTP',
example: 'time.google.com'
)]
public ?string $ntp = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La interfaz de red',
example: 'eth0'
)]
public ?string $netiface = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'El modo de transferencia punto a punto',
example: 'full'
)]
public ?string $p2pMode = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'Tiempo de transferencia P2P en segundos',
example: 300
)]
public ?int $p2pTime = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La dirección IP multicast',
example: '239.194.2.11'
)]
public ?string $mcastIp = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La velocidad multicast en Mbps',
example: 100
)]
public ?int $mcastSpeed = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'El puerto multicast',
example: 9000
)]
public ?int $mcastPort = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'El modo multicast',
example: 'full-duplex'
)]
public ?string $mcastMode = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'El menú de arranque configurado',
example: null
)]
public ?MenuOutput $menu = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'El perfil de hardware configurado',
example: null
)]
public ?HardwareProfileOutput $hardwareProfile = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La imagen OGLive configurada',
example: null
)]
public ?OgLiveOutput $ogLive = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'El repositorio de imágenes configurado',
example: null
)]
public ?ImageRepositoryOutput $repository = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La plantilla PXE configurada',
example: null
)]
public ?PxeTemplateOutput $pxeTemplate = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
#[ApiProperty(
description: 'La ruta compartida de OGAgent',
example: '/opt/opengnsys/ogshare'
)]
public ?string $ogshare = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Fecha de creación de la configuración de red',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(NetworkSettings $networkSettings)

View File

@ -11,48 +11,108 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class OgLiveOutput extends AbstractOutput
{
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
#[ApiProperty(
description: 'El nombre de la imagen OGLive',
example: 'ogLive-5.2.0'
)]
public ?string $name = '';
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'Indica si la imagen está sincronizada',
example: true
)]
public ?bool $synchronized = false;
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'Indica si la imagen está instalada',
example: true
)]
public ?bool $installed = false;
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'Indica si es la imagen OGLive predeterminada',
example: true
)]
public ?bool $isDefault = false;
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'URL de descarga de la imagen',
example: 'https://opengnsys.es/svn/branches/version1.1/installer/ogLive-5.2.0-r6374.iso'
)]
public ?string $downloadUrl = '';
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'El estado de la imagen',
example: 'synchronized'
)]
public ?string $status = '';
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'Suma de verificación de la imagen',
example: 'a1b2c3d4e5f6...'
)]
public ?string $checksum = '';
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'La distribución de Linux',
example: 'Ubuntu'
)]
public ?string $distribution = '';
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'La revisión de la imagen',
example: 'r6374'
)]
public ?string $revision = '';
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
#[ApiProperty(
description: 'El nombre del archivo de la imagen',
example: 'ogLive-5.2.0-r6374.iso'
)]
public ?string $filename = null;
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
#[ApiProperty(
description: 'La versión del kernel',
example: '5.4.0-42-generic'
)]
public ?string $kernel = '';
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'La arquitectura del sistema',
example: 'amd64'
)]
public ?string $architecture = '';
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'Fecha de creación del registro',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
#[ApiProperty(
description: 'Fecha de la imagen',
example: '2024-01-10T00:00:00+00:00'
)]
public ?\DateTimeInterface $date;
#[Groups(['og-live:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(OgLive $ogLive)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\OperativeSystem;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,12 +11,24 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class OperativeSystemOutput extends AbstractOutput
{
#[Groups(['operative-system:read', 'partition:read', 'software-profile:read', 'client:read'])]
#[ApiProperty(
description: 'El nombre del sistema operativo',
example: 'Windows 10 Pro'
)]
public string $name;
#[Groups(['operative-system:read'])]
#[ApiProperty(
description: 'Fecha de creación del sistema operativo',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['operative-system:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(OperativeSystem $operativeSystem)

View File

@ -12,59 +12,129 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class OrganizationalUnitOutput extends AbstractOutput
{
#[Groups(['organizational-unit:read', "client:read", "user:read", 'organizational-unit:read:collection:short', 'software-profile:read', 'command-task:read'])]
#[ApiProperty(
description: 'El nombre de la unidad organizativa',
example: 'Aula 1'
)]
public string $name;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Comentarios adicionales',
example: 'Aula de informática equipada con 30 equipos'
)]
public ?string $comments = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'La descripción de la unidad organizativa',
example: 'Aula de informática principal'
)]
public ?string $description = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'La ubicación física',
example: 'Planta baja, edificio A'
)]
public ?string $location = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Indica si tiene proyector',
example: true
)]
public ?bool $projector = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Indica si tiene pizarra digital',
example: false
)]
public ?bool $board = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'La capacidad de la unidad organizativa',
example: 30
)]
public ?int $capacity = null;
#[Groups(['organizational-unit:read', "client:read"])]
#[ApiProperty(
description: 'El tipo de unidad organizativa',
example: 'aula'
)]
public string $type;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'La unidad organizativa padre',
example: null
)]
public ?self $parent = null;
#[Groups(['organizational-unit:read', 'client:read', 'organizational-unit:read:collection:short'])]
#[ApiProperty(
description: 'La ruta completa de la unidad organizativa',
example: '/Edificio A/Planta Baja/Aula 1'
)]
public string $path;
#[Groups(['organizational-unit:read', "client:read"])]
#[ApiProperty(readableLink: true)]
#[ApiProperty(
description: 'La configuración de red de la unidad organizativa',
readableLink: true
)]
public ?NetworkSettingsOutput $networkSettings = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Las unidades organizativas hijas',
example: []
)]
public array $children = [];
#[Groups(['organizational-unit:read', "client:read"])]
#[ApiProperty(readableLink: true)]
#[ApiProperty(
description: 'El calendario remoto asociado',
readableLink: true
)]
public ?RemoteCalendarOutput $remoteCalendar = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Indica si es un PC remoto',
example: false
)]
public ?bool $remotePc = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Indica si está disponible según el calendario',
example: true
)]
public ?bool $available = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Indica si excluye cambios del padre',
example: false
)]
public ?bool $excludeParentChanges = null;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Fecha de creación de la unidad organizativa',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['organizational-unit:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(OrganizationalUnit $organizationalUnit, array $context = [])

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\ImageImageRepository;
use App\Entity\Partition;
@ -11,30 +12,66 @@ use Symfony\Component\Serializer\Annotation\Groups;
class PartitionOutput extends AbstractOutput
{
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El número del disco',
example: 1
)]
public ?int $diskNumber = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El número de la partición',
example: 1
)]
public ?int $partitionNumber = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El código del tipo de partición',
example: '83'
)]
public ?string $partitionCode = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El tamaño de la partición en MB',
example: 51200
)]
public ?int $size = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El contenido de la caché',
example: 'system'
)]
public ?string $cacheContent = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El sistema de archivos',
example: 'ext4'
)]
public ?string $filesystem = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El sistema operativo instalado en la partición',
example: null
)]
public ?OperativeSystemOutput $operativeSystem = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'La imagen asociada a la partición',
example: null
)]
public ?ImageImageRepositoryOutput $image = null;
#[Groups(['partition:read', 'client:read'])]
#[ApiProperty(
description: 'El porcentaje de uso de memoria',
example: 45
)]
public ?int $memoryUsage = null;
public function __construct(Partition $partition)

View File

@ -12,24 +12,52 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class PxeTemplateOutput extends AbstractOutput
{
#[Groups(['pxe-template:read', 'client:read', 'organizational-unit:read'])]
#[ApiProperty(
description: 'El nombre de la plantilla PXE',
example: 'Plantilla BIOS'
)]
public string $name;
#[Groups(['pxe-template:read'])]
#[ApiProperty(
description: 'Indica si la plantilla está sincronizada',
example: true
)]
public ?bool $synchronized = null;
#[Groups(['pxe-template:read'])]
#[ApiProperty(
description: 'El contenido de la plantilla PXE',
example: 'DEFAULT ogLive\nPROMPT 0\nTIMEOUT 0...'
)]
public ?string $templateContent = '';
#[Groups(['pxe-template:read'])]
#[ApiProperty(
description: 'Indica si es la plantilla predeterminada',
example: true
)]
public ?bool $isDefault = null;
#[Groups(['pxe-template:read'])]
#[ApiProperty(
description: 'El número de clientes que usan esta plantilla',
example: 15
)]
public ?int $clientsLength = 0;
#[Groups(['pxe-template:read'])]
#[ApiProperty(
description: 'Fecha de creación de la plantilla',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['pxe-template:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(PxeTemplate $pxeTemplate)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\RemoteCalendar;
use App\Entity\RemoteCalendarRule;
@ -11,15 +12,27 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class RemoteCalendarOutput extends AbstractOutput
{
#[Groups(['remote-calendar:read', 'organizational-unit:read'])]
#[ApiProperty(
description: 'El nombre del calendario remoto',
example: 'Horario Escolar'
)]
public ?string $name = null;
/**
* @var RemoteCalendarRuleOutput[]
*/
#[Groups(['remote-calendar:read'])]
#[ApiProperty(
description: 'Las reglas del calendario remoto',
example: []
)]
public array $remoteCalendarRules = [];
#[Groups(['remote-calendar:read'])]
#[ApiProperty(
description: 'Fecha de creación del calendario',
example: '2024-01-15T10:30:00+00:00'
)]
public ?\DateTimeInterface $createdAt = null;
public function __construct(RemoteCalendar $remoteCalendar)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\RemoteCalendarRule;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,24 +11,52 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class RemoteCalendarRuleOutput extends AbstractOutput
{
#[Groups(['remote-calendar-rule:read', 'remote-calendar:read'])]
#[ApiProperty(
description: 'Los días de la semana ocupados',
example: ['monday', 'wednesday', 'friday']
)]
public ?array $busyWeekDays = null;
#[Groups(['remote-calendar-rule:read', 'remote-calendar:read'])]
#[ApiProperty(
description: 'Hora de inicio del periodo ocupado',
example: '08:00'
)]
public ?string $busyFromHour = null;
#[Groups(['remote-calendar-rule:read', 'remote-calendar:read'])]
#[ApiProperty(
description: 'Hora de fin del periodo ocupado',
example: '14:00'
)]
public ?string $busyToHour = null;
#[Groups(['remote-calendar-rule:read', 'remote-calendar:read'])]
#[ApiProperty(
description: 'Indica si está disponible para acceso remoto',
example: true
)]
public ?bool $isRemoteAvailable = false;
#[Groups(['remote-calendar-rule:read', 'remote-calendar:read'])]
#[ApiProperty(
description: 'Fecha desde la que está disponible',
example: '2024-01-15T00:00:00+00:00'
)]
public ?\DateTimeInterface $availableFromDate = null;
#[Groups(['remote-calendar-rule:read', 'remote-calendar:read'])]
#[ApiProperty(
description: 'Fecha hasta la que está disponible',
example: '2024-06-30T23:59:59+00:00'
)]
public ?\DateTimeInterface $availableToDate = null;
#[Groups(['remote-calendar-rule:read', 'remote-calendar:read'])]
#[ApiProperty(
description: 'El motivo de la disponibilidad',
example: 'Periodo lectivo'
)]
public ?string $availableReason = null;
public function __construct(RemoteCalendarRule $remoteCalendarRule)

View File

@ -11,18 +11,38 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class SoftwareOutput extends AbstractOutput
{
#[Groups(['software:read', 'software-profile:read'])]
#[ApiProperty(
description: 'El nombre del software',
example: 'Microsoft Office 2019'
)]
public string $name;
#[Groups(['software:read'])]
#[ApiProperty(
description: 'La descripción del software',
example: 'Suite de oficina completa'
)]
public ?string $description = '';
#[Groups(['software:read', 'software-profile:read'])]
#[ApiProperty(
description: 'El tipo de software',
example: 'productivity'
)]
public ?string $type = '';
#[Groups(['software:read'])]
#[ApiProperty(
description: 'Fecha de creación del software',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['software:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(Software $software)

View File

@ -12,24 +12,52 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class SoftwareProfileOutput extends AbstractOutput
{
#[Groups(['software-profile:read', 'image:read'])]
#[ApiProperty(
description: 'La descripción del perfil de software',
example: 'Perfil estándar para aula de informática'
)]
public ?string $description = '';
#[Groups(['software-profile:read'])]
#[ApiProperty(
description: 'Comentarios adicionales sobre el perfil',
example: 'Incluye software educativo básico'
)]
public ?string $comments = '';
#[Groups(['software-profile:read'])]
#[ApiProperty(
description: 'La unidad organizativa asociada',
example: null
)]
public ?OrganizationalUnitOutput $organizationalUnit = null;
#[Groups(['software-profile:read'])]
#[ApiProperty(
description: 'El sistema operativo base del perfil',
example: null
)]
public ?OperativeSystemOutput $operativeSystem = null;
#[Groups(['software-profile:item:get'])]
#[ApiProperty(
description: 'La colección de software incluido en el perfil',
example: []
)]
public ?array $softwareCollection = [];
#[Groups(['software-profile:read'])]
#[ApiProperty(
description: 'Fecha de creación del perfil de software',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['software-profile:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(SoftwareProfile $softwareProfile)

View File

@ -13,36 +13,80 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class SubnetOutput extends AbstractOutput
{
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'El nombre de la subred',
example: 'Subred Principal'
)]
public string $name;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'La máscara de subred',
example: '255.255.255.0'
)]
public string $netmask;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'La dirección IP de la subred',
example: '192.168.1.0'
)]
public string $ipAddress;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'La dirección del servidor TFTP siguiente',
example: '192.168.1.10'
)]
public ?string $nextServer = null;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'El nombre del archivo de arranque',
example: 'pxelinux.0'
)]
public ?string $bootFileName = null;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'La dirección del router/gateway',
example: '192.168.1.1'
)]
public ?string $router = null;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'La dirección del servidor DNS',
example: '8.8.8.8'
)]
public ?string $dns = null;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'Indica si la subred está sincronizada',
example: true
)]
public ?bool $synchronized = false;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'El ID del servidor DHCP',
example: 1
)]
public ?int $serverId;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'Fecha de creación de la subred',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['subnet:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(Subnet $subnet)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\Menu;
use App\Entity\Trace;
@ -11,36 +12,80 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class TraceOutput extends AbstractOutput
{
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'El comando ejecutado',
example: 'Reiniciar sistema'
)]
public ?string $command;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'El cliente sobre el que se ejecutó el comando',
example: null
)]
public ?ClientOutput $client = null;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'El estado de la traza',
example: 'completed'
)]
public string $status;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'El ID del trabajo asociado',
example: 'job-12345'
)]
public ?string $jobId = null;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'Fecha de ejecución del comando',
example: '2024-01-15T10:30:00+00:00'
)]
public ?\DateTimeInterface $executedAt = null;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'La salida del comando ejecutado',
example: 'Sistema reiniciado correctamente'
)]
public ?string $output = null;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'Los parámetros de entrada del comando',
example: []
)]
public ?array $input = null;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'Fecha de finalización del comando',
example: '2024-01-15T10:31:00+00:00'
)]
public ?\DateTimeInterface $finishedAt = null;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'El progreso de ejecución (0.0 a 1.0)',
example: 1.0
)]
public ?float $progress = null;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'Fecha de creación de la traza',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['trace:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(Trace $trace)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\User;
use App\Entity\UserGroup;
@ -11,18 +12,38 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class UserGroupOutput extends AbstractOutput
{
#[Groups(['user-group:read', 'user:read'])]
#[ApiProperty(
description: 'El nombre del grupo de usuarios',
example: 'Administradores'
)]
public string $name;
#[Groups(['user-group:read'])]
#[ApiProperty(
description: 'Los permisos asignados al grupo',
example: ['clients.read', 'clients.write', 'images.read']
)]
public array $permissions;
#[Groups(['user-group:read'])]
#[ApiProperty(
description: 'Indica si el grupo está habilitado',
example: true
)]
public bool $enabled;
#[Groups(['user-group:read'])]
#[ApiProperty(
description: 'Fecha de creación del grupo de usuarios',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['user-group:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(UserGroup $userGroup)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
@ -12,24 +13,59 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class UserOutput extends AbstractOutput
{
#[Groups(['user:read'])]
#[ApiProperty(
description: 'El nombre de usuario',
example: 'admin'
)]
public string $username;
#[Groups(['user:read'])]
#[ApiProperty(
description: 'Los roles asignados al usuario',
example: ['ROLE_USER', 'ROLE_ADMIN']
)]
public array $roles;
#[Groups(['user:read'])]
#[ApiProperty(
description: 'Indica si el usuario está habilitado',
example: true
)]
public bool $enabled;
#[Groups(['user:read'])]
#[ApiProperty(
description: 'Las unidades organizativas permitidas para el usuario',
example: []
)]
public array $allowedOrganizationalUnits;
#[Groups(['user:read'])]
#[ApiProperty(
description: 'Los grupos de usuario asignados',
example: []
)]
public array $userGroups;
#[Groups(['user:read'])]
#[ApiProperty(
description: 'La vista por defecto de grupos para el usuario',
example: 'card'
)]
public ?string $groupsView = 'card';
#[Groups(['user:read'])]
#[ApiProperty(
description: 'Fecha de creación del usuario',
example: '2024-01-15T10:30:00+00:00'
)]
public \DateTime $createdAt;
#[Groups(['user:read'])]
#[ApiProperty(
description: 'Usuario que creó este registro',
example: 'admin'
)]
public ?string $createdBy = null;
public function __construct(User $user)

View File

@ -2,6 +2,7 @@
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\View;
use Symfony\Component\Serializer\Annotation\Groups;
@ -10,12 +11,24 @@ use Symfony\Component\Serializer\Annotation\Groups;
final class ViewOutput extends AbstractOutput
{
#[Groups(['view:read'])]
#[ApiProperty(
description: 'El nombre de la vista',
example: 'Mi Vista Personalizada'
)]
public string $name;
#[Groups(['view:read'])]
#[ApiProperty(
description: 'Indica si es una vista favorita',
example: true
)]
public bool $favorite;
#[Groups(['view:read'])]
#[ApiProperty(
description: 'Los filtros aplicados en la vista',
example: []
)]
public ?array $filters = null;
public function __construct(View $view)

View File

@ -3,6 +3,7 @@
namespace App\Factory;
use App\Entity\Client;
use App\Model\OrganizationalUnitTypes;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
@ -33,6 +34,7 @@ final class ClientFactory extends ModelFactory
'name' => self::faker()->text(255),
'updatedAt' => self::faker()->dateTime(),
'maintenance' => self::faker()->boolean(),
'organizationalUnit' => OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT])->_save(),
];
}

View File

@ -38,7 +38,7 @@ final class HardwareProfileFactory extends ModelFactory
'createdAt' => self::faker()->dateTime(),
'updatedAt' => self::faker()->dateTime(),
'description' => self::faker()->text(255),
'organizationalUnit' => OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT])->_save(),
'client' => ClientFactory::new(),
];
}

View File

@ -3,17 +3,10 @@
namespace Functional;
use App\Entity\Client;
use App\Entity\HardwareProfile;
use App\Entity\HardwareType;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
use App\Entity\UserGroup;
use App\Factory\ClientFactory;
use App\Factory\HardwareProfileFactory;
use App\Factory\HardwareTypeFactory;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use App\Factory\UserGroupFactory;
use App\Model\OrganizationalUnitTypes;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
@ -29,7 +22,6 @@ class ClientTest extends AbstractTest
CONST string CLIENT_CREATE = 'test-client-create';
CONST string CLIENT_UPDATE = 'test-client-update';
CONST string CLIENT_DELETE = 'test-client-delete';
const string HW_PROFILE = 'HW Test';
/**
* @throws RedirectionExceptionInterface
@ -71,13 +63,9 @@ class ClientTest extends AbstractTest
OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
$ouIri = $this->findIriBy(OrganizationalUnit::class, ['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]);
$hpIri = $this->findIriBy(HardwareProfile::class, ['description' => self::HW_PROFILE]);
$this->createClientWithCredentials()->request('POST', '/clients',['json' => [
'name' => self::CLIENT_CREATE,
'organizationalUnit' => $ouIri,
'hardwareProfile' => $hpIri,
'serialNumber' => '123abc',
]]);
@ -103,9 +91,8 @@ class ClientTest extends AbstractTest
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
$ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
$hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]);
ClientFactory::createOne(['name' => self::CLIENT_UPDATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]);
ClientFactory::createOne(['name' => self::CLIENT_UPDATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou]);
$iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_UPDATE]);
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
@ -133,9 +120,8 @@ class ClientTest extends AbstractTest
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
$ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
$hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]);
ClientFactory::createOne(['name' => self::CLIENT_DELETE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]);
ClientFactory::createOne(['name' => self::CLIENT_DELETE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou]);
$iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_DELETE]);
$this->createClientWithCredentials()->request('DELETE', $iri);

View File

@ -3,12 +3,11 @@
namespace Functional;
use App\Entity\Client;
use App\Entity\HardwareProfile;
use App\Entity\OrganizationalUnit;
use App\Factory\ClientFactory;
use App\Factory\HardwareProfileFactory;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use App\Model\OrganizationalUnitTypes;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
@ -59,12 +58,12 @@ class HardwareProfileTest extends AbstractTest
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
$ouIri = $this->findIriBy(OrganizationalUnit::class, ['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
ClientFactory::createOne(['name' => 'test-client']);
$clientIri = $this->findIriBy(Client::class, ['name' => 'test-client']);
$this->createClientWithCredentials()->request('POST', '/hardware-profiles',['json' => [
'description' => self::HW_PROFILE_CREATE,
'organizationalUnit' => $ouIri
'client' => $clientIri
]]);
$this->assertResponseStatusCodeSame(201);

View File

@ -2,19 +2,9 @@
namespace Functional;
use App\Entity\Client;
use App\Entity\HardwareProfile;
use App\Entity\ImageRepository;
use App\Entity\Menu;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
use App\Factory\ClientFactory;
use App\Factory\HardwareProfileFactory;
use App\Factory\ImageRepositoryFactory;
use App\Factory\MenuFactory;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use App\Model\OrganizationalUnitTypes;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;

View File

@ -2,17 +2,9 @@
namespace Functional;
use App\Entity\Client;
use App\Entity\HardwareProfile;
use App\Entity\Menu;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
use App\Factory\ClientFactory;
use App\Factory\HardwareProfileFactory;
use App\Factory\MenuFactory;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use App\Model\OrganizationalUnitTypes;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;

View File

@ -2,11 +2,7 @@
namespace Functional;
use App\Entity\Client;
use App\Entity\HardwareProfile;
use App\Entity\OgLive;
use App\Entity\User;
use App\Factory\HardwareProfileFactory;
use App\Factory\OgLiveFactory;
use App\Factory\UserFactory;
use App\Model\OgLiveStatus;

View File

@ -2,20 +2,9 @@
namespace Functional;
use App\Entity\Client;
use App\Entity\Image;
use App\Entity\Menu;
use App\Entity\OperativeSystem;
use App\Entity\Partition;
use App\Factory\ClientFactory;
use App\Factory\HardwareProfileFactory;
use App\Factory\ImageFactory;
use App\Factory\MenuFactory;
use App\Factory\OperativeSystemFactory;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\PartitionFactory;
use App\Factory\UserFactory;
use App\Model\OrganizationalUnitTypes;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
@ -27,9 +16,6 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class PartitionTest extends AbstractTest
{
CONST string USER_ADMIN = 'ogadmin';
CONST string CLIENT_CREATE = 'test-client-create';
const string HW_PROFILE = 'HW Test';
/**
* @throws RedirectionExceptionInterface

View File

@ -3,14 +3,9 @@
namespace Functional;
use App\Entity\HardwareProfile;
use App\Entity\OrganizationalUnit;
use App\Entity\View;
use App\Factory\HardwareProfileFactory;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use App\Factory\ViewFactory;
use App\Model\OrganizationalUnitTypes;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;