refs #659. Trace API. New endpoint execute in command
parent
b4f9f1e9bb
commit
d1105a1e89
|
@ -24,6 +24,13 @@ resources:
|
||||||
ApiPlatform\Metadata\Post: ~
|
ApiPlatform\Metadata\Post: ~
|
||||||
ApiPlatform\Metadata\Delete: ~
|
ApiPlatform\Metadata\Delete: ~
|
||||||
|
|
||||||
|
execute:
|
||||||
|
class: ApiPlatform\Metadata\Post
|
||||||
|
method: POST
|
||||||
|
input: App\Dto\Input\CommandExecuteInput
|
||||||
|
uriTemplate: /commands/{uuid}/execute
|
||||||
|
controller: App\Controller\CommandExecuteAction
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
App\Entity\Command:
|
App\Entity\Command:
|
||||||
id:
|
id:
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
resources:
|
||||||
|
App\Entity\Trace:
|
||||||
|
output: App\Dto\Output\TraceOutput
|
||||||
|
normalizationContext:
|
||||||
|
groups: ['default', 'trace:read']
|
||||||
|
operations:
|
||||||
|
ApiPlatform\Metadata\GetCollection:
|
||||||
|
provider: App\State\Provider\TraceProvider
|
||||||
|
filters:
|
||||||
|
- 'api_platform.filter.trace.order'
|
||||||
|
- 'api_platform.filter.trace.search'
|
||||||
|
ApiPlatform\Metadata\Get:
|
||||||
|
provider: App\State\Provider\TraceProvider
|
||||||
|
|
||||||
|
properties:
|
||||||
|
App\Entity\Trace:
|
||||||
|
id:
|
||||||
|
identifier: false
|
||||||
|
uuid:
|
||||||
|
identifier: true
|
|
@ -116,3 +116,8 @@ services:
|
||||||
bind:
|
bind:
|
||||||
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
|
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
|
||||||
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
|
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
|
||||||
|
|
||||||
|
App\State\Provider\TraceProvider:
|
||||||
|
bind:
|
||||||
|
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
|
||||||
|
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?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 Version20240917091950 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('CREATE TABLE trace (id INT AUTO_INCREMENT NOT NULL, client_id INT NOT NULL, command_id INT NOT NULL, uuid CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', migration_id VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, created_by VARCHAR(255) DEFAULT NULL, updated_by VARCHAR(255) DEFAULT NULL, status VARCHAR(255) NOT NULL, output VARCHAR(255) DEFAULT NULL, executed_at DATETIME NOT NULL, finished_at DATETIME NOT NULL, UNIQUE INDEX UNIQ_315BD5A1D17F50A6 (uuid), INDEX IDX_315BD5A119EB6921 (client_id), INDEX IDX_315BD5A133E1689A (command_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
$this->addSql('ALTER TABLE trace ADD CONSTRAINT FK_315BD5A119EB6921 FOREIGN KEY (client_id) REFERENCES client (id)');
|
||||||
|
$this->addSql('ALTER TABLE trace ADD CONSTRAINT FK_315BD5A133E1689A FOREIGN KEY (command_id) REFERENCES command (id)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE trace DROP FOREIGN KEY FK_315BD5A119EB6921');
|
||||||
|
$this->addSql('ALTER TABLE trace DROP FOREIGN KEY FK_315BD5A133E1689A');
|
||||||
|
$this->addSql('DROP TABLE trace');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 Version20240917092207 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 trace CHANGE finished_at finished_at DATETIME DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE trace CHANGE finished_at finished_at DATETIME NOT NULL');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Dto\Input\CommandExecuteInput;
|
||||||
|
use App\Dto\Input\CommandGroupAddCommandsInput;
|
||||||
|
use App\Entity\Client;
|
||||||
|
use App\Entity\Command;
|
||||||
|
use App\Entity\CommandGroup;
|
||||||
|
use App\Entity\Trace;
|
||||||
|
use App\Model\TraceStatus;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class CommandExecuteAction extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly EntityManagerInterface $entityManager
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(CommandExecuteInput $input, Command $command): JsonResponse
|
||||||
|
{
|
||||||
|
$clients = $input->clients;
|
||||||
|
|
||||||
|
/** @var Client $client */
|
||||||
|
foreach ($clients as $client) {
|
||||||
|
$trace = new Trace();
|
||||||
|
$trace->setClient($client->getEntity());
|
||||||
|
$trace->setCommand($command);
|
||||||
|
$trace->setStatus(TraceStatus::IN_PROGRESS);
|
||||||
|
$trace->setExecutedAt(new \DateTimeImmutable());
|
||||||
|
|
||||||
|
$this->entityManager->persist($trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
return new JsonResponse(data: 'Command executed successfully', status: Response::HTTP_OK);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Dto\Input;
|
||||||
|
|
||||||
|
use App\Dto\Output\ClientOutput;
|
||||||
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
final class CommandExecuteInput
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ClientOutput[]
|
||||||
|
*/
|
||||||
|
#[Assert\NotNull]
|
||||||
|
#[Groups(['command:write'])]
|
||||||
|
public array $clients = [];
|
||||||
|
}
|
|
@ -13,19 +13,19 @@ final class ClientOutput extends AbstractOutput
|
||||||
{
|
{
|
||||||
CONST string TYPE = 'client';
|
CONST string TYPE = 'client';
|
||||||
|
|
||||||
#[Groups(['client:read', 'organizational-unit:read'])]
|
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Groups(['client:read', 'organizational-unit:read'])]
|
#[Groups(['client:read', 'organizational-unit:read'])]
|
||||||
public string $type = self::TYPE;
|
public string $type = self::TYPE;
|
||||||
|
|
||||||
#[Groups(['client:read', 'organizational-unit:read'])]
|
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
|
||||||
public ?string $ip = '';
|
public ?string $ip = '';
|
||||||
|
|
||||||
#[Groups(['client:read', 'organizational-unit:read'])]
|
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
|
||||||
public ?string $mac = '';
|
public ?string $mac = '';
|
||||||
|
|
||||||
#[Groups(['client:read', 'organizational-unit:read'])]
|
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
|
||||||
public ?string $serialNumber = '';
|
public ?string $serialNumber = '';
|
||||||
|
|
||||||
#[Groups(['client:read'])]
|
#[Groups(['client:read'])]
|
||||||
|
|
|
@ -9,10 +9,10 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
#[Get(shortName: 'Command')]
|
#[Get(shortName: 'Command')]
|
||||||
final class CommandOutput extends AbstractOutput
|
final class CommandOutput extends AbstractOutput
|
||||||
{
|
{
|
||||||
#[Groups(['command:read', 'command-group:read', 'command-task:read'])]
|
#[Groups(['command:read', 'command-group:read', 'command-task:read', 'trace:read'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Groups(['command:read', 'command-group:read', 'command-task:read'])]
|
#[Groups(['command:read', 'command-group:read', 'command-task:read', 'trace:read'])]
|
||||||
public ?string $script = '';
|
public ?string $script = '';
|
||||||
|
|
||||||
#[Groups(['command:read'])]
|
#[Groups(['command:read'])]
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Dto\Output;
|
||||||
|
|
||||||
|
use ApiPlatform\Metadata\Get;
|
||||||
|
use App\Entity\Menu;
|
||||||
|
use App\Entity\Trace;
|
||||||
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
|
#[Get(shortName: 'Trace')]
|
||||||
|
final class TraceOutput extends AbstractOutput
|
||||||
|
{
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public CommandOutput $command;
|
||||||
|
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public ClientOutput $client;
|
||||||
|
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public string $status;
|
||||||
|
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public ?\DateTimeInterface $executedAt = null;
|
||||||
|
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public ?string $output = null;
|
||||||
|
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public ?\DateTimeInterface $finishedAt = null;
|
||||||
|
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public \DateTime $createdAt;
|
||||||
|
|
||||||
|
#[Groups(['trace:read'])]
|
||||||
|
public ?string $createdBy = null;
|
||||||
|
|
||||||
|
public function __construct(Trace $trace)
|
||||||
|
{
|
||||||
|
parent::__construct($trace);
|
||||||
|
|
||||||
|
$this->command = new CommandOutput($trace->getCommand());
|
||||||
|
$this->client = new ClientOutput($trace->getClient());
|
||||||
|
$this->status = $trace->getStatus();
|
||||||
|
$this->executedAt = $trace->getExecutedAt();
|
||||||
|
$this->output = $trace->getOutput();
|
||||||
|
$this->finishedAt = $trace->getFinishedAt();
|
||||||
|
$this->createdAt = $trace->getCreatedAt();
|
||||||
|
$this->createdBy = $trace->getCreatedBy();
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,10 +24,10 @@ class Trace extends AbstractEntity
|
||||||
private ?string $output = null;
|
private ?string $output = null;
|
||||||
|
|
||||||
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||||
private ?\DateTimeImmutable $executedAt = null;
|
private ?\DateTimeInterface $executedAt = null;
|
||||||
|
|
||||||
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||||
private ?\DateTimeImmutable $finishedAt = null;
|
private ?\DateTimeInterface $finishedAt = null;
|
||||||
|
|
||||||
public function getClient(): ?Client
|
public function getClient(): ?Client
|
||||||
{
|
{
|
||||||
|
@ -77,24 +77,24 @@ class Trace extends AbstractEntity
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExecutedAt(): ?\DateTimeImmutable
|
public function getExecutedAt(): ?\DateTimeInterface
|
||||||
{
|
{
|
||||||
return $this->executedAt;
|
return $this->executedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setExecutedAt(\DateTimeImmutable $executedAt): static
|
public function setExecutedAt(\DateTimeInterface $executedAt): static
|
||||||
{
|
{
|
||||||
$this->executedAt = $executedAt;
|
$this->executedAt = $executedAt;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFinishedAt(): ?\DateTimeImmutable
|
public function getFinishedAt(): ?\DateTimeInterface
|
||||||
{
|
{
|
||||||
return $this->finishedAt;
|
return $this->finishedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFinishedAt(\DateTimeImmutable $finishedAt): static
|
public function setFinishedAt(\DateTimeInterface $finishedAt): static
|
||||||
{
|
{
|
||||||
$this->finishedAt = $finishedAt;
|
$this->finishedAt = $finishedAt;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Model;
|
||||||
|
|
||||||
|
final class TraceStatus
|
||||||
|
{
|
||||||
|
public const string PENDING = 'pending';
|
||||||
|
public const string IN_PROGRESS = 'in-progress';
|
||||||
|
public const string COMPLETED = 'completed';
|
||||||
|
public const string FAILED = 'failed';
|
||||||
|
|
||||||
|
private const array STATUS = [
|
||||||
|
self::PENDING => 'Pendiente',
|
||||||
|
self::IN_PROGRESS => 'En progreso',
|
||||||
|
self::COMPLETED => 'Completado',
|
||||||
|
self::FAILED => 'Fallido',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function getStatus(): array
|
||||||
|
{
|
||||||
|
return self::STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTraceStatus(string $status): ?string
|
||||||
|
{
|
||||||
|
return self::STATUS[$status] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getStatusKeys(): array
|
||||||
|
{
|
||||||
|
return array_keys(self::STATUS);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\State\Provider;
|
||||||
|
|
||||||
|
use ApiPlatform\Metadata\Get;
|
||||||
|
use ApiPlatform\Metadata\GetCollection;
|
||||||
|
use ApiPlatform\Metadata\Operation;
|
||||||
|
use ApiPlatform\Metadata\Patch;
|
||||||
|
use ApiPlatform\Metadata\Put;
|
||||||
|
use ApiPlatform\State\Pagination\TraversablePaginator;
|
||||||
|
use ApiPlatform\State\ProviderInterface;
|
||||||
|
use App\Dto\Output\TraceOutput;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
readonly class TraceProvider implements ProviderInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private ProviderInterface $collectionProvider,
|
||||||
|
private ProviderInterface $itemProvider
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
|
||||||
|
{
|
||||||
|
switch ($operation){
|
||||||
|
case $operation instanceof GetCollection:
|
||||||
|
return $this->provideCollection($operation, $uriVariables, $context);
|
||||||
|
case $operation instanceof Get:
|
||||||
|
return $this->provideItem($operation, $uriVariables, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
|
||||||
|
{
|
||||||
|
$paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
|
||||||
|
|
||||||
|
$items = new \ArrayObject();
|
||||||
|
foreach ($paginator->getIterator() as $item){
|
||||||
|
$items[] = new TraceOutput($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
|
||||||
|
{
|
||||||
|
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
|
||||||
|
|
||||||
|
if (!$item) {
|
||||||
|
throw new NotFoundHttpException('Trace not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TraceOutput($item);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue