develop #18
File diff suppressed because it is too large
Load Diff
|
@ -7,8 +7,9 @@ when@dev:
|
|||
handlers:
|
||||
main:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
level: info
|
||||
path: php://stderr
|
||||
formatter: App\Formatter\CustomLineFormatter
|
||||
channels: ["!event"]
|
||||
# uncomment to get logging in your browser
|
||||
# you may have to allow bigger header sizes in your Web server configuration
|
||||
|
|
|
@ -33,6 +33,8 @@ security:
|
|||
- { path: ^/og-repository/webhook, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/og-lives/install/webhook, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/auth/refresh, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/menu-browser, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/menu/, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
|
||||
|
||||
when@test:
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20241211074943 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP INDEX UNIQ_IDENTIFIER_NAME ON og_live');
|
||||
$this->addSql('ALTER TABLE og_live DROP name');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE og_live ADD name VARCHAR(255) NOT NULL');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_NAME ON og_live (name)');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20241211075520 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B54F7E54CF3');
|
||||
$this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54F7E54CF3 FOREIGN KEY (og_live_id) REFERENCES og_live (id) ON DELETE SET NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B54F7E54CF3');
|
||||
$this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54F7E54CF3 FOREIGN KEY (og_live_id) REFERENCES og_live (id)');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20241211080733 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE og_live CHANGE filename filename VARCHAR(255) NOT NULL');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_FILENAME ON og_live (filename)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP INDEX UNIQ_IDENTIFIER_FILENAME ON og_live');
|
||||
$this->addSql('ALTER TABLE og_live CHANGE filename filename VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20241216080914 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE menu DROP title');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE menu ADD title VARCHAR(255) NOT NULL');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250107121226 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE menu ADD is_default TINYINT(1) NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE menu DROP is_default');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250107124654 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CCD7E912');
|
||||
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id) ON DELETE SET NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CCD7E912');
|
||||
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)');
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Menu;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
#[AsCommand(name: 'opengnsys:load-default-menu', description: 'Load the default menu')]
|
||||
class LoadDefaultMenuCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$menu = new Menu();
|
||||
$menu->setName('Default menu');
|
||||
$menu->setResolution('1920x1080');
|
||||
$menu->setComments('Default menu comments');
|
||||
$menu->setPublicUrl('main');
|
||||
$menu->setIsDefault(true);
|
||||
|
||||
$this->entityManager->persist($menu);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,9 @@ namespace App\Command\Migration;
|
|||
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageRepository;
|
||||
use App\Entity\OrganizationalUnit;
|
||||
use App\Model\ImageStatus;
|
||||
use App\Model\OrganizationalUnitTypes;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
|
@ -70,18 +72,26 @@ class MigrateImagesCommand extends Command
|
|||
}
|
||||
|
||||
$imageEntity = $imagesRepository->findOneBy(['migrationId' => $image['idimagen']]);
|
||||
|
||||
$repository = $this->entityManager->getRepository(ImageRepository::class)->findAll()[0];
|
||||
|
||||
if(!$imageEntity) {
|
||||
$imageEntity = new Image();
|
||||
$imageEntity->setMigrationId((string) $image['idimagen']);
|
||||
$imageEntity->setName($image['nombreca']);
|
||||
$imageEntity->setClient($clientEntity);
|
||||
$imageEntity->setOrganizationalUnit($ouEntity);
|
||||
//$imageEntity->setOrganizationalUnit($ouEntity);
|
||||
$imageEntity->setRemotePc(false);
|
||||
$imageEntity->setStatus(ImageStatus::SUCCESS);
|
||||
$imageEntity->setRepository($repository);
|
||||
$imageEntity->setRevision((string) $image['revision']);
|
||||
$imageEntity->setDescription($image['descripcion']);
|
||||
$imageEntity->setComments($image['comentarios']);
|
||||
}
|
||||
|
||||
$this->entityManager->persist($imageEntity);
|
||||
$this->entityManager->flush();
|
||||
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
|
|
@ -18,6 +18,9 @@ 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 DeployImageAction extends AbstractController
|
||||
|
@ -32,17 +35,42 @@ class DeployImageAction extends AbstractController
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function __invoke(DeployImageInput $input, Image $image): JsonResponse
|
||||
{
|
||||
/** @var Partition $partition */
|
||||
$partition = $input->partition->getEntity();
|
||||
|
||||
switch ($input->method){
|
||||
case DeployMethodTypes::UNICAST:
|
||||
case DeployMethodTypes::UNICAST_DIRECT:
|
||||
$inputData = [
|
||||
'method' => $input->method,
|
||||
'client' => $input->client->getEntity()->getUuid(),
|
||||
'image' => $image->getUuid(),
|
||||
'numDisk' => (string) $partition->getDiskNumber(),
|
||||
'numPartition' => (string) $partition->getPartitionNumber(),
|
||||
];
|
||||
|
||||
$agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::UNICAST);
|
||||
$this->createService->__invoke($input->client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData);
|
||||
|
||||
break;
|
||||
|
||||
case DeployMethodTypes::MULTICAST_UFTP:
|
||||
case DeployMethodTypes::MULTICAST_UDPCAST:
|
||||
case DeployMethodTypes::MULTICAST:
|
||||
case DeployMethodTypes::MULTICAST_UFTP_DIRECT:
|
||||
case DeployMethodTypes::MULTICAST_UDPCAST_DIRECT:
|
||||
|
||||
$inputData = [
|
||||
'method' => $input->method,
|
||||
'client' => $input->client->getEntity()->getUuid(),
|
||||
'image' => $image->getUuid(),
|
||||
'p2pMode' => $input->p2pMode,
|
||||
'p2pTime' => $input->p2pTime,
|
||||
'mcastIp' => $input->mcastIp,
|
||||
'mcastPort' => $input->mcastPort,
|
||||
'mcastSpeed' => $input->mcastSpeed,
|
||||
|
@ -51,16 +79,30 @@ class DeployImageAction extends AbstractController
|
|||
'numPartition' => (string) $partition->getPartitionNumber(),
|
||||
];
|
||||
|
||||
switch ($input->method){
|
||||
case DeployMethodTypes::UNICAST:
|
||||
$agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::UNICAST);
|
||||
try {
|
||||
$this->deployImageOgRepositoryAction->__invoke($input, $image, $this->httpClient);
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse(data: ['error' => $e->getMessage()], status: Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::MULTICAST);
|
||||
$this->createService->__invoke($input->client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData);
|
||||
|
||||
break;
|
||||
|
||||
case DeployMethodTypes::MULTICAST:
|
||||
$agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::MULTICAST);
|
||||
$this->createService->__invoke($image->getClient(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData);
|
||||
case DeployMethodTypes::TORRENT:
|
||||
$inputData = [
|
||||
'method' => $input->method,
|
||||
'client' => $input->client->getEntity()->getUuid(),
|
||||
'image' => $image->getUuid(),
|
||||
'p2pMode' => $input->p2pMode,
|
||||
'p2pTime' => $input->p2pTime,
|
||||
'numDisk' => (string) $partition->getDiskNumber(),
|
||||
'numPartition' => (string) $partition->getPartitionNumber(),
|
||||
];
|
||||
|
||||
$agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::TORRENT);
|
||||
$this->createService->__invoke($input->client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Client;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Twig\Environment;
|
||||
|
||||
class MenuBrowserController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
protected readonly EntityManagerInterface $entityManager,
|
||||
private Environment $twig,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
#[Route('/menu-browser')]
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$host = $request->getClientIp();
|
||||
|
||||
$partitions = [];
|
||||
|
||||
$client = $this->entityManager->getRepository(Client::class)->findOneBy(['ip' => $host]);
|
||||
|
||||
if ($client) {
|
||||
$partitions = $client->getPartitions();
|
||||
}
|
||||
|
||||
$menuName = $client->getMenu()->getPublicUrl();
|
||||
|
||||
return $this->render('browser/' . $menuName . '.html.twig', [
|
||||
'ip' => $host,
|
||||
'partitions' => $partitions,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/menu/{templateName}', name: 'render_menu_template')]
|
||||
public function renderMenu(string $templateName, Request $request): Response
|
||||
{
|
||||
$templatePath = 'browser/' . $templateName . '.html.twig';
|
||||
|
||||
if (!$this->twig->getLoader()->exists($templatePath)) {
|
||||
throw $this->createNotFoundException(sprintf('La plantilla "%s" no existe.', $templateName));
|
||||
}
|
||||
|
||||
return $this->render($templatePath, [
|
||||
'ip' => 'invitado',
|
||||
'partitions' => [],
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ use App\Model\TraceStatus;
|
|||
use App\Service\Trace\CreateService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
@ -33,6 +34,7 @@ class CreateImageAction extends AbstractController
|
|||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -77,6 +79,7 @@ class CreateImageAction extends AbstractController
|
|||
}
|
||||
|
||||
try {
|
||||
$this->logger->info('Creating image', ['image' => $image->getId()]);
|
||||
$response = $this->httpClient->request('POST', 'https://'.$image->getClient()->getIp().':8000/CloningEngine/CrearImagen', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
|
@ -86,7 +89,9 @@ class CreateImageAction extends AbstractController
|
|||
'json' => $data,
|
||||
]);
|
||||
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Error creating image', ['image' => $image->getId(), 'error' => $e->getMessage()]);
|
||||
return new JsonResponse(
|
||||
data: ['error' => $e->getMessage()],
|
||||
status: Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
|
|
|
@ -11,9 +11,11 @@ use App\Entity\Image;
|
|||
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\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
@ -31,11 +33,11 @@ class DeployImageAction extends AbstractController
|
|||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function __invoke(Image $image, DeployImageInput $input, string $method)
|
||||
{
|
||||
if (!$image->getClient()->getIp()) {
|
||||
|
@ -50,6 +52,26 @@ class DeployImageAction extends AbstractController
|
|||
/** @var Partition $partition */
|
||||
$partition = $input->partition->getEntity();
|
||||
|
||||
$method = match ($input->method) {
|
||||
DeployMethodTypes::MULTICAST_UFTP_DIRECT, DeployMethodTypes::MULTICAST_UDPCAST_DIRECT, => 'multicast-direct',
|
||||
DeployMethodTypes::MULTICAST, DeployMethodTypes::MULTICAST_UFTP, DeployMethodTypes::MULTICAST_UDPCAST => 'multicast',
|
||||
DeployMethodTypes::UNICAST_DIRECT => 'unicast-direct',
|
||||
DeployMethodTypes::UNICAST => 'unicast',
|
||||
DeployMethodTypes::TORRENT => 'torrent',
|
||||
default => throw new ValidatorException('Invalid method'),
|
||||
};
|
||||
|
||||
$ptcMulticastValue = "$method $input->mcastPort:$input->mcastMode:$input->mcastIp:$input->mcastSpeed:$input->maxClients:$input->maxTime";
|
||||
$ptcTorrentValue = "$method $input->p2pMode:$input->p2pTime";
|
||||
$ptcUnicastValue = $method;
|
||||
|
||||
$ptcValue = match ($input->method) {
|
||||
DeployMethodTypes::MULTICAST, DeployMethodTypes::MULTICAST_UFTP, DeployMethodTypes::MULTICAST_UFTP_DIRECT, DeployMethodTypes::MULTICAST_UDPCAST, DeployMethodTypes::MULTICAST_UDPCAST_DIRECT => $ptcMulticastValue,
|
||||
DeployMethodTypes::UNICAST, DeployMethodTypes::UNICAST_DIRECT => $ptcUnicastValue,
|
||||
DeployMethodTypes::TORRENT => $ptcTorrentValue,
|
||||
default => throw new ValidatorException('Invalid method'),
|
||||
};
|
||||
|
||||
$data = [
|
||||
'dsk' => (string) $partition->getDiskNumber(),
|
||||
'par' => (string) $partition->getPartitionNumber(),
|
||||
|
@ -58,7 +80,7 @@ class DeployImageAction extends AbstractController
|
|||
'nci' => $image->getName(),
|
||||
'ipr' => $image->getRepository()->getIp(),
|
||||
'nfn' => 'RestaurarImagen',
|
||||
'ptc' => $method,
|
||||
'ptc' => $ptcValue,
|
||||
'ids' => '0'
|
||||
];
|
||||
|
||||
|
@ -71,8 +93,10 @@ class DeployImageAction extends AbstractController
|
|||
],
|
||||
'json' => $data,
|
||||
]);
|
||||
$this->logger->info('Deploying image', ['image' => $image->getId()]);
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Error deploying image', ['image' => $image->getId(), 'error' => $e->getMessage()]);
|
||||
return new JsonResponse(
|
||||
data: ['error' => $e->getMessage()],
|
||||
status: Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
|
|
|
@ -15,6 +15,7 @@ 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;
|
||||
|
@ -32,6 +33,7 @@ class PartitionAssistantAction extends AbstractController
|
|||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -70,12 +72,11 @@ class PartitionAssistantAction extends AbstractController
|
|||
'par' => (string) $partition->partitionNumber,
|
||||
'cpt' => $partition->partitionCode,
|
||||
'sfi' => $partition->filesystem,
|
||||
'tam' => (string) ($partition->size * 1024),
|
||||
'tam' => (string) (integer) ($partition->size * 1024),
|
||||
'ope' => $partition->format ? "1" : "0",
|
||||
];
|
||||
}
|
||||
|
||||
// Hacer una llamada por cada disco
|
||||
foreach ($disks as $diskNumber => $diskInfo) {
|
||||
$data = [];
|
||||
if (!empty($diskInfo['diskData'])) {
|
||||
|
@ -99,7 +100,9 @@ class PartitionAssistantAction extends AbstractController
|
|||
],
|
||||
'json' => $result,
|
||||
]);
|
||||
$this->logger->info('Partitioning disk', ['client' => $client->getId(), 'disk' => $diskNumber]);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Error partitioning disk', ['client' => $client->getId(), 'disk' => $diskNumber, 'error' => $e->getMessage()]);
|
||||
return new JsonResponse(
|
||||
data: ['error' => "Error en disco $diskNumber: " . $e->getMessage()],
|
||||
status: Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
|
|
|
@ -14,6 +14,7 @@ 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;
|
||||
|
@ -31,6 +32,7 @@ class PowerOffAction extends AbstractController
|
|||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -55,8 +57,10 @@ class PowerOffAction extends AbstractController
|
|||
],
|
||||
'json' => $data,
|
||||
]);
|
||||
$this->logger->info('Powering off client', ['client' => $client->getId()]);
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Error powering off client', ['client' => $client->getId(), 'error' => $e->getMessage()]);
|
||||
return new JsonResponse(
|
||||
data: ['error' => $e->getMessage()],
|
||||
status: Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
|
|
|
@ -14,6 +14,7 @@ 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;
|
||||
|
@ -31,6 +32,7 @@ class RebootAction extends AbstractController
|
|||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -55,8 +57,10 @@ class RebootAction extends AbstractController
|
|||
],
|
||||
'json' => $data,
|
||||
]);
|
||||
$this->logger->info('Rebooting client', ['client' => $client->getId()]);
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Error rebooting client', ['client' => $client->getId(), 'error' => $e->getMessage()]);
|
||||
return new JsonResponse(
|
||||
data: ['error' => $e->getMessage()],
|
||||
status: Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
|
|
|
@ -47,7 +47,7 @@ class StatusAction extends AbstractController
|
|||
throw new ValidatorException('IP is required');
|
||||
}
|
||||
|
||||
if ($client->getStatus() === ClientStatus::OG_LIVE || $client->getStatus() === ClientStatus::OFF || $client->getStatus() === ClientStatus::BUSY) {
|
||||
if ($client->getStatus() === ClientStatus::OG_LIVE || $client->getStatus() === ClientStatus::OFF || $client->getStatus() === ClientStatus::BUSY || $client->getStatus() === ClientStatus::INITIALIZING) {
|
||||
$response = $this->getOgLiveStatus($client);
|
||||
}
|
||||
|
||||
|
@ -79,6 +79,7 @@ class StatusAction extends AbstractController
|
|||
$client->setStatus($statusCode === Response::HTTP_OK ? ClientStatus::OG_LIVE : ClientStatus::OFF);
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Error checking client status', ['client' => $client->getId(), 'error' => $e->getMessage()]);
|
||||
$client->setStatus(ClientStatus::OFF);
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
@ -116,7 +117,7 @@ class StatusAction extends AbstractController
|
|||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$client->setStatus(ClientStatus::OFF);
|
||||
|
||||
$this->logger->error('Error checking client status', ['client' => $client->getId(), 'error' => $e->getMessage()]);
|
||||
return Response::HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Controller\OgAgent\Webhook;
|
|||
use App\Entity\Client;
|
||||
use App\Entity\OrganizationalUnit;
|
||||
use App\Entity\Partition;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Service\CreatePartitionService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
|
@ -47,6 +48,9 @@ class AgentController extends AbstractController
|
|||
return new JsonResponse(['message' => 'Client not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$clientEntity->setStatus(ClientStatus::OG_LIVE);
|
||||
$this->entityManager->persist($clientEntity);
|
||||
|
||||
if (isset($data['cfg'])) {
|
||||
$this->createPartitionService->__invoke($data, $clientEntity);
|
||||
}
|
||||
|
|
|
@ -113,34 +113,7 @@ class ClientsController extends AbstractController
|
|||
$this->logger->info('Image updated. Success.', ['image' => (string) $image->getUuid()]);
|
||||
}
|
||||
|
||||
if ($data['nfn'] === 'RESPUESTA_RestaurarImagen') {
|
||||
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
|
||||
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $data['idi']]);
|
||||
|
||||
$client = $trace->getClient();
|
||||
|
||||
if ($data['res'] === 1) {
|
||||
$trace->setStatus(TraceStatus::SUCCESS);
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$image->setStatus(ImageStatus::PENDING);
|
||||
$client->setStatus(ClientStatus::OG_LIVE);
|
||||
if (isset($data['cfg'])) {
|
||||
$this->createPartitionService->__invoke($data,$client);
|
||||
}
|
||||
} else {
|
||||
$trace->setStatus(TraceStatus::FAILED);
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$trace->setOutput($data['der']);
|
||||
}
|
||||
|
||||
$client->setStatus(ClientStatus::OG_LIVE);
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->persist($image);
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
if ($data['nfn'] === 'RESPUESTA_Configurar') {
|
||||
if ($data['nfn'] === 'RESPUESTA_RestaurarImagen'|| $data['nfn'] === 'RESPUESTA_Configurar') {
|
||||
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
|
||||
|
||||
$client = $trace->getClient();
|
||||
|
@ -158,7 +131,6 @@ class ClientsController extends AbstractController
|
|||
}
|
||||
|
||||
$client->setStatus(ClientStatus::OG_LIVE);
|
||||
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
|
@ -185,7 +157,7 @@ class ClientsController extends AbstractController
|
|||
}
|
||||
|
||||
$softwareProfile = new SoftwareProfile();
|
||||
$softwareProfile->setDescription('Perfil: ' . $image->getName());
|
||||
$softwareProfile->setDescription('Perfil software: ' . $image->getClient()->getName());
|
||||
$softwareProfile->setOrganizationalUnit($image->getClient()->getOrganizationalUnit());
|
||||
|
||||
foreach ($existingSoftware as $softwareEntity) {
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace App\Controller\OgBoot;
|
||||
|
||||
use App\Controller\OgBoot\PxeBootFile\PostAction;
|
||||
use App\Service\Trace\CreateService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
|
@ -26,8 +27,11 @@ abstract class AbstractOgBootController extends AbstractController
|
|||
protected string $ogBootApiUrl,
|
||||
#[Autowire(env: 'OG_CORE_IP')]
|
||||
protected string $ogCoreIP,
|
||||
#[Autowire(env: 'OG_LOG_IP')]
|
||||
protected string $ogLogIp,
|
||||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -32,14 +32,22 @@ class SyncAction extends AbstractOgBootController
|
|||
|
||||
foreach ($content['message']['installed_ogLives'] as $ogLive) {
|
||||
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['checksum' => $ogLive['id']]);
|
||||
|
||||
if (!$ogLiveEntity) {
|
||||
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['filename' => str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])]);
|
||||
|
||||
if (!$ogLiveEntity) {
|
||||
$ogLiveEntity = new OgLive();
|
||||
}
|
||||
}
|
||||
$this->extracted($ogLiveEntity, $ogLive);
|
||||
$this->entityManager->persist($ogLiveEntity);
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
//$this->serDefaultOgLive($content['default_oglive']);
|
||||
|
||||
if (isset($content['message']['default_oglive'])) {
|
||||
$this->serDefaultOgLive($content['message']['default_oglive']);
|
||||
}
|
||||
|
||||
return new JsonResponse(data: $content, status: Response::HTTP_OK);
|
||||
}
|
||||
|
@ -51,13 +59,10 @@ class SyncAction extends AbstractOgBootController
|
|||
*/
|
||||
private function extracted(OgLive $ogLiveEntity, mixed $ogLive): void
|
||||
{
|
||||
if (!$ogLiveEntity->getId()){
|
||||
$ogLiveEntity->setName(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']));
|
||||
}
|
||||
$ogLiveEntity->setInstalled(true);
|
||||
$ogLiveEntity->setArchitecture($ogLive['architecture']);
|
||||
$ogLiveEntity->setDistribution($ogLive['distribution']);
|
||||
$ogLiveEntity->setFilename($ogLive['directory']);
|
||||
$ogLiveEntity->setFilename(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']));
|
||||
$ogLiveEntity->setKernel($ogLive['kernel']);
|
||||
$ogLiveEntity->setRevision($ogLive['revision']);
|
||||
$ogLiveEntity->setDirectory($ogLive['directory']);
|
||||
|
@ -67,7 +72,7 @@ class SyncAction extends AbstractOgBootController
|
|||
|
||||
private function serDefaultOgLive(string $defaultOgLive): void
|
||||
{
|
||||
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['name' => $defaultOgLive]);
|
||||
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['filename' => $defaultOgLive]);
|
||||
|
||||
if (!$ogLiveEntity) {
|
||||
return;
|
||||
|
|
|
@ -6,6 +6,7 @@ use App\Controller\OgBoot\AbstractOgBootController;
|
|||
use App\Entity\OgLive;
|
||||
use App\Model\OgLiveStatus;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -24,11 +25,11 @@ class InstallOgLiveResponseAction extends AbstractController
|
|||
{
|
||||
public CONST string OG_LIVE_INSTALL_SUCCESS = 'success';
|
||||
public CONST string OG_LIVE_INSTALL_FAILED = 'failure';
|
||||
|
||||
|
||||
const string OG_BOOT_DIRECTORY = '/opt/opengnsys/ogboot/tftpboot//';
|
||||
|
||||
public function __construct(
|
||||
protected readonly EntityManagerInterface $entityManager
|
||||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -63,6 +64,7 @@ class InstallOgLiveResponseAction extends AbstractController
|
|||
}
|
||||
|
||||
$this->updateOgLive($ogLive, $message, $status);
|
||||
$this->logger->info(sprintf('OgLive %s updated successfully', $ogLive->getChecksum()));
|
||||
|
||||
return new JsonResponse(data: sprintf('OgLive %s updated successfully', $ogLive->getChecksum()), status: Response::HTTP_OK);
|
||||
}
|
||||
|
@ -70,6 +72,7 @@ class InstallOgLiveResponseAction extends AbstractController
|
|||
private function updateOgLive (OgLive $ogLive, array $details, string $status): void
|
||||
{
|
||||
if ($status === self::OG_LIVE_INSTALL_SUCCESS) {
|
||||
$ogLive->setFilename(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']));
|
||||
$ogLive->setInstalled(true);
|
||||
$ogLive->setSynchronized(true);
|
||||
$ogLive->setChecksum($details['id']);
|
||||
|
|
|
@ -28,6 +28,14 @@ class PostAction extends AbstractOgBootController
|
|||
*/
|
||||
public function __invoke(Client $client, PxeTemplate $pxeTemplate): JsonResponse
|
||||
{
|
||||
$ogRepoIp = $this->ogBootApiUrl;
|
||||
|
||||
if ($client->getRepository()) {
|
||||
$ogRepoIp = $client->getRepository()->getIp();
|
||||
} else if ($client->getOrganizationalUnit()->getNetworkSettings()->getRepository()) {
|
||||
$ogRepoIp = $client->getOrganizationalUnit()->getNetworkSettings()->getRepository()->getIp();
|
||||
}
|
||||
|
||||
$params = [
|
||||
'json' => [
|
||||
'template_name' => $pxeTemplate->getName(),
|
||||
|
@ -40,10 +48,10 @@ class PostAction extends AbstractOgBootController
|
|||
'computer_name' => $client->getName(),
|
||||
'netiface' => $client->getNetiface(),
|
||||
'group' => $client->getOrganizationalUnit()->getName(),
|
||||
'ogrepo' => $client->getRepository() ? $client->getRepository()->getIp() : $client->getOrganizationalUnit()->getNetworkSettings()->getRepository()->getIp(),
|
||||
'ogrepo' => $ogRepoIp,
|
||||
'ogcore' => $this->ogCoreIP,
|
||||
'oglive' => $this->ogBootApiUrl,
|
||||
'oglog' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgLog(),
|
||||
'oglog' => $this->ogLogIp,
|
||||
'ogshare' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare()
|
||||
? $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare(): $this->ogBootApiUrl,
|
||||
'oglivedir' => $client->getOgLive()->getFilename(),
|
||||
|
|
|
@ -7,6 +7,8 @@ use App\Dto\Input\DeployImageInput;
|
|||
use App\Entity\Command;
|
||||
use App\Entity\Image;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\DeployImageTypes;
|
||||
use App\Model\DeployMethodTypes;
|
||||
use App\Model\TraceStatus;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
@ -24,12 +26,31 @@ class DeployImageAction extends AbstractOgRepositoryController
|
|||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
*/
|
||||
public function __invoke(DeployImageInput $input, Image $data, HttpClientInterface $httpClient): JsonResponse
|
||||
{
|
||||
$client = $input->client;
|
||||
|
||||
$this->createService->__invoke($data->getClient(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, null);
|
||||
$params = [
|
||||
'json' => [
|
||||
'ID_img' => $data->getImageFullsum(),
|
||||
'bitrate' => (string) $input->mcastSpeed.'M',
|
||||
'ip' => $input->mcastIp,
|
||||
'port' => $input->mcastPort,
|
||||
'method' => $input->mcastMode,
|
||||
'nclients' => $input->maxClients,
|
||||
'maxtime' => $input->maxTime
|
||||
]
|
||||
];
|
||||
|
||||
$type = match ($input->method) {
|
||||
'udpcast', 'udpcast_direct' => DeployMethodTypes::MULTICAST_UDPCAST,
|
||||
'p2p' => DeployMethodTypes::TORRENT,
|
||||
default => DeployMethodTypes::MULTICAST_UFTP,
|
||||
};
|
||||
|
||||
$content = $this->createRequest('POST', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/'.$type, $params);
|
||||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ class WoLAction extends AbstractOgRepositoryController
|
|||
|
||||
$content = $this->createRequest('POST', 'http://'.$repository->getIp(). ':8006/ogrepository/v1/wol', $params);
|
||||
|
||||
$client->setStatus(ClientStatus::OFF);
|
||||
$client->setStatus(ClientStatus::INITIALIZING);
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
|
|
|
@ -40,14 +40,20 @@ class DeployImageInput
|
|||
public ?string $mcastIp = null;
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
public ?string $mcastSpeed = null;
|
||||
public ?int $mcastSpeed = null;
|
||||
|
||||
#[OrganizationalUnitMulticastPort]
|
||||
#[Groups(['image:write'])]
|
||||
public ?string $mcastPort = null;
|
||||
public ?int $mcastPort = null;
|
||||
|
||||
#[OrganizationalUnitMulticastMode]
|
||||
#[Groups(['image:write'])]
|
||||
public ?string $mcastMode = null;
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
public ?int $maxClients = null;
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
public ?int $maxTime = null;
|
||||
|
||||
}
|
|
@ -16,11 +16,6 @@ final class MenuInput
|
|||
#[ApiProperty(description: 'The name of the menu', example: "Menu 1")]
|
||||
public ?string $name = null;
|
||||
|
||||
#[Assert\NotNull()]
|
||||
#[Groups(['menu:write'])]
|
||||
#[ApiProperty(description: 'The title of the menu', example: "Menu 1 title")]
|
||||
public ?string $title = null;
|
||||
|
||||
#[Groups(['menu:write'])]
|
||||
#[ApiProperty(description: 'Comments of the menu', example: "Menu 1 comments")]
|
||||
public ?string $comments = null;
|
||||
|
@ -38,6 +33,10 @@ final class MenuInput
|
|||
#[ApiProperty(description: 'The private url of the menu', example: "http://example.com")]
|
||||
public ?string $privateUrl = null;
|
||||
|
||||
#[Groups(['menu:write'])]
|
||||
#[ApiProperty(description: 'The default menu', example: "false")]
|
||||
public ?bool $isDefault = false;
|
||||
|
||||
public function __construct(?Menu $menu = null)
|
||||
{
|
||||
if (!$menu) {
|
||||
|
@ -45,11 +44,11 @@ final class MenuInput
|
|||
}
|
||||
|
||||
$this->name = $menu->getName();
|
||||
$this->title = $menu->getTitle();
|
||||
$this->comments = $menu->getComments();
|
||||
$this->resolution = $menu->getResolution();
|
||||
$this->publicUrl = $menu->getPublicUrl();
|
||||
$this->privateUrl = $menu->getPrivateUrl();
|
||||
$this->isDefault = $menu->isDefault();
|
||||
}
|
||||
|
||||
public function createOrUpdateEntity(?Menu $menu = null): Menu
|
||||
|
@ -59,11 +58,11 @@ final class MenuInput
|
|||
}
|
||||
|
||||
$menu->setName($this->name);
|
||||
$menu->setTitle($this->title);
|
||||
$menu->setComments($this->comments);
|
||||
$menu->setResolution($this->resolution);
|
||||
$menu->setPublicUrl($this->publicUrl);
|
||||
$menu->setPrivateUrl($this->privateUrl);
|
||||
$menu->setIsDefault($this->isDefault);
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
|
|
@ -10,10 +10,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||
|
||||
final class OgLiveInput
|
||||
{
|
||||
#[Assert\NotBlank(message: 'validators.hardware.name.not_blank')]
|
||||
#[Groups(['og-live:write'])]
|
||||
#[ApiProperty(description: 'The name of the ogLive', example: "OgLive 1")]
|
||||
public ?string $name = null;
|
||||
const string DOWNLOAD_URL = 'https://ognproject.evlt.uma.es/oglive//';
|
||||
|
||||
#[Groups(['og-live:write'])]
|
||||
#[ApiProperty(description: 'The download url of the ogLive', example: "http://example.com/oglive1.iso")]
|
||||
|
@ -25,7 +22,6 @@ final class OgLiveInput
|
|||
return;
|
||||
}
|
||||
|
||||
$this->name = $ogLive->getName();
|
||||
$this->downloadUrl = $ogLive->getDownloadUrl();
|
||||
}
|
||||
|
||||
|
@ -35,7 +31,13 @@ final class OgLiveInput
|
|||
$ogLive = new OgLive();
|
||||
}
|
||||
|
||||
$ogLive->setName($this->name);
|
||||
$filename = str_replace(self::DOWNLOAD_URL, '', $this->downloadUrl);
|
||||
|
||||
if (str_ends_with($filename, '.iso')) {
|
||||
$filename = substr($filename, 0, -4);
|
||||
}
|
||||
|
||||
$ogLive->setFilename($filename);
|
||||
$ogLive->setDownloadUrl($this->downloadUrl);
|
||||
$ogLive->setStatus(OgLiveStatus::INACTIVE);
|
||||
|
||||
|
|
|
@ -13,9 +13,6 @@ final class MenuOutput extends AbstractOutput
|
|||
#[Groups(['menu:read', 'organizational-unit:read'])]
|
||||
public string $name;
|
||||
|
||||
#[Groups(['menu:read'])]
|
||||
public ?string $title = null;
|
||||
|
||||
#[Groups(['menu:read'])]
|
||||
public string $resolution;
|
||||
|
||||
|
@ -28,6 +25,9 @@ final class MenuOutput extends AbstractOutput
|
|||
#[Groups(['menu:read'])]
|
||||
public ?string $privateUrl = null;
|
||||
|
||||
#[Groups(['menu:read'])]
|
||||
public ?bool $isDefault = false;
|
||||
|
||||
#[Groups(['menu:read'])]
|
||||
public \DateTime $createdAt;
|
||||
|
||||
|
@ -39,11 +39,11 @@ public function __construct(Menu $menu)
|
|||
parent::__construct($menu);
|
||||
|
||||
$this->name = $menu->getName();
|
||||
$this->title = $menu->getTitle();
|
||||
$this->resolution = $menu->getResolution();
|
||||
$this->comments = $menu->getComments();
|
||||
$this->publicUrl = $menu->getPublicUrl();
|
||||
$this->privateUrl = $menu->getPrivateUrl();
|
||||
$this->isDefault = $menu->isDefault();
|
||||
$this->createdAt = $menu->getCreatedAt();
|
||||
$this->createdBy = $menu->getCreatedBy();
|
||||
}
|
||||
|
|
|
@ -10,9 +10,6 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
|||
#[Get(shortName: 'OgLive')]
|
||||
final class OgLiveOutput extends AbstractOutput
|
||||
{
|
||||
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
|
||||
public string $name;
|
||||
|
||||
#[Groups(['og-live:read'])]
|
||||
public ?bool $synchronized = false;
|
||||
|
||||
|
@ -37,8 +34,8 @@ final class OgLiveOutput extends AbstractOutput
|
|||
#[Groups(['og-live:read'])]
|
||||
public ?string $revision = '';
|
||||
|
||||
#[Groups(['og-live:read'])]
|
||||
public ?string $filename = '';
|
||||
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
|
||||
public ?string $filename = null;
|
||||
|
||||
#[Groups(['og-live:read'])]
|
||||
public ?string $kernel = '';
|
||||
|
@ -56,7 +53,6 @@ final class OgLiveOutput extends AbstractOutput
|
|||
{
|
||||
parent::__construct($ogLive);
|
||||
|
||||
$this->name = $ogLive->getName();
|
||||
$this->synchronized = $ogLive->isSynchronized();
|
||||
$this->installed = $ogLive->isInstalled();
|
||||
$this->isDefault = $ogLive->getIsDefault();
|
||||
|
|
|
@ -49,6 +49,7 @@ class Client extends AbstractEntity
|
|||
private Collection $partitions;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn( onDelete: 'SET NULL')]
|
||||
private ?Menu $menu = null;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
|
@ -63,7 +64,7 @@ class Client extends AbstractEntity
|
|||
#[ORM\ManyToOne(inversedBy: 'clients')]
|
||||
private ?PxeTemplate $template = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'clients')]
|
||||
#[ORM\ManyToOne()]
|
||||
private ?ImageRepository $repository = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'clients')]
|
||||
|
|
|
@ -12,9 +12,6 @@ class Menu extends AbstractEntity
|
|||
{
|
||||
use NameableTrait;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $title = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $resolution = null;
|
||||
|
||||
|
@ -27,28 +24,12 @@ class Menu extends AbstractEntity
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $privateUrl = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Client>
|
||||
*/
|
||||
#[ORM\OneToMany(mappedBy: 'menu', targetEntity: Client::class)]
|
||||
private Collection $clients;
|
||||
#[ORM\Column]
|
||||
private ?bool $isDefault = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->clients = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getTitle(): ?string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(string $title): static
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getResolution(): ?string
|
||||
|
@ -99,31 +80,14 @@ class Menu extends AbstractEntity
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Client>
|
||||
*/
|
||||
public function getClients(): Collection
|
||||
public function isDefault(): ?bool
|
||||
{
|
||||
return $this->clients;
|
||||
return $this->isDefault;
|
||||
}
|
||||
|
||||
public function addClient(Client $client): static
|
||||
public function setIsDefault(bool $isDefault): static
|
||||
{
|
||||
if (!$this->clients->contains($client)) {
|
||||
$this->clients->add($client);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeClient(Client $client): static
|
||||
{
|
||||
if ($this->clients->removeElement($client)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($client->getMenu() === $this) {
|
||||
$client->setMenu(null);
|
||||
}
|
||||
}
|
||||
$this->isDefault = $isDefault;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ class NetworkSettings extends AbstractEntity
|
|||
private ?ImageRepository $repository = null;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn( onDelete: 'SET NULL')]
|
||||
private ?OgLive $ogLive = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
|
|
|
@ -9,11 +9,10 @@ use Doctrine\ORM\Mapping as ORM;
|
|||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
|
||||
#[ORM\Entity(repositoryClass: OgLiveRepository::class)]
|
||||
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_NAME', fields: ['name'])]
|
||||
#[UniqueEntity(fields: ['name'], message: 'validators.og_live.name.unique')]
|
||||
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_FILENAME', fields: ['filename'])]
|
||||
#[UniqueEntity(fields: ['filename'], message: 'validators.og_live.filename.unique')]
|
||||
class OgLive extends AbstractEntity
|
||||
{
|
||||
use NameableTrait;
|
||||
use SynchronizedTrait;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
|
@ -37,7 +36,7 @@ class OgLive extends AbstractEntity
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $directory = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
#[ORM\Column(length: 255, nullable: false)]
|
||||
private ?string $filename = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
|
|
|
@ -97,12 +97,6 @@ class OrganizationalUnit extends AbstractEntity
|
|||
#[ORM\Column]
|
||||
private ?bool $reserved = false;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Image>
|
||||
*/
|
||||
#[ORM\OneToMany(mappedBy: 'organizationalUnit', targetEntity: Image::class)]
|
||||
private Collection $images;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -110,7 +104,6 @@ class OrganizationalUnit extends AbstractEntity
|
|||
$this->users = new ArrayCollection();
|
||||
$this->clients = new ArrayCollection();
|
||||
$this->softwareProfiles = new ArrayCollection();
|
||||
$this->images = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
|
@ -436,34 +429,4 @@ class OrganizationalUnit extends AbstractEntity
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Image>
|
||||
*/
|
||||
public function getImages(): Collection
|
||||
{
|
||||
return $this->images;
|
||||
}
|
||||
|
||||
public function addImage(Image $image): static
|
||||
{
|
||||
if (!$this->images->contains($image)) {
|
||||
$this->images->add($image);
|
||||
$image->setOrganizationalUnit($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeImage(Image $image): static
|
||||
{
|
||||
if ($this->images->removeElement($image)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($image->getOrganizationalUnit() === $this) {
|
||||
$image->setOrganizationalUnit(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ final readonly class ClientSubscriber implements EventSubscriberInterface
|
|||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::VIEW => ['sendMail', EventPriorities::POST_WRITE],
|
||||
KernelEvents::VIEW => ['updatePxe', EventPriorities::POST_WRITE],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ final readonly class ClientSubscriber implements EventSubscriberInterface
|
|||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function sendMail(ViewEvent $event): void
|
||||
public function updatePxe(ViewEvent $event): void
|
||||
{
|
||||
$clientOutput = $event->getControllerResult();
|
||||
$method = $event->getRequest()->getMethod();
|
||||
|
|
|
@ -33,7 +33,7 @@ final class MenuFactory extends ModelFactory
|
|||
'createdAt' => self::faker()->dateTime(),
|
||||
'name' => self::faker()->text(255),
|
||||
'resolution' => self::faker()->text(255),
|
||||
'title' => self::faker()->text(255),
|
||||
'isDefault' => self::faker()->boolean(),
|
||||
'updatedAt' => self::faker()->dateTime(),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -34,8 +34,7 @@ final class OgLiveFactory extends ModelFactory
|
|||
{
|
||||
return [
|
||||
'createdAt' => self::faker()->dateTime(),
|
||||
'name' => self::faker()->text(255),
|
||||
'downloadUrl' => self::faker()->text(255),
|
||||
'filename' => self::faker()->text(255),
|
||||
'status' => OgLiveStatus::ACTIVE,
|
||||
'updatedAt' => self::faker()->dateTime(),
|
||||
];
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Formatter;
|
||||
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
class CustomLineFormatter extends LineFormatter
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(null, 'Y-m-d H:i:s', true, true);
|
||||
}
|
||||
|
||||
public function format($record): string
|
||||
{
|
||||
$output = [
|
||||
'severity' => $record['level_name'],
|
||||
'operation' => $record['channel'],
|
||||
'component' => 'ogcore',
|
||||
'params' => $record['context'],
|
||||
'desc' => $record['message'],
|
||||
];
|
||||
|
||||
return json_encode($output, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL;
|
||||
}
|
||||
}
|
|
@ -5,8 +5,13 @@ namespace App\Model;
|
|||
final class DeployMethodTypes
|
||||
{
|
||||
public const string MULTICAST = 'multicast';
|
||||
public const string MULTICAST_UFTP = 'uftp';
|
||||
public const string MULTICAST_UFTP_DIRECT = 'uftp-direct';
|
||||
public const string MULTICAST_UDPCAST = 'udpcast';
|
||||
public const string MULTICAST_UDPCAST_DIRECT = 'udp-direct';
|
||||
public const string UNICAST = 'unicast';
|
||||
public const string TORRENT = 'torrent';
|
||||
public const string UNICAST_DIRECT = 'unicast-direct';
|
||||
public const string TORRENT = 'p2p';
|
||||
|
||||
private const array DEPLOYMENT_METHOD_TYPES = [
|
||||
self::MULTICAST => 'Multicast',
|
||||
|
|
|
@ -4,8 +4,8 @@ namespace App\Model;
|
|||
|
||||
final class OrganizationalUnitMulticastModes
|
||||
{
|
||||
public const string HALF_DUPLEX = 'half-duplex';
|
||||
public const string FULL_DUPLEX = 'full-duplex';
|
||||
public const string HALF_DUPLEX = 'half';
|
||||
public const string FULL_DUPLEX = 'full';
|
||||
|
||||
private const array MCAST_MODES = [
|
||||
self::HALF_DUPLEX => 'Half Duplex',
|
||||
|
|
|
@ -15,4 +15,40 @@ class ClientRepository extends AbstractRepository
|
|||
{
|
||||
parent::__construct($registry, Client::class);
|
||||
}
|
||||
|
||||
public function findClientsByOrganizationalUnitAndDescendants(int $organizationalUnitId): array
|
||||
{
|
||||
$query = $this->getEntityManager()->createQuery(
|
||||
'SELECT o.path
|
||||
FROM App\Entity\OrganizationalUnit o
|
||||
WHERE o.id = :id'
|
||||
)->setParameter('id', $organizationalUnitId);
|
||||
|
||||
$result = $query->getOneOrNullResult();
|
||||
|
||||
if (!$result) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$path = $result['path'] . '/%';
|
||||
|
||||
$query = $this->getEntityManager()->createQuery(
|
||||
'SELECT o.id
|
||||
FROM App\Entity\OrganizationalUnit o
|
||||
WHERE o.id = :id OR o.path LIKE :path'
|
||||
)
|
||||
->setParameter('id', $organizationalUnitId)
|
||||
->setParameter('path', $path);
|
||||
|
||||
$unitIds = array_column($query->getArrayResult(), 'id');
|
||||
|
||||
$query = $this->getEntityManager()->createQuery(
|
||||
'SELECT c
|
||||
FROM App\Entity\Client c
|
||||
WHERE c.organizationalUnit IN (:unitIds)'
|
||||
)
|
||||
->setParameter('unitIds', $unitIds);
|
||||
|
||||
return $query->getResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,15 @@ use App\Entity\Client;
|
|||
use App\Entity\OperativeSystem;
|
||||
use App\Entity\Partition;
|
||||
use App\Model\PartitionTypes;
|
||||
use App\Service\Utils\GetPartitionCodeService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
|
||||
class CreatePartitionService
|
||||
{
|
||||
public function __construct(
|
||||
protected EntityManagerInterface $entityManager
|
||||
protected EntityManagerInterface $entityManager,
|
||||
protected GetPartitionCodeService $partitionCodeService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -54,11 +56,15 @@ class CreatePartitionService
|
|||
$partitionEntity->setSize($cfg['tam']);
|
||||
|
||||
if (isset($cfg['cpt']) && $cfg['cpt'] !== '') {
|
||||
if ($cfg['par'] === "0") {
|
||||
$partitionType = $this->partitionCodeService->__invoke($cfg['cpt']);
|
||||
} else {
|
||||
$decimalValue = hexdec($cfg['cpt']);
|
||||
$partitionType = PartitionTypes::getPartitionType($decimalValue);
|
||||
}
|
||||
|
||||
if ($partitionType) {
|
||||
$partitionEntity->setPartitionCode($partitionType['name']);
|
||||
$partitionEntity->setPartitionCode($partitionType['name'] ?? $partitionType);
|
||||
}
|
||||
} else {
|
||||
$partitionEntity->setPartitionCode(PartitionTypes::getPartitionType(0)['name']);
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\Utils;
|
||||
|
||||
class GetPartitionCodeService
|
||||
{
|
||||
public function __invoke(string $partitionCode): string
|
||||
{
|
||||
return match ($partitionCode) {
|
||||
"1" => "MSDOS",
|
||||
"2" => "GPT",
|
||||
"3" => "LVM",
|
||||
"4" => "ZPOOL",
|
||||
default => "UNKNOWN",
|
||||
};
|
||||
}
|
||||
}
|
|
@ -13,12 +13,14 @@ use App\Dto\Input\ClientInput;
|
|||
use App\Dto\Output\ClientOutput;
|
||||
use App\Dto\Output\UserGroupOutput;
|
||||
use App\Repository\ClientRepository;
|
||||
use App\Repository\MenuRepository;
|
||||
|
||||
class ClientProcessor implements ProcessorInterface
|
||||
readonly class ClientProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientRepository $clientRepository,
|
||||
private readonly ValidatorInterface $validator
|
||||
private ClientRepository $clientRepository,
|
||||
private MenuRepository $menuRepository,
|
||||
private ValidatorInterface $validator
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -52,11 +54,18 @@ class ClientProcessor implements ProcessorInterface
|
|||
$entity = $this->clientRepository->findOneByUuid($uriVariables['uuid']);
|
||||
}
|
||||
|
||||
$userGroup = $data->createOrUpdateEntity($entity);
|
||||
$this->validator->validate($userGroup);
|
||||
$this->clientRepository->save($userGroup);
|
||||
$defaultMenu = $this->menuRepository->findOneBy(['isDefault' => true]);
|
||||
|
||||
return new ClientOutput($userGroup);
|
||||
$client = $data->createOrUpdateEntity($entity);
|
||||
|
||||
if ($defaultMenu) {
|
||||
$client->setMenu($defaultMenu);
|
||||
}
|
||||
|
||||
$this->validator->validate($client);
|
||||
$this->clientRepository->save($client);
|
||||
|
||||
return new ClientOutput($client);
|
||||
}
|
||||
|
||||
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
|
||||
|
|
|
@ -11,11 +11,13 @@ use ApiPlatform\State\Pagination\TraversablePaginator;
|
|||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Dto\Input\ClientInput;
|
||||
use App\Dto\Output\ClientOutput;
|
||||
use App\Repository\ClientRepository;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
readonly class ClientProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private ClientRepository $clientRepository,
|
||||
private ProviderInterface $collectionProvider,
|
||||
private ProviderInterface $itemProvider
|
||||
)
|
||||
|
@ -35,18 +37,25 @@ readonly class ClientProvider implements ProviderInterface
|
|||
}
|
||||
}
|
||||
|
||||
private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
|
||||
public function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
|
||||
{
|
||||
$paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
|
||||
$organizationalUnitId = $context['filters']['organizationalUnit.id'] ?? null;
|
||||
|
||||
if ($organizationalUnitId) {
|
||||
$clients = $this->clientRepository->findClientsByOrganizationalUnitAndDescendants((int) $organizationalUnitId);
|
||||
|
||||
$items = new \ArrayObject();
|
||||
foreach ($paginator->getIterator() as $item){
|
||||
$items[] = new ClientOutput($item);
|
||||
foreach ($clients as $client) {
|
||||
$items[] = new ClientOutput($client);
|
||||
}
|
||||
|
||||
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());
|
||||
return new TraversablePaginator($items, 1, count($clients), count($clients));
|
||||
}
|
||||
|
||||
return $this->collectionProvider->provide($operation, $uriVariables, $context);
|
||||
}
|
||||
|
||||
|
||||
public function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
|
||||
{
|
||||
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
|
||||
|
|
117
symfony.lock
117
symfony.lock
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"api-platform/core": {
|
||||
"version": "3.3",
|
||||
"version": "3.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
|
@ -13,17 +13,8 @@
|
|||
"src/ApiResource/.gitignore"
|
||||
]
|
||||
},
|
||||
"dama/doctrine-test-bundle": {
|
||||
"version": "8.2",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "main",
|
||||
"version": "7.2",
|
||||
"ref": "896306d79d4ee143af9eadf9b09fd34a8c391b70"
|
||||
}
|
||||
},
|
||||
"doctrine/doctrine-bundle": {
|
||||
"version": "2.12",
|
||||
"version": "2.13",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
|
@ -36,18 +27,6 @@
|
|||
"src/Repository/.gitignore"
|
||||
]
|
||||
},
|
||||
"doctrine/doctrine-fixtures-bundle": {
|
||||
"version": "3.6",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "3.0",
|
||||
"ref": "1f5514cfa15b947298df4d771e694e578d4c204d"
|
||||
},
|
||||
"files": [
|
||||
"src/DataFixtures/AppFixtures.php"
|
||||
]
|
||||
},
|
||||
"doctrine/doctrine-migrations-bundle": {
|
||||
"version": "3.3",
|
||||
"recipe": {
|
||||
|
@ -62,16 +41,21 @@
|
|||
]
|
||||
},
|
||||
"gesdinet/jwt-refresh-token-bundle": {
|
||||
"version": "1.3",
|
||||
"version": "1.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "2390b4ed5c195e0b3f6dea45221f3b7c0af523a0"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"config/packages/gesdinet_jwt_refresh_token.yaml",
|
||||
"config/routes/gesdinet_jwt_refresh_token.yaml",
|
||||
"src/Entity/RefreshToken.php"
|
||||
]
|
||||
},
|
||||
"lexik/jwt-authentication-bundle": {
|
||||
"version": "3.0",
|
||||
"version": "3.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
|
@ -83,7 +67,7 @@
|
|||
]
|
||||
},
|
||||
"nelmio/cors-bundle": {
|
||||
"version": "2.4",
|
||||
"version": "2.5",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
|
@ -94,20 +78,6 @@
|
|||
"config/packages/nelmio_cors.yaml"
|
||||
]
|
||||
},
|
||||
"phpunit/phpunit": {
|
||||
"version": "9.6",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "9.6",
|
||||
"ref": "7364a21d87e658eb363c5020c072ecfdc12e2326"
|
||||
},
|
||||
"files": [
|
||||
".env.test",
|
||||
"phpunit.xml.dist",
|
||||
"tests/bootstrap.php"
|
||||
]
|
||||
},
|
||||
"ramsey/uuid-doctrine": {
|
||||
"version": "2.1",
|
||||
"recipe": {
|
||||
|
@ -118,13 +88,16 @@
|
|||
}
|
||||
},
|
||||
"stof/doctrine-extensions-bundle": {
|
||||
"version": "1.11",
|
||||
"version": "1.12",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "main",
|
||||
"version": "1.2",
|
||||
"ref": "e805aba9eff5372e2d149a9ff56566769e22819d"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"config/packages/stof_doctrine_extensions.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/console": {
|
||||
"version": "6.4",
|
||||
|
@ -143,11 +116,12 @@
|
|||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
|
||||
"version": "2.4",
|
||||
"ref": "52e9754527a15e2b79d9a610f98185a1fe46622a"
|
||||
},
|
||||
"files": [
|
||||
".env"
|
||||
".env",
|
||||
".env.dev"
|
||||
]
|
||||
},
|
||||
"symfony/framework-bundle": {
|
||||
|
@ -156,7 +130,7 @@
|
|||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.4",
|
||||
"ref": "a91c965766ad3ff2ae15981801643330eb42b6a5"
|
||||
"ref": "32126346f25e1cee607cc4aa6783d46034920554"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/cache.yaml",
|
||||
|
@ -169,15 +143,6 @@
|
|||
"src/Kernel.php"
|
||||
]
|
||||
},
|
||||
"symfony/maker-bundle": {
|
||||
"version": "1.60",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
|
||||
}
|
||||
},
|
||||
"symfony/monolog-bundle": {
|
||||
"version": "3.10",
|
||||
"recipe": {
|
||||
|
@ -190,21 +155,6 @@
|
|||
"config/packages/monolog.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/phpunit-bridge": {
|
||||
"version": "7.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.3",
|
||||
"ref": "a411a0480041243d97382cac7984f7dce7813c08"
|
||||
},
|
||||
"files": [
|
||||
".env.test",
|
||||
"bin/phpunit",
|
||||
"phpunit.xml.dist",
|
||||
"tests/bootstrap.php"
|
||||
]
|
||||
},
|
||||
"symfony/routing": {
|
||||
"version": "6.4",
|
||||
"recipe": {
|
||||
|
@ -268,30 +218,5 @@
|
|||
"files": [
|
||||
"config/packages/validator.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/web-profiler-bundle": {
|
||||
"version": "6.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.1",
|
||||
"ref": "e42b3f0177df239add25373083a564e5ead4e13a"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/web_profiler.yaml",
|
||||
"config/routes/web_profiler.yaml"
|
||||
]
|
||||
},
|
||||
"zenstruck/foundry": {
|
||||
"version": "1.38",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.10",
|
||||
"ref": "37c2f894cc098ab4c08874b80cccc8e2f8de7976"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/zenstruck_foundry.yaml"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Menú de Opciones</title>
|
||||
<style>
|
||||
.navbar {
|
||||
color: white;
|
||||
padding: 15px 30px;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.navbar img {
|
||||
width: auto;
|
||||
position: absolute; /* Logo en la izquierda */
|
||||
left: 30px; /* Ajuste de la distancia desde la izquierda */
|
||||
}
|
||||
|
||||
.navbar h1 {
|
||||
margin: 0;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 5px 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 80px auto 0; /* Deja espacio para la barra de navegación */
|
||||
width: 90%;
|
||||
max-width: 1000px;
|
||||
text-align: center; /* Centra los elementos en navegadores básicos */
|
||||
}
|
||||
|
||||
.menu-container {
|
||||
display: block;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
background-color: #f0f8ff; /* Fondo suave */
|
||||
padding: 15px;
|
||||
margin: 15px 0; /* Espaciado entre cajas */
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
width: 45%; /* Dos elementos por fila */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.menu-item a {
|
||||
font-size: 1.2em;
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.menu-item p {
|
||||
font-size: 0.9em;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.menu-item {
|
||||
width: 100%; /* En pantallas pequeñas, las cajas ocupan todo el ancho */
|
||||
}
|
||||
}
|
||||
|
||||
.windows {
|
||||
background-color: #e0f7fa; /* Azul suave para Windows */
|
||||
}
|
||||
|
||||
.linux {
|
||||
background-color: #c8e6c9; /* Verde suave para Linux */
|
||||
}
|
||||
|
||||
.apagar {
|
||||
background-color: #ffccbc; /* Naranja suave para Apagar */
|
||||
}
|
||||
.partition-container {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.partition-header {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.partition-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap; /* Permite adaptarse a pantallas pequeñas */
|
||||
align-items: center;
|
||||
text-align: left; /* Asegura que el contenido está alineado a la izquierda */
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.partition-item span {
|
||||
margin-right: 15px;
|
||||
font-size: 1em;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.partition-link {
|
||||
font-size: 0.9em;
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.partition-link:hover {
|
||||
text-decoration: underline;
|
||||
color: #0056b3;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.partition-item {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.partition-item span {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.partition-link {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Barra de navegación superior -->
|
||||
<div class="navbar">
|
||||
<img src="{{ asset('images/img.png') }}" alt="Logo">
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="menu-container">
|
||||
<h1>Bienvenido {{ ip }}</h1>
|
||||
<div class="menu-item windows">
|
||||
<a href="command+confirm:restoreImage REPO windows 1 1">Instalar Windows</a>
|
||||
<p>El proceso de instalación tardará unos minutos.</p>
|
||||
</div>
|
||||
<div class="menu-item linux">
|
||||
<a href="command+output+confirm:restoreImage REPO linux 1 2">Instalar GNU/Linux</a>
|
||||
<p>El proceso de instalación tardará unos minutos.</p>
|
||||
</div>
|
||||
|
||||
<div class="menu-item apagar">
|
||||
<a href="command:poweroff">Apagar</a>
|
||||
<p>Apagar el ordenador.</p>
|
||||
</div>
|
||||
<div class="menu-item apagar">
|
||||
<a href="command:reboot">Reiniciar</a>
|
||||
<p>Reiniciar el ordenador.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="partition-container">
|
||||
<h2 class="partition-header">Particiones del sistema</h2>
|
||||
{% if partitions|length > 0 %}
|
||||
{% for partition in partitions %}
|
||||
<div class="partition-item">
|
||||
<span><strong>Disco:</strong> {{ partition.diskNumber }} </span>
|
||||
<span><strong>Partición:</strong> {{ partition.partitionNumber }}</span>
|
||||
<span>Tamaño: {{ (partition.size / 1024)|number_format(2) }} MB</span>
|
||||
<span>Tipo: {{ partition.filesystem }}</span>
|
||||
<span><strong>SO:</strong> {{ partition.operativeSystem ? partition.operativeSystem.name : '-' }}</span>
|
||||
{% if partition.operativeSystem %}
|
||||
<a href="command+output:bootOs {{ partition.diskNumber }} {{ partition.partitionNumber }}" class="partition-link">Arrancar {{ partition.operativeSystem.name }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>No hay particiones disponibles.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -65,7 +65,6 @@ class MenuTest extends AbstractTest
|
|||
|
||||
$this->createClientWithCredentials()->request('POST', '/menus',['json' => [
|
||||
'name' => self::MENU_CREATE,
|
||||
'title' => self::MENU_CREATE,
|
||||
'resolution' => "1920x1080",
|
||||
]]);
|
||||
|
||||
|
@ -75,7 +74,6 @@ class MenuTest extends AbstractTest
|
|||
'@context' => '/contexts/MenuOutput',
|
||||
'@type' => 'Menu',
|
||||
'name' => self::MENU_CREATE,
|
||||
'title' => self::MENU_CREATE,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -90,7 +88,7 @@ class MenuTest extends AbstractTest
|
|||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
MenuFactory::createOne(['name' => self::MENU_UPDATE, 'title' => self::MENU_UPDATE, 'resolution' => "1920x1080"]);
|
||||
MenuFactory::createOne(['name' => self::MENU_UPDATE, 'resolution' => "1920x1080"]);
|
||||
$iri = $this->findIriBy(Menu::class, ['name' => self::MENU_UPDATE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
|
||||
|
@ -117,7 +115,7 @@ class MenuTest extends AbstractTest
|
|||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
MenuFactory::createOne(['name' => self::MENU_DELETE, 'title' => self::MENU_DELETE, 'resolution' => "1920x1080"]);
|
||||
MenuFactory::createOne(['name' => self::MENU_DELETE, 'resolution' => "1920x1080"]);
|
||||
$iri = $this->findIriBy(Menu::class, ['name' => self::MENU_DELETE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('DELETE', $iri);
|
||||
|
|
|
@ -61,8 +61,8 @@ class OgLiveTest extends AbstractTest
|
|||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
$this->createClientWithCredentials()->request('POST', '/og-lives',['json' => [
|
||||
'name' => self::OGLIVE_CREATE,
|
||||
'downloadUrl' => 'http://example.com',
|
||||
'filename' => self::OGLIVE_CREATE,
|
||||
'downloadUrl' => self::OGLIVE_CREATE
|
||||
]]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(201);
|
||||
|
@ -70,8 +70,7 @@ class OgLiveTest extends AbstractTest
|
|||
$this->assertJsonContains([
|
||||
'@context' => '/contexts/OgLiveOutput',
|
||||
'@type' => 'OgLive',
|
||||
'name' => self::OGLIVE_CREATE,
|
||||
'downloadUrl' => 'http://example.com',
|
||||
'filename' => self::OGLIVE_CREATE,
|
||||
'status' => OgLiveStatus::INACTIVE
|
||||
]);
|
||||
}
|
||||
|
@ -87,19 +86,17 @@ class OgLiveTest extends AbstractTest
|
|||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
OgLiveFactory::createOne(['name' => self::OGLIVE_CREATE, 'downloadUrl' => 'http://example.com']);
|
||||
$iri = $this->findIriBy(OgLive::class, ['name' => self::OGLIVE_CREATE]);
|
||||
OgLiveFactory::createOne(['filename' => self::OGLIVE_CREATE, 'downloadUrl' => self::OGLIVE_UPDATE]);
|
||||
$iri = $this->findIriBy(OgLive::class, ['filename' => self::OGLIVE_CREATE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
|
||||
'name' => self::OGLIVE_UPDATE,
|
||||
'downloadUrl' => 'http://example-2.com',
|
||||
'filename' => self::OGLIVE_UPDATE,
|
||||
]]);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonContains([
|
||||
'@id' => $iri,
|
||||
'name' => self::OGLIVE_UPDATE,
|
||||
'downloadUrl' => 'http://example-2.com',
|
||||
'filename' => self::OGLIVE_UPDATE,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -114,13 +111,13 @@ class OgLiveTest extends AbstractTest
|
|||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
OgLiveFactory::createOne(['name' => self::OGLIVE_CREATE, 'downloadUrl' => 'http://example.com']);
|
||||
$iri = $this->findIriBy(OgLive::class, ['name' => self::OGLIVE_CREATE]);
|
||||
OgLiveFactory::createOne(['filename' => self::OGLIVE_CREATE, 'downloadUrl' => 'http://example.com']);
|
||||
$iri = $this->findIriBy(OgLive::class, ['filename' => self::OGLIVE_CREATE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('DELETE', $iri);
|
||||
$this->assertResponseStatusCodeSame(204);
|
||||
$this->assertNull(
|
||||
static::getContainer()->get('doctrine')->getRepository(OgLive::class)->findOneBy(['name' => self::OGLIVE_CREATE])
|
||||
static::getContainer()->get('doctrine')->getRepository(OgLive::class)->findOneBy(['filename' => self::OGLIVE_CREATE])
|
||||
);
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ validators:
|
|||
not_blank: 'The name should not be blank.'
|
||||
|
||||
og_live:
|
||||
name:
|
||||
filename:
|
||||
not_blank: 'The name should not be blank.'
|
||||
unique: 'The name should be unique.'
|
||||
|
||||
|
|
|
@ -39,6 +39,11 @@ validators:
|
|||
not_blank: 'El nombre no debería estar vacío.'
|
||||
unique: 'El nombre debería ser único. Ya existe una imagen con ese nombre.'
|
||||
|
||||
og_live:
|
||||
filename:
|
||||
not_blank: 'El nombre no debería estar vacío.'
|
||||
unique: 'El nombre debería ser único. Ya existe un archivo con ese nombre.'
|
||||
|
||||
network_settings:
|
||||
ip_address:
|
||||
invalid: 'La dirección IP "{{ value }}" no es válida.'
|
||||
|
|
Loading…
Reference in New Issue